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