cmds.c revision 98152
1/* 2 * Copyright (c) 1983, 1993 3 * The Regents of the University of California. All rights reserved. 4 * 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 3. All advertising materials mentioning features or use of this software 15 * must display the following acknowledgement: 16 * This product includes software developed by the University of 17 * California, Berkeley and its contributors. 18 * 4. Neither the name of the University nor the names of its contributors 19 * may be used to endorse or promote products derived from this software 20 * without specific prior written permission. 21 * 22 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 25 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 32 * SUCH DAMAGE. 33 */ 34 35#ifndef lint 36static const char copyright[] = 37"@(#) Copyright (c) 1983, 1993\n\ 38 The Regents of the University of California. All rights reserved.\n"; 39#endif /* not lint */ 40 41#ifndef lint 42/* 43static char sccsid[] = "@(#)cmds.c 8.2 (Berkeley) 4/28/95"; 44*/ 45static const char rcsid[] = 46 "$FreeBSD: head/usr.sbin/lpr/lpc/cmds.c 98152 2002-06-13 01:55:48Z gad $"; 47#endif /* not lint */ 48 49/* 50 * lpc -- line printer control program -- commands: 51 */ 52 53#include <sys/param.h> 54#include <sys/time.h> 55#include <sys/stat.h> 56#include <sys/file.h> 57 58#include <signal.h> 59#include <fcntl.h> 60#include <errno.h> 61#include <dirent.h> 62#include <unistd.h> 63#include <stdlib.h> 64#include <stdio.h> 65#include <ctype.h> 66#include <string.h> 67#include "lp.h" 68#include "lp.local.h" 69#include "lpc.h" 70#include "extern.h" 71#include "pathnames.h" 72 73/* 74 * Return values from kill_qtask(). 75 */ 76#define KQT_LFERROR -2 77#define KQT_KILLFAIL -1 78#define KQT_NODAEMON 0 79#define KQT_KILLOK 1 80 81static void abortpr(struct printer *_pp, int _dis); 82static int doarg(char *_job); 83static int doselect(struct dirent *_d); 84static int kill_qtask(const char *lf); 85static void putmsg(struct printer *_pp, int _argc, char **_argv); 86static int sortq(const void *_a, const void *_b); 87static void startpr(struct printer *_pp, int _chgenable); 88static int touch(struct jobqueue *_jq); 89static void unlinkf(char *_name); 90static void upstat(struct printer *_pp, const char *_msg); 91static void wrapup_clean(int _laststatus); 92 93/* 94 * generic framework for commands which operate on all or a specified 95 * set of printers 96 */ 97enum qsel_val { /* how a given ptr was selected */ 98 QSEL_UNKNOWN = -1, /* ... not selected yet */ 99 QSEL_BYNAME = 0, /* ... user specifed it by name */ 100 QSEL_ALL = 1 /* ... user wants "all" printers */ 101 /* (with more to come) */ 102}; 103 104static enum qsel_val generic_qselect; /* indicates how ptr was selected */ 105static int generic_initerr; /* result of initrtn processing */ 106static char *generic_nullarg; 107static void (*generic_wrapup)(int _last_status); /* perform rtn wrap-up */ 108 109void 110generic(void (*specificrtn)(struct printer *_pp), 111 void (*initrtn)(int _argc, char *_argv[]), int argc, char *argv[]) 112{ 113 int cmdstatus, more, targc; 114 struct printer myprinter, *pp; 115 char **targv; 116 117 if (argc == 1) { 118 printf("usage: %s {all | printer ...}\n", argv[0]); 119 return; 120 } 121 122 /* 123 * The initialization routine for a command might set a generic 124 * "wrapup" routine, which should be called after processing all 125 * the printers in the command. This might print summary info. 126 * 127 * Note that the initialization routine may also parse (and 128 * nullify) some of the parameters given on the command, leaving 129 * only the parameters which have to do with printer names. 130 */ 131 pp = &myprinter; 132 generic_wrapup = NULL; 133 generic_qselect = QSEL_UNKNOWN; 134 cmdstatus = 0; 135 /* this just needs to be a distinct value of type 'char *' */ 136 if (generic_nullarg == NULL) 137 generic_nullarg = strdup(""); 138 139 /* call initialization routine, if there is one for this cmd */ 140 if (initrtn != NULL) { 141 generic_initerr = 0; 142 (*initrtn)(argc, argv); 143 if (generic_initerr) 144 return; 145 /* skip any initial arguments null-ified by initrtn */ 146 targc = argc; 147 targv = argv; 148 while (--targc) { 149 if (targv[1] != generic_nullarg) 150 break; 151 ++targv; 152 } 153 if (targv != argv) { 154 targv[0] = argv[0]; /* copy the command-name */ 155 argv = targv; 156 argc = targc + 1; 157 } 158 } 159 160 if (argc == 2 && strcmp(argv[1], "all") == 0) { 161 generic_qselect = QSEL_ALL; 162 more = firstprinter(pp, &cmdstatus); 163 if (cmdstatus) 164 goto looperr; 165 while (more) { 166 (*specificrtn)(pp); 167 do { 168 more = nextprinter(pp, &cmdstatus); 169looperr: 170 switch (cmdstatus) { 171 case PCAPERR_TCOPEN: 172 printf("warning: %s: unresolved " 173 "tc= reference(s) ", 174 pp->printer); 175 case PCAPERR_SUCCESS: 176 break; 177 default: 178 fatal(pp, "%s", pcaperr(cmdstatus)); 179 } 180 } while (more && cmdstatus); 181 } 182 goto wrapup; 183 } 184 185 generic_qselect = QSEL_BYNAME; /* specifically-named ptrs */ 186 while (--argc) { 187 ++argv; 188 if (*argv == generic_nullarg) 189 continue; 190 init_printer(pp); 191 cmdstatus = getprintcap(*argv, pp); 192 switch (cmdstatus) { 193 default: 194 fatal(pp, "%s", pcaperr(cmdstatus)); 195 case PCAPERR_NOTFOUND: 196 printf("unknown printer %s\n", *argv); 197 continue; 198 case PCAPERR_TCOPEN: 199 printf("warning: %s: unresolved tc= reference(s)\n", 200 *argv); 201 break; 202 case PCAPERR_SUCCESS: 203 break; 204 } 205 (*specificrtn)(pp); 206 } 207 208wrapup: 209 if (generic_wrapup) { 210 (*generic_wrapup)(cmdstatus); 211 } 212 213} 214 215/* 216 * kill an existing daemon and disable printing. 217 */ 218void 219doabort(struct printer *pp) 220{ 221 abortpr(pp, 1); 222} 223 224static void 225abortpr(struct printer *pp, int dis) 226{ 227 register FILE *fp; 228 struct stat stbuf; 229 int pid, fd; 230 char lf[MAXPATHLEN]; 231 232 lock_file_name(pp, lf, sizeof lf); 233 printf("%s:\n", pp->printer); 234 235 /* 236 * Turn on the owner execute bit of the lock file to disable printing. 237 */ 238 if (dis) { 239 seteuid(euid); 240 if (stat(lf, &stbuf) >= 0) { 241 if (chmod(lf, stbuf.st_mode | LFM_PRINT_DIS) < 0) 242 printf("\tcannot disable printing: %s\n", 243 strerror(errno)); 244 else { 245 upstat(pp, "printing disabled\n"); 246 printf("\tprinting disabled\n"); 247 } 248 } else if (errno == ENOENT) { 249 if ((fd = open(lf, O_WRONLY|O_CREAT, 250 LOCK_FILE_MODE | LFM_PRINT_DIS)) < 0) 251 printf("\tcannot create lock file: %s\n", 252 strerror(errno)); 253 else { 254 (void) close(fd); 255 upstat(pp, "printing disabled\n"); 256 printf("\tprinting disabled\n"); 257 printf("\tno daemon to abort\n"); 258 } 259 goto out; 260 } else { 261 printf("\tcannot stat lock file\n"); 262 goto out; 263 } 264 } 265 /* 266 * Kill the current daemon to stop printing now. 267 */ 268 if ((fp = fopen(lf, "r")) == NULL) { 269 printf("\tcannot open lock file\n"); 270 goto out; 271 } 272 if (!getline(fp) || flock(fileno(fp), LOCK_SH|LOCK_NB) == 0) { 273 (void) fclose(fp); /* unlocks as well */ 274 printf("\tno daemon to abort\n"); 275 goto out; 276 } 277 (void) fclose(fp); 278 if (kill(pid = atoi(line), SIGTERM) < 0) { 279 if (errno == ESRCH) 280 printf("\tno daemon to abort\n"); 281 else 282 printf("\tWarning: daemon (pid %d) not killed\n", pid); 283 } else 284 printf("\tdaemon (pid %d) killed\n", pid); 285out: 286 seteuid(uid); 287} 288 289/* 290 * Kill the current daemon, to stop printing of the active job. 291 */ 292static int 293kill_qtask(const char *lf) 294{ 295 FILE *fp; 296 pid_t pid; 297 int errsav, killres, lockres, res; 298 299 seteuid(euid); 300 fp = fopen(lf, "r"); 301 errsav = errno; 302 seteuid(uid); 303 res = KQT_NODAEMON; 304 if (fp == NULL) { 305 /* 306 * If there is no lock file, then there is no daemon to 307 * kill. Any other error return means there is some 308 * kind of problem with the lock file. 309 */ 310 if (errsav != ENOENT) 311 res = KQT_LFERROR; 312 goto killdone; 313 } 314 315 /* If the lock file is empty, then there is no daemon to kill */ 316 if (getline(fp) == 0) 317 goto killdone; 318 319 /* 320 * If the file can be locked without blocking, then there 321 * no daemon to kill, or we should not try to kill it. 322 * 323 * XXX - not sure I understand the reasoning behind this... 324 */ 325 lockres = flock(fileno(fp), LOCK_SH|LOCK_NB); 326 (void) fclose(fp); 327 if (lockres == 0) 328 goto killdone; 329 330 pid = atoi(line); 331 if (pid < 0) { 332 /* 333 * If we got a negative pid, then the contents of the 334 * lock file is not valid. 335 */ 336 res = KQT_LFERROR; 337 goto killdone; 338 } 339 340 seteuid(uid); 341 killres = kill(pid, SIGTERM); 342 errsav = errno; 343 seteuid(uid); 344 if (killres == 0) { 345 res = KQT_KILLOK; 346 printf("\tdaemon (pid %d) killed\n", pid); 347 } else if (errno == ESRCH) { 348 res = KQT_NODAEMON; 349 } else { 350 res = KQT_KILLFAIL; 351 printf("\tWarning: daemon (pid %d) not killed:\n", pid); 352 printf("\t %s\n", strerror(errsav)); 353 } 354 355killdone: 356 switch (res) { 357 case KQT_LFERROR: 358 printf("\tcannot open lock file: %s\n", 359 strerror(errsav)); 360 break; 361 case KQT_NODAEMON: 362 printf("\tno daemon to abort\n"); 363 break; 364 case KQT_KILLFAIL: 365 case KQT_KILLOK: 366 /* These two already printed messages to the user. */ 367 break; 368 default: 369 printf("\t<internal error in kill_qtask>\n"); 370 break; 371 } 372 373 return (res); 374} 375 376/* 377 * Write a message into the status file. 378 */ 379static void 380upstat(struct printer *pp, const char *msg) 381{ 382 register int fd; 383 char statfile[MAXPATHLEN]; 384 385 status_file_name(pp, statfile, sizeof statfile); 386 umask(0); 387 fd = open(statfile, O_WRONLY|O_CREAT|O_EXLOCK, STAT_FILE_MODE); 388 if (fd < 0) { 389 printf("\tcannot create status file: %s\n", strerror(errno)); 390 return; 391 } 392 (void) ftruncate(fd, 0); 393 if (msg == (char *)NULL) 394 (void) write(fd, "\n", 1); 395 else 396 (void) write(fd, msg, strlen(msg)); 397 (void) close(fd); 398} 399 400/* 401 * kill an existing daemon and disable printing. 402 */ 403void 404abort_q(struct printer *pp) 405{ 406 int killres, setres; 407 char lf[MAXPATHLEN]; 408 409 lock_file_name(pp, lf, sizeof lf); 410 printf("%s:\n", pp->printer); 411 412 /* 413 * Turn on the owner execute bit of the lock file to disable printing. 414 */ 415 setres = set_qstate(SQS_STOPP, lf); 416 417 /* 418 * If set_qstate found that there already was a lock file, then 419 * call a routine which will read that lock file and kill the 420 * lpd-process which is listed in that lock file. If the lock 421 * file did not exist, then either there is no daemon running 422 * for this queue, or there is one running but *it* could not 423 * write a lock file (which means we can not determine the 424 * process id of that lpd-process). 425 */ 426 switch (setres) { 427 case SQS_CHGOK: 428 case SQS_CHGFAIL: 429 /* Kill the process */ 430 killres = kill_qtask(lf); 431 break; 432 case SQS_CREOK: 433 case SQS_CREFAIL: 434 printf("\tno daemon to abort\n"); 435 break; 436 case SQS_STATFAIL: 437 printf("\tassuming no daemon to abort\n"); 438 break; 439 default: 440 printf("\t<unexpected result (%d) from set_qstate>\n", 441 setres); 442 break; 443 } 444 445 if (setres >= 0) { 446 seteuid(euid); 447 upstat(pp, "printing disabled\n"); 448 seteuid(uid); 449 } 450} 451 452/* 453 * "global" variables for all the routines related to 'clean' and 'tclean' 454 */ 455static time_t cln_now; /* current time */ 456static double cln_minage; /* minimum age before file is removed */ 457static long cln_sizecnt; /* amount of space freed up */ 458static int cln_debug; /* print extra debugging msgs */ 459static int cln_filecnt; /* number of files destroyed */ 460static int cln_foundcore; /* found a core file! */ 461static int cln_queuecnt; /* number of queues checked */ 462static int cln_testonly; /* remove-files vs just-print-info */ 463 464static int 465doselect(struct dirent *d) 466{ 467 int c = d->d_name[0]; 468 469 if ((c == 'c' || c == 'd' || c == 'r' || c == 't') && 470 d->d_name[1] == 'f') 471 return 1; 472 if (c == 'c') { 473 if (!strcmp(d->d_name, "core")) 474 cln_foundcore = 1; 475 } 476 if (c == 'e') { 477 if (!strncmp(d->d_name, "errs.", 5)) 478 return 1; 479 } 480 return 0; 481} 482 483/* 484 * Comparison routine that clean_q() uses for scandir. 485 * 486 * The purpose of this sort is to have all `df' files end up immediately 487 * after the matching `cf' file. For files matching `cf', `df', `rf', or 488 * `tf', it sorts by job number and machine, then by `cf', `df', `rf', or 489 * `tf', and then by the sequence letter (which is A-Z, or a-z). This 490 * routine may also see filenames which do not start with `cf', `df', `rf', 491 * or `tf' (such as `errs.*'), and those are simply sorted by the full 492 * filename. 493 * 494 * XXX 495 * This assumes that all control files start with `cfA*', and it turns 496 * out there are a few implementations of lpr which will create `cfB*' 497 * filenames (they will have datafile names which start with `dfB*'). 498 */ 499static int 500sortq(const void *a, const void *b) 501{ 502 const int a_lt_b = -1, a_gt_b = 1, cat_other = 10; 503 const char *fname_a, *fname_b, *jnum_a, *jnum_b; 504 int cat_a, cat_b, ch, res, seq_a, seq_b; 505 506 fname_a = (*(const struct dirent * const *)a)->d_name; 507 fname_b = (*(const struct dirent * const *)b)->d_name; 508 509 /* 510 * First separate filenames into cagatories. Catagories are 511 * legitimate `cf', `df', `rf' & `tf' filenames, and "other" - in 512 * that order. It is critical that the mapping be exactly the 513 * same for 'a' vs 'b', so define a macro for the job. 514 * 515 * [aside: the standard `cf' file has the jobnumber start in 516 * position 4, but some implementations have that as an extra 517 * file-sequence letter, and start the job number in position 5.] 518 */ 519#define MAP_TO_CAT(fname_X,cat_X,jnum_X,seq_X) do { \ 520 cat_X = cat_other; \ 521 ch = *(fname_X + 2); \ 522 jnum_X = fname_X + 3; \ 523 seq_X = 0; \ 524 if ((*(fname_X + 1) == 'f') && (isalpha(ch))) { \ 525 seq_X = ch; \ 526 if (*fname_X == 'c') \ 527 cat_X = 1; \ 528 else if (*fname_X == 'd') \ 529 cat_X = 2; \ 530 else if (*fname_X == 'r') \ 531 cat_X = 3; \ 532 else if (*fname_X == 't') \ 533 cat_X = 4; \ 534 if (cat_X != cat_other) { \ 535 ch = *jnum_X; \ 536 if (!isdigit(ch)) { \ 537 if (isalpha(ch)) { \ 538 jnum_X++; \ 539 ch = *jnum_X; \ 540 seq_X = (seq_X << 8) + ch; \ 541 } \ 542 if (!isdigit(ch)) \ 543 cat_X = cat_other; \ 544 } \ 545 } \ 546 } \ 547} while (0) 548 549 MAP_TO_CAT(fname_a, cat_a, jnum_a, seq_a); 550 MAP_TO_CAT(fname_b, cat_b, jnum_b, seq_b); 551 552#undef MAP_TO_CAT 553 554 /* First handle all cases which have "other" files */ 555 if ((cat_a >= cat_other) || (cat_b >= cat_other)) { 556 /* for two "other" files, just compare the full name */ 557 if (cat_a == cat_b) 558 res = strcmp(fname_a, fname_b); 559 else if (cat_a < cat_b) 560 res = a_lt_b; 561 else 562 res = a_gt_b; 563 goto have_res; 564 } 565 566 /* 567 * At this point, we know both files are legitimate `cf', `df', `rf', 568 * or `tf' files. Compare them by job-number and machine name. 569 */ 570 res = strcmp(jnum_a, jnum_b); 571 if (res != 0) 572 goto have_res; 573 574 /* 575 * We have two files which belong to the same job. Sort based 576 * on the catagory of file (`c' before `d', etc). 577 */ 578 if (cat_a < cat_b) { 579 res = a_lt_b; 580 goto have_res; 581 } else if (cat_a > cat_b) { 582 res = a_gt_b; 583 goto have_res; 584 } 585 586 /* 587 * Two files in the same catagory for a single job. Sort based 588 * on the sequence letter(s). (usually `A' thru `Z', etc). 589 */ 590 if (seq_a < seq_b) { 591 res = a_lt_b; 592 goto have_res; 593 } else if (seq_a > seq_b) { 594 res = a_gt_b; 595 goto have_res; 596 } 597 598 /* 599 * Given that the filenames in a directory are unique, this SHOULD 600 * never happen (unless there are logic errors in this routine). 601 * But if it does happen, we must return "is equal" or the caller 602 * might see inconsistent results in the sorting order, and that 603 * can trigger other problems. 604 */ 605 printf("\t*** Error in sortq: %s == %s !\n", fname_a, fname_b); 606 printf("\t*** cat %d == %d ; seq = %d %d\n", cat_a, cat_b, 607 seq_a, seq_b); 608 res = 0; 609 610have_res: 611 return res; 612} 613 614/* 615 * Remove all spool files and temporaries from the spooling area. 616 * Or, perhaps: 617 * Remove incomplete jobs from spooling area. 618 */ 619 620void 621init_clean(int argc, char *argv[]) 622{ 623 624 /* init some fields before 'clean' is called for each queue */ 625 cln_queuecnt = 0; 626 cln_now = time(NULL); 627 cln_minage = 3600.0; /* only delete files >1h old */ 628 cln_filecnt = 0; 629 cln_sizecnt = 0; 630 cln_debug = 0; 631 cln_testonly = 0; 632 generic_wrapup = &wrapup_clean; 633 634 /* see if there are any options specified before the ptr list */ 635 while (--argc) { 636 ++argv; 637 if (**argv != '-') 638 break; 639 if (strcmp(*argv, "-d") == 0) { 640 /* just an example of an option... */ 641 cln_debug++; 642 *argv = generic_nullarg; /* "erase" it */ 643 } else { 644 printf("Invalid option '%s'\n", *argv); 645 generic_initerr = 1; 646 } 647 } 648 649 return; 650} 651 652void 653init_tclean(int argc, char *argv[]) 654{ 655 656 /* only difference between 'clean' and 'tclean' is one value */ 657 /* (...and the fact that 'clean' is priv and 'tclean' is not) */ 658 init_clean(argc, argv); 659 cln_testonly = 1; 660 661 return; 662} 663 664void 665clean_q(struct printer *pp) 666{ 667 char *cp, *cp1, *lp; 668 struct dirent **queue; 669 size_t linerem; 670 int didhead, i, n, nitems, rmcp; 671 672 cln_queuecnt++; 673 674 didhead = 0; 675 if (generic_qselect == QSEL_BYNAME) { 676 printf("%s:\n", pp->printer); 677 didhead = 1; 678 } 679 680 lp = line; 681 cp = pp->spool_dir; 682 while (lp < &line[sizeof(line) - 1]) { 683 if ((*lp++ = *cp++) == 0) 684 break; 685 } 686 lp[-1] = '/'; 687 linerem = sizeof(line) - (lp - line); 688 689 cln_foundcore = 0; 690 seteuid(euid); 691 nitems = scandir(pp->spool_dir, &queue, doselect, sortq); 692 seteuid(uid); 693 if (nitems < 0) { 694 if (!didhead) { 695 printf("%s:\n", pp->printer); 696 didhead = 1; 697 } 698 printf("\tcannot examine spool directory\n"); 699 return; 700 } 701 if (cln_foundcore) { 702 if (!didhead) { 703 printf("%s:\n", pp->printer); 704 didhead = 1; 705 } 706 printf("\t** found a core file in %s !\n", pp->spool_dir); 707 } 708 if (nitems == 0) 709 return; 710 if (!didhead) 711 printf("%s:\n", pp->printer); 712 if (cln_debug) { 713 printf("\t** ----- Sorted list of files being checked:\n"); 714 i = 0; 715 do { 716 cp = queue[i]->d_name; 717 printf("\t** [%3d] = %s\n", i, cp); 718 } while (++i < nitems); 719 printf("\t** ----- end of sorted list\n"); 720 } 721 i = 0; 722 do { 723 cp = queue[i]->d_name; 724 rmcp = 0; 725 if (*cp == 'c') { 726 /* 727 * A control file. Look for matching data-files. 728 */ 729 /* XXX 730 * Note the logic here assumes that the hostname 731 * part of cf-filenames match the hostname part 732 * in df-filenames, and that is not necessarily 733 * true (eg: for multi-homed hosts). This needs 734 * some further thought... 735 */ 736 n = 0; 737 while (i + 1 < nitems) { 738 cp1 = queue[i + 1]->d_name; 739 if (*cp1 != 'd' || strcmp(cp + 3, cp1 + 3)) 740 break; 741 i++; 742 n++; 743 } 744 if (n == 0) { 745 rmcp = 1; 746 } 747 } else if (*cp == 'e') { 748 /* 749 * Must be an errrs or email temp file. 750 */ 751 rmcp = 1; 752 } else { 753 /* 754 * Must be a df with no cf (otherwise, it would have 755 * been skipped above) or an rf or tf file (which can 756 * always be removed if it is old enough). 757 */ 758 rmcp = 1; 759 } 760 if (rmcp) { 761 if (strlen(cp) >= linerem) { 762 printf("\t** internal error: 'line' overflow!\n"); 763 printf("\t** spooldir = %s\n", pp->spool_dir); 764 printf("\t** cp = %s\n", cp); 765 return; 766 } 767 strlcpy(lp, cp, linerem); 768 unlinkf(line); 769 } 770 } while (++i < nitems); 771} 772 773static void 774wrapup_clean(int laststatus __unused) 775{ 776 777 printf("Checked %d queues, and ", cln_queuecnt); 778 if (cln_filecnt < 1) { 779 printf("no cruft was found\n"); 780 return; 781 } 782 if (cln_testonly) { 783 printf("would have "); 784 } 785 printf("removed %d files (%ld bytes).\n", cln_filecnt, cln_sizecnt); 786} 787 788static void 789unlinkf(char *name) 790{ 791 struct stat stbuf; 792 double agemod, agestat; 793 int res; 794 char linkbuf[BUFSIZ]; 795 796 /* 797 * We have to use lstat() instead of stat(), in case this is a df* 798 * "file" which is really a symlink due to 'lpr -s' processing. In 799 * that case, we need to check the last-mod time of the symlink, and 800 * not the file that the symlink is pointed at. 801 */ 802 seteuid(euid); 803 res = lstat(name, &stbuf); 804 seteuid(uid); 805 if (res < 0) { 806 printf("\terror return from stat(%s):\n", name); 807 printf("\t %s\n", strerror(errno)); 808 return; 809 } 810 811 agemod = difftime(cln_now, stbuf.st_mtime); 812 agestat = difftime(cln_now, stbuf.st_ctime); 813 if (cln_debug > 1) { 814 /* this debugging-aid probably is not needed any more... */ 815 printf("\t\t modify age=%g secs, stat age=%g secs\n", 816 agemod, agestat); 817 } 818 if ((agemod <= cln_minage) && (agestat <= cln_minage)) 819 return; 820 821 /* 822 * if this file is a symlink, then find out the target of the 823 * symlink before unlink-ing the file itself 824 */ 825 if (S_ISLNK(stbuf.st_mode)) { 826 seteuid(euid); 827 res = readlink(name, linkbuf, sizeof(linkbuf)); 828 seteuid(uid); 829 if (res < 0) { 830 printf("\terror return from readlink(%s):\n", name); 831 printf("\t %s\n", strerror(errno)); 832 return; 833 } 834 if (res == sizeof(linkbuf)) 835 res--; 836 linkbuf[res] = '\0'; 837 } 838 839 cln_filecnt++; 840 cln_sizecnt += stbuf.st_size; 841 842 if (cln_testonly) { 843 printf("\twould remove %s\n", name); 844 if (S_ISLNK(stbuf.st_mode)) { 845 printf("\t (which is a symlink to %s)\n", linkbuf); 846 } 847 } else { 848 seteuid(euid); 849 res = unlink(name); 850 seteuid(uid); 851 if (res < 0) 852 printf("\tcannot remove %s (!)\n", name); 853 else 854 printf("\tremoved %s\n", name); 855 /* XXX 856 * Note that for a df* file, this code should also check to see 857 * if it is a symlink to some other file, and if the original 858 * lpr command included '-r' ("remove file"). Of course, this 859 * code would not be removing the df* file unless there was no 860 * matching cf* file, and without the cf* file it is currently 861 * impossible to determine if '-r' had been specified... 862 * 863 * As a result of this quandry, we may be leaving behind a 864 * user's file that was supposed to have been removed after 865 * being printed. This may effect services such as CAP or 866 * samba, if they were configured to use 'lpr -r', and if 867 * datafiles are not being properly removed. 868 */ 869 if (S_ISLNK(stbuf.st_mode)) { 870 printf("\t (which was a symlink to %s)\n", linkbuf); 871 } 872 } 873} 874 875/* 876 * Enable queuing to the printer (allow lpr's). 877 */ 878void 879enable(struct printer *pp) 880{ 881 struct stat stbuf; 882 char lf[MAXPATHLEN]; 883 884 lock_file_name(pp, lf, sizeof lf); 885 printf("%s:\n", pp->printer); 886 887 /* 888 * Turn off the group execute bit of the lock file to enable queuing. 889 */ 890 seteuid(euid); 891 if (stat(lf, &stbuf) >= 0) { 892 if (chmod(lf, stbuf.st_mode & ~LFM_QUEUE_DIS) < 0) 893 printf("\tcannot enable queuing\n"); 894 else 895 printf("\tqueuing enabled\n"); 896 } 897 seteuid(uid); 898} 899 900/* 901 * Enable queuing to the printer (allow lpr to add new jobs to the queue). 902 */ 903void 904enable_q(struct printer *pp) 905{ 906 int setres; 907 char lf[MAXPATHLEN]; 908 909 lock_file_name(pp, lf, sizeof lf); 910 printf("%s:\n", pp->printer); 911 912 setres = set_qstate(SQS_ENABLEQ, lf); 913} 914 915/* 916 * Disable queuing. 917 */ 918void 919disable(struct printer *pp) 920{ 921 register int fd; 922 struct stat stbuf; 923 char lf[MAXPATHLEN]; 924 925 lock_file_name(pp, lf, sizeof lf); 926 printf("%s:\n", pp->printer); 927 /* 928 * Turn on the group execute bit of the lock file to disable queuing. 929 */ 930 seteuid(euid); 931 if (stat(lf, &stbuf) >= 0) { 932 if (chmod(lf, stbuf.st_mode | LFM_QUEUE_DIS) < 0) 933 printf("\tcannot disable queuing: %s\n", 934 strerror(errno)); 935 else 936 printf("\tqueuing disabled\n"); 937 } else if (errno == ENOENT) { 938 if ((fd = open(lf, O_WRONLY|O_CREAT, 939 LOCK_FILE_MODE | LFM_QUEUE_DIS)) < 0) 940 printf("\tcannot create lock file: %s\n", 941 strerror(errno)); 942 else { 943 (void) close(fd); 944 printf("\tqueuing disabled\n"); 945 } 946 } else 947 printf("\tcannot stat lock file\n"); 948 seteuid(uid); 949} 950 951/* 952 * Disable queuing. 953 */ 954void 955disable_q(struct printer *pp) 956{ 957 int setres; 958 char lf[MAXPATHLEN]; 959 960 lock_file_name(pp, lf, sizeof lf); 961 printf("%s:\n", pp->printer); 962 963 setres = set_qstate(SQS_DISABLEQ, lf); 964} 965 966/* 967 * Disable queuing and printing and put a message into the status file 968 * (reason for being down). 969 */ 970void 971down(int argc, char *argv[]) 972{ 973 int cmdstatus, more; 974 struct printer myprinter, *pp = &myprinter; 975 976 if (argc == 1) { 977 printf("usage: down {all | printer} [message ...]\n"); 978 return; 979 } 980 if (!strcmp(argv[1], "all")) { 981 more = firstprinter(pp, &cmdstatus); 982 if (cmdstatus) 983 goto looperr; 984 while (more) { 985 putmsg(pp, argc - 2, argv + 2); 986 do { 987 more = nextprinter(pp, &cmdstatus); 988looperr: 989 switch (cmdstatus) { 990 case PCAPERR_TCOPEN: 991 printf("warning: %s: unresolved " 992 "tc= reference(s) ", 993 pp->printer); 994 case PCAPERR_SUCCESS: 995 break; 996 default: 997 fatal(pp, "%s", pcaperr(cmdstatus)); 998 } 999 } while (more && cmdstatus); 1000 } 1001 return; 1002 } 1003 init_printer(pp); 1004 cmdstatus = getprintcap(argv[1], pp); 1005 switch (cmdstatus) { 1006 default: 1007 fatal(pp, "%s", pcaperr(cmdstatus)); 1008 case PCAPERR_NOTFOUND: 1009 printf("unknown printer %s\n", argv[1]); 1010 return; 1011 case PCAPERR_TCOPEN: 1012 printf("warning: %s: unresolved tc= reference(s)", argv[1]); 1013 break; 1014 case PCAPERR_SUCCESS: 1015 break; 1016 } 1017 putmsg(pp, argc - 2, argv + 2); 1018} 1019 1020static void 1021putmsg(struct printer *pp, int argc, char **argv) 1022{ 1023 register int fd; 1024 register char *cp1, *cp2; 1025 char buf[1024]; 1026 char file[MAXPATHLEN]; 1027 struct stat stbuf; 1028 1029 printf("%s:\n", pp->printer); 1030 /* 1031 * Turn on the group execute bit of the lock file to disable queuing; 1032 * turn on the owner execute bit of the lock file to disable printing. 1033 */ 1034 lock_file_name(pp, file, sizeof file); 1035 seteuid(euid); 1036 if (stat(file, &stbuf) >= 0) { 1037 if (chmod(file, stbuf.st_mode|LFM_PRINT_DIS|LFM_QUEUE_DIS) < 0) 1038 printf("\tcannot disable queuing: %s\n", 1039 strerror(errno)); 1040 else 1041 printf("\tprinter and queuing disabled\n"); 1042 } else if (errno == ENOENT) { 1043 if ((fd = open(file, O_WRONLY|O_CREAT, 1044 LOCK_FILE_MODE|LFM_PRINT_DIS|LFM_QUEUE_DIS)) < 0) 1045 printf("\tcannot create lock file: %s\n", 1046 strerror(errno)); 1047 else { 1048 (void) close(fd); 1049 printf("\tprinter and queuing disabled\n"); 1050 } 1051 seteuid(uid); 1052 return; 1053 } else 1054 printf("\tcannot stat lock file\n"); 1055 /* 1056 * Write the message into the status file. 1057 */ 1058 status_file_name(pp, file, sizeof file); 1059 fd = open(file, O_WRONLY|O_CREAT|O_EXLOCK, STAT_FILE_MODE); 1060 if (fd < 0) { 1061 printf("\tcannot create status file: %s\n", strerror(errno)); 1062 seteuid(uid); 1063 return; 1064 } 1065 seteuid(uid); 1066 (void) ftruncate(fd, 0); 1067 if (argc <= 0) { 1068 (void) write(fd, "\n", 1); 1069 (void) close(fd); 1070 return; 1071 } 1072 cp1 = buf; 1073 while (--argc >= 0) { 1074 cp2 = *argv++; 1075 while ((size_t)(cp1 - buf) < sizeof(buf) && (*cp1++ = *cp2++)) 1076 ; 1077 cp1[-1] = ' '; 1078 } 1079 cp1[-1] = '\n'; 1080 *cp1 = '\0'; 1081 (void) write(fd, buf, strlen(buf)); 1082 (void) close(fd); 1083} 1084 1085/* 1086 * Exit lpc 1087 */ 1088void 1089quit(int argc __unused, char *argv[] __unused) 1090{ 1091 exit(0); 1092} 1093 1094/* 1095 * Kill and restart the daemon. 1096 */ 1097void 1098restart(struct printer *pp) 1099{ 1100 abortpr(pp, 0); 1101 startpr(pp, 0); 1102} 1103 1104/* 1105 * Kill and restart the daemon. 1106 */ 1107void 1108restart_q(struct printer *pp) 1109{ 1110 int killres, setres, startok; 1111 char lf[MAXPATHLEN]; 1112 1113 lock_file_name(pp, lf, sizeof lf); 1114 printf("%s:\n", pp->printer); 1115 1116 killres = kill_qtask(lf); 1117 1118 /* 1119 * XXX - if the kill worked, we should probably sleep for 1120 * a second or so before trying to restart the queue. 1121 */ 1122 1123 /* make sure the queue is set to print jobs */ 1124 setres = set_qstate(SQS_STARTP, lf); 1125 1126 seteuid(euid); 1127 startok = startdaemon(pp); 1128 seteuid(uid); 1129 if (!startok) 1130 printf("\tcouldn't restart daemon\n"); 1131 else 1132 printf("\tdaemon restarted\n"); 1133} 1134 1135/* 1136 * Enable printing on the specified printer and startup the daemon. 1137 */ 1138void 1139startcmd(struct printer *pp) 1140{ 1141 startpr(pp, 1); 1142} 1143 1144static void 1145startpr(struct printer *pp, int chgenable) 1146{ 1147 struct stat stbuf; 1148 char lf[MAXPATHLEN]; 1149 1150 lock_file_name(pp, lf, sizeof lf); 1151 printf("%s:\n", pp->printer); 1152 1153 /* 1154 * For chgenable==1 ('start'), turn off the LFM_PRINT_DIS bit of the 1155 * lock file to re-enable printing. For chgenable==2 ('up'), also 1156 * turn off the LFM_QUEUE_DIS bit to re-enable queueing. 1157 */ 1158 seteuid(euid); 1159 if (chgenable && stat(lf, &stbuf) >= 0) { 1160 mode_t bits = (chgenable == 2 ? 0 : LFM_QUEUE_DIS); 1161 if (chmod(lf, stbuf.st_mode & (LOCK_FILE_MODE | bits)) < 0) 1162 printf("\tcannot enable printing\n"); 1163 else 1164 printf("\tprinting enabled\n"); 1165 } 1166 if (!startdaemon(pp)) 1167 printf("\tcouldn't start daemon\n"); 1168 else 1169 printf("\tdaemon started\n"); 1170 seteuid(uid); 1171} 1172 1173/* 1174 * Enable printing on the specified printer and startup the daemon. 1175 */ 1176void 1177start_q(struct printer *pp) 1178{ 1179 int setres, startok; 1180 char lf[MAXPATHLEN]; 1181 1182 lock_file_name(pp, lf, sizeof lf); 1183 printf("%s:\n", pp->printer); 1184 1185 setres = set_qstate(SQS_STARTP, lf); 1186 1187 seteuid(euid); 1188 startok = startdaemon(pp); 1189 seteuid(uid); 1190 if (!startok) 1191 printf("\tcouldn't start daemon\n"); 1192 else 1193 printf("\tdaemon started\n"); 1194 seteuid(uid); 1195} 1196 1197/* 1198 * Print the status of the printer queue. 1199 */ 1200void 1201status(struct printer *pp) 1202{ 1203 struct stat stbuf; 1204 register int fd, i; 1205 register struct dirent *dp; 1206 DIR *dirp; 1207 char file[MAXPATHLEN]; 1208 1209 printf("%s:\n", pp->printer); 1210 lock_file_name(pp, file, sizeof file); 1211 if (stat(file, &stbuf) >= 0) { 1212 printf("\tqueuing is %s\n", 1213 ((stbuf.st_mode & LFM_QUEUE_DIS) ? "disabled" 1214 : "enabled")); 1215 printf("\tprinting is %s\n", 1216 ((stbuf.st_mode & LFM_PRINT_DIS) ? "disabled" 1217 : "enabled")); 1218 } else { 1219 printf("\tqueuing is enabled\n"); 1220 printf("\tprinting is enabled\n"); 1221 } 1222 if ((dirp = opendir(pp->spool_dir)) == NULL) { 1223 printf("\tcannot examine spool directory\n"); 1224 return; 1225 } 1226 i = 0; 1227 while ((dp = readdir(dirp)) != NULL) { 1228 if (*dp->d_name == 'c' && dp->d_name[1] == 'f') 1229 i++; 1230 } 1231 closedir(dirp); 1232 if (i == 0) 1233 printf("\tno entries in spool area\n"); 1234 else if (i == 1) 1235 printf("\t1 entry in spool area\n"); 1236 else 1237 printf("\t%d entries in spool area\n", i); 1238 fd = open(file, O_RDONLY); 1239 if (fd < 0 || flock(fd, LOCK_SH|LOCK_NB) == 0) { 1240 (void) close(fd); /* unlocks as well */ 1241 printf("\tprinter idle\n"); 1242 return; 1243 } 1244 (void) close(fd); 1245 /* print out the contents of the status file, if it exists */ 1246 status_file_name(pp, file, sizeof file); 1247 fd = open(file, O_RDONLY|O_SHLOCK); 1248 if (fd >= 0) { 1249 (void) fstat(fd, &stbuf); 1250 if (stbuf.st_size > 0) { 1251 putchar('\t'); 1252 while ((i = read(fd, line, sizeof(line))) > 0) 1253 (void) fwrite(line, 1, i, stdout); 1254 } 1255 (void) close(fd); /* unlocks as well */ 1256 } 1257} 1258 1259/* 1260 * Stop the specified daemon after completing the current job and disable 1261 * printing. 1262 */ 1263void 1264stop(struct printer *pp) 1265{ 1266 register int fd; 1267 struct stat stbuf; 1268 char lf[MAXPATHLEN]; 1269 1270 lock_file_name(pp, lf, sizeof lf); 1271 printf("%s:\n", pp->printer); 1272 1273 /* 1274 * Turn on the owner execute bit of the lock file to disable printing. 1275 */ 1276 seteuid(euid); 1277 if (stat(lf, &stbuf) >= 0) { 1278 if (chmod(lf, stbuf.st_mode | LFM_PRINT_DIS) < 0) 1279 printf("\tcannot disable printing: %s\n", 1280 strerror(errno)); 1281 else { 1282 upstat(pp, "printing disabled\n"); 1283 printf("\tprinting disabled\n"); 1284 } 1285 } else if (errno == ENOENT) { 1286 if ((fd = open(lf, O_WRONLY|O_CREAT, 1287 LOCK_FILE_MODE | LFM_PRINT_DIS)) < 0) 1288 printf("\tcannot create lock file: %s\n", 1289 strerror(errno)); 1290 else { 1291 (void) close(fd); 1292 upstat(pp, "printing disabled\n"); 1293 printf("\tprinting disabled\n"); 1294 } 1295 } else 1296 printf("\tcannot stat lock file\n"); 1297 seteuid(uid); 1298} 1299 1300/* 1301 * Stop the specified daemon after completing the current job and disable 1302 * printing. 1303 */ 1304void 1305stop_q(struct printer *pp) 1306{ 1307 int setres; 1308 char lf[MAXPATHLEN]; 1309 1310 lock_file_name(pp, lf, sizeof lf); 1311 printf("%s:\n", pp->printer); 1312 1313 setres = set_qstate(SQS_STOPP, lf); 1314 1315 if (setres >= 0) { 1316 seteuid(euid); 1317 upstat(pp, "printing disabled\n"); 1318 seteuid(uid); 1319 } 1320} 1321 1322struct jobqueue **queue; 1323int nitems; 1324time_t mtime; 1325 1326/* 1327 * Put the specified jobs at the top of printer queue. 1328 */ 1329void 1330topq(int argc, char *argv[]) 1331{ 1332 register int i; 1333 struct stat stbuf; 1334 int cmdstatus, changed; 1335 struct printer myprinter, *pp = &myprinter; 1336 1337 if (argc < 3) { 1338 printf("usage: topq printer [jobnum ...] [user ...]\n"); 1339 return; 1340 } 1341 1342 --argc; 1343 ++argv; 1344 init_printer(pp); 1345 cmdstatus = getprintcap(*argv, pp); 1346 switch(cmdstatus) { 1347 default: 1348 fatal(pp, "%s", pcaperr(cmdstatus)); 1349 case PCAPERR_NOTFOUND: 1350 printf("unknown printer %s\n", *argv); 1351 return; 1352 case PCAPERR_TCOPEN: 1353 printf("warning: %s: unresolved tc= reference(s)", *argv); 1354 break; 1355 case PCAPERR_SUCCESS: 1356 break; 1357 } 1358 printf("%s:\n", pp->printer); 1359 1360 seteuid(euid); 1361 if (chdir(pp->spool_dir) < 0) { 1362 printf("\tcannot chdir to %s\n", pp->spool_dir); 1363 goto out; 1364 } 1365 seteuid(uid); 1366 nitems = getq(pp, &queue); 1367 if (nitems == 0) 1368 return; 1369 changed = 0; 1370 mtime = queue[0]->job_time; 1371 for (i = argc; --i; ) { 1372 if (doarg(argv[i]) == 0) { 1373 printf("\tjob %s is not in the queue\n", argv[i]); 1374 continue; 1375 } else 1376 changed++; 1377 } 1378 for (i = 0; i < nitems; i++) 1379 free(queue[i]); 1380 free(queue); 1381 if (!changed) { 1382 printf("\tqueue order unchanged\n"); 1383 return; 1384 } 1385 /* 1386 * Turn on the public execute bit of the lock file to 1387 * get lpd to rebuild the queue after the current job. 1388 */ 1389 seteuid(euid); 1390 if (changed && stat(pp->lock_file, &stbuf) >= 0) 1391 (void) chmod(pp->lock_file, stbuf.st_mode | LFM_RESET_QUE); 1392 1393out: 1394 seteuid(uid); 1395} 1396 1397/* 1398 * Reposition the job by changing the modification time of 1399 * the control file. 1400 */ 1401static int 1402touch(struct jobqueue *jq) 1403{ 1404 struct timeval tvp[2]; 1405 int ret; 1406 1407 tvp[0].tv_sec = tvp[1].tv_sec = --mtime; 1408 tvp[0].tv_usec = tvp[1].tv_usec = 0; 1409 seteuid(euid); 1410 ret = utimes(jq->job_cfname, tvp); 1411 seteuid(uid); 1412 return (ret); 1413} 1414 1415/* 1416 * Checks if specified job name is in the printer's queue. 1417 * Returns: negative (-1) if argument name is not in the queue. 1418 */ 1419static int 1420doarg(char *job) 1421{ 1422 register struct jobqueue **qq; 1423 register int jobnum, n; 1424 register char *cp, *machine; 1425 int cnt = 0; 1426 FILE *fp; 1427 1428 /* 1429 * Look for a job item consisting of system name, colon, number 1430 * (example: ucbarpa:114) 1431 */ 1432 if ((cp = strchr(job, ':')) != NULL) { 1433 machine = job; 1434 *cp++ = '\0'; 1435 job = cp; 1436 } else 1437 machine = NULL; 1438 1439 /* 1440 * Check for job specified by number (example: 112 or 235ucbarpa). 1441 */ 1442 if (isdigit(*job)) { 1443 jobnum = 0; 1444 do 1445 jobnum = jobnum * 10 + (*job++ - '0'); 1446 while (isdigit(*job)); 1447 for (qq = queue + nitems; --qq >= queue; ) { 1448 n = 0; 1449 for (cp = (*qq)->job_cfname+3; isdigit(*cp); ) 1450 n = n * 10 + (*cp++ - '0'); 1451 if (jobnum != n) 1452 continue; 1453 if (*job && strcmp(job, cp) != 0) 1454 continue; 1455 if (machine != NULL && strcmp(machine, cp) != 0) 1456 continue; 1457 if (touch(*qq) == 0) { 1458 printf("\tmoved %s\n", (*qq)->job_cfname); 1459 cnt++; 1460 } 1461 } 1462 return(cnt); 1463 } 1464 /* 1465 * Process item consisting of owner's name (example: henry). 1466 */ 1467 for (qq = queue + nitems; --qq >= queue; ) { 1468 seteuid(euid); 1469 fp = fopen((*qq)->job_cfname, "r"); 1470 seteuid(uid); 1471 if (fp == NULL) 1472 continue; 1473 while (getline(fp) > 0) 1474 if (line[0] == 'P') 1475 break; 1476 (void) fclose(fp); 1477 if (line[0] != 'P' || strcmp(job, line+1) != 0) 1478 continue; 1479 if (touch(*qq) == 0) { 1480 printf("\tmoved %s\n", (*qq)->job_cfname); 1481 cnt++; 1482 } 1483 } 1484 return(cnt); 1485} 1486 1487/* 1488 * Enable everything and start printer (undo `down'). 1489 */ 1490void 1491up(struct printer *pp) 1492{ 1493 startpr(pp, 2); 1494} 1495 1496/* 1497 * Enable both queuing & printing, and start printer (undo `down'). 1498 */ 1499void 1500up_q(struct printer *pp) 1501{ 1502 int setres, startok; 1503 char lf[MAXPATHLEN]; 1504 1505 lock_file_name(pp, lf, sizeof lf); 1506 printf("%s:\n", pp->printer); 1507 1508 setres = set_qstate(SQS_ENABLEQ+SQS_STARTP, lf); 1509 1510 seteuid(euid); 1511 startok = startdaemon(pp); 1512 seteuid(uid); 1513 if (!startok) 1514 printf("\tcouldn't start daemon\n"); 1515 else 1516 printf("\tdaemon started\n"); 1517} 1518