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 static void abortpr __P((struct printer *, int)); 74 static int doarg __P((char *)); 75 static int doselect __P((struct dirent *)); 76 static void putmsg __P((struct printer *, int, char **)); 77 static int sortq __P((const void *, const void *)); 78 static void startpr __P((struct printer *, int)); 79 static int touch __P((struct queue *)); 80 static void unlinkf __P((char *)); 81 static void upstat __P((struct printer *, char *)); 82 83 /* 84 * generic framework for commands which operate on all or a specified 85 * set of printers 86 */ 87 void 88 generic(doit, argc, argv) 89 void (*doit) __P((struct printer *)); 90 int argc; 91 char *argv[]; 92 { 93 int status, more; 94 struct printer myprinter, *pp = &myprinter; 95 96 if (argc == 1) { 97 printf("Usage: %s {all | printer ...}\n", argv[0]); 98 return; 99 } 100 if (argc == 2 && strcmp(argv[1], "all") == 0) { 101 more = firstprinter(pp, &status); 102 if (status) 103 goto looperr; 104 while (more) { 105 (*doit)(pp); 106 do { 107 more = nextprinter(pp, &status); 108 looperr: 109 switch (status) { 110 case PCAPERR_TCOPEN: 111 printf("warning: %s: unresolved " 112 "tc= reference(s) ", 113 pp->printer); 114 case PCAPERR_SUCCESS: 115 break; 116 default: 117 fatal(pp, pcaperr(status)); 118 } 119 } while (more && status); 120 } 121 return; 122 } 123 while (--argc) { 124 ++argv; 125 init_printer(pp); 126 status = getprintcap(*argv, pp); 127 switch(status) { 128 default: 129 fatal(pp, pcaperr(status)); 130 case PCAPERR_NOTFOUND: 131 printf("unknown printer %s\n", *argv); 132 continue; 133 case PCAPERR_TCOPEN: 134 printf("warning: %s: unresolved tc= reference(s)\n", 135 *argv); 136 break; 137 case PCAPERR_SUCCESS: 138 break; 139 } 140 (*doit)(pp); 141 } 142 } 143 144 /* 145 * kill an existing daemon and disable printing. 146 */ 147 void 148 doabort(pp) 149 struct printer *pp; 150 { 151 abortpr(pp, 1); 152 } 153 154 static void 155 abortpr(pp, dis) 156 struct printer *pp; 157 int dis; 158 { 159 register FILE *fp; 160 struct stat stbuf; 161 int pid, fd; 162 char lf[MAXPATHLEN]; 163 164 lock_file_name(pp, lf, sizeof lf); 165 printf("%s:\n", pp->printer); 166 167 /* 168 * Turn on the owner execute bit of the lock file to disable printing. 169 */ 170 if (dis) { 171 seteuid(euid); 172 if (stat(lf, &stbuf) >= 0) { 173 if (chmod(lf, stbuf.st_mode | LFM_PRINT_DIS) < 0) 174 printf("\tcannot disable printing: %s\n", 175 strerror(errno)); 176 else { 177 upstat(pp, "printing disabled\n"); 178 printf("\tprinting disabled\n"); 179 } 180 } else if (errno == ENOENT) { 181 if ((fd = open(lf, O_WRONLY|O_CREAT, 182 LOCK_FILE_MODE | LFM_PRINT_DIS)) < 0) 183 printf("\tcannot create lock file: %s\n", 184 strerror(errno)); 185 else { 186 (void) close(fd); 187 upstat(pp, "printing disabled\n"); 188 printf("\tprinting disabled\n"); 189 printf("\tno daemon to abort\n"); 190 } 191 goto out; 192 } else { 193 printf("\tcannot stat lock file\n"); 194 goto out; 195 } 196 } 197 /* 198 * Kill the current daemon to stop printing now. 199 */ 200 if ((fp = fopen(lf, "r")) == NULL) { 201 printf("\tcannot open lock file\n"); 202 goto out; 203 } 204 if (!getline(fp) || flock(fileno(fp), LOCK_SH|LOCK_NB) == 0) { 205 (void) fclose(fp); /* unlocks as well */ 206 printf("\tno daemon to abort\n"); 207 goto out; 208 } 209 (void) fclose(fp); 210 if (kill(pid = atoi(line), SIGTERM) < 0) { 211 if (errno == ESRCH) 212 printf("\tno daemon to abort\n"); 213 else 214 printf("\tWarning: daemon (pid %d) not killed\n", pid); 215 } else 216 printf("\tdaemon (pid %d) killed\n", pid); 217 out: 218 seteuid(uid); 219 } 220 221 /* 222 * Write a message into the status file. 223 */ 224 static void 225 upstat(pp, msg) 226 struct printer *pp; 227 char *msg; 228 { 229 register int fd; 230 char statfile[MAXPATHLEN]; 231 232 status_file_name(pp, statfile, sizeof statfile); 233 umask(0); 234 fd = open(statfile, O_WRONLY|O_CREAT|O_EXLOCK, STAT_FILE_MODE); 235 if (fd < 0) { 236 printf("\tcannot create status file: %s\n", strerror(errno)); 237 return; 238 } 239 (void) ftruncate(fd, 0); 240 if (msg == (char *)NULL) 241 (void) write(fd, "\n", 1); 242 else 243 (void) write(fd, msg, strlen(msg)); 244 (void) close(fd); 245 } 246 247 static int 248 doselect(d) 249 struct dirent *d; 250 { 251 int c = d->d_name[0]; 252 253 if ((c == 't' || c == 'c' || c == 'd') && d->d_name[1] == 'f') 254 return(1); 255 return(0); 256 } 257 258 /* 259 * Comparison routine for scandir. Sort by job number and machine, then 260 * by `cf', `tf', or `df', then by the sequence letter A-Z, a-z. 261 */ 262 static int 263 sortq(a, b) 264 const void *a, *b; 265 { 266 struct dirent **d1, **d2; 267 int c1, c2; 268 269 d1 = (struct dirent **)a; 270 d2 = (struct dirent **)b; 271 if ((c1 = strcmp((*d1)->d_name + 3, (*d2)->d_name + 3))) 272 return(c1); 273 c1 = (*d1)->d_name[0]; 274 c2 = (*d2)->d_name[0]; 275 if (c1 == c2) 276 return((*d1)->d_name[2] - (*d2)->d_name[2]); 277 if (c1 == 'c') 278 return(-1); 279 if (c1 == 'd' || c2 == 'c') 280 return(1); 281 return(-1); 282 } 283 284 /* 285 * Remove all spool files and temporaries from the spooling area. 286 * Or, perhaps: 287 * Remove incomplete jobs from spooling area. 288 */ 289 void 290 clean(pp) 291 struct printer *pp; 292 { 293 register int i, n; 294 register char *cp, *cp1, *lp; 295 struct dirent **queue; 296 int nitems; 297 298 printf("%s:\n", pp->printer); 299 300 lp = line; 301 cp = pp->spool_dir; 302 while (lp < &line[sizeof(line) - 1]) { 303 if ((*lp++ = *cp++) == 0) 304 break; 305 } 306 lp[-1] = '/'; 307 308 seteuid(euid); 309 nitems = scandir(pp->spool_dir, &queue, doselect, sortq); 310 seteuid(uid); 311 if (nitems < 0) { 312 printf("\tcannot examine spool directory\n"); 313 return; 314 } 315 if (nitems == 0) 316 return; 317 i = 0; 318 do { 319 cp = queue[i]->d_name; 320 if (*cp == 'c') { 321 n = 0; 322 while (i + 1 < nitems) { 323 cp1 = queue[i + 1]->d_name; 324 if (*cp1 != 'd' || strcmp(cp + 3, cp1 + 3)) 325 break; 326 i++; 327 n++; 328 } 329 if (n == 0) { 330 strncpy(lp, cp, sizeof(line) - strlen(line) - 1); 331 line[sizeof(line) - 1] = '\0'; 332 unlinkf(line); 333 } 334 } else { 335 /* 336 * Must be a df with no cf (otherwise, it would have 337 * been skipped above) or a tf file (which can always 338 * be removed). 339 */ 340 strncpy(lp, cp, sizeof(line) - strlen(line) - 1); 341 line[sizeof(line) - 1] = '\0'; 342 unlinkf(line); 343 } 344 } while (++i < nitems); 345 } 346 347 static void 348 unlinkf(name) 349 char *name; 350 { 351 seteuid(euid); 352 if (unlink(name) < 0) 353 printf("\tcannot remove %s\n", name); 354 else 355 printf("\tremoved %s\n", name); 356 seteuid(uid); 357 } 358 359 /* 360 * Enable queuing to the printer (allow lpr's). 361 */ 362 void 363 enable(pp) 364 struct printer *pp; 365 { 366 struct stat stbuf; 367 char lf[MAXPATHLEN]; 368 369 lock_file_name(pp, lf, sizeof lf); 370 printf("%s:\n", pp->printer); 371 372 /* 373 * Turn off the group execute bit of the lock file to enable queuing. 374 */ 375 seteuid(euid); 376 if (stat(lf, &stbuf) >= 0) { 377 if (chmod(lf, stbuf.st_mode & ~LFM_QUEUE_DIS) < 0) 378 printf("\tcannot enable queuing\n"); 379 else 380 printf("\tqueuing enabled\n"); 381 } 382 seteuid(uid); 383 } 384 385 /* 386 * Disable queuing. 387 */ 388 void 389 disable(pp) 390 struct printer *pp; 391 { 392 register int fd; 393 struct stat stbuf; 394 char lf[MAXPATHLEN]; 395 396 lock_file_name(pp, lf, sizeof lf); 397 printf("%s:\n", pp->printer); 398 /* 399 * Turn on the group execute bit of the lock file to disable queuing. 400 */ 401 seteuid(euid); 402 if (stat(lf, &stbuf) >= 0) { 403 if (chmod(lf, stbuf.st_mode | LFM_QUEUE_DIS) < 0) 404 printf("\tcannot disable queuing: %s\n", 405 strerror(errno)); 406 else 407 printf("\tqueuing disabled\n"); 408 } else if (errno == ENOENT) { 409 if ((fd = open(lf, O_WRONLY|O_CREAT, 410 LOCK_FILE_MODE | LFM_QUEUE_DIS)) < 0) 411 printf("\tcannot create lock file: %s\n", 412 strerror(errno)); 413 else { 414 (void) close(fd); 415 printf("\tqueuing disabled\n"); 416 } 417 } else 418 printf("\tcannot stat lock file\n"); 419 seteuid(uid); 420 } 421 422 /* 423 * Disable queuing and printing and put a message into the status file 424 * (reason for being down). 425 */ 426 void 427 down(argc, argv) 428 int argc; 429 char *argv[]; 430 { 431 int status, more; 432 struct printer myprinter, *pp = &myprinter; 433 434 if (argc == 1) { 435 printf("Usage: down {all | printer} [message ...]\n"); 436 return; 437 } 438 if (!strcmp(argv[1], "all")) { 439 more = firstprinter(pp, &status); 440 if (status) 441 goto looperr; 442 while (more) { 443 putmsg(pp, argc - 2, argv + 2); 444 do { 445 more = nextprinter(pp, &status); 446 looperr: 447 switch (status) { 448 case PCAPERR_TCOPEN: 449 printf("warning: %s: unresolved " 450 "tc= reference(s) ", 451 pp->printer); 452 case PCAPERR_SUCCESS: 453 break; 454 default: 455 fatal(pp, pcaperr(status)); 456 } 457 } while (more && status); 458 } 459 return; 460 } 461 init_printer(pp); 462 status = getprintcap(argv[1], pp); 463 switch(status) { 464 default: 465 fatal(pp, pcaperr(status)); 466 case PCAPERR_NOTFOUND: 467 printf("unknown printer %s\n", argv[1]); 468 return; 469 case PCAPERR_TCOPEN: 470 printf("warning: %s: unresolved tc= reference(s)", argv[1]); 471 break; 472 case PCAPERR_SUCCESS: 473 break; 474 } 475 putmsg(pp, argc - 2, argv + 2); 476 } 477 478 static void 479 putmsg(pp, argc, argv) 480 struct printer *pp; 481 int argc; 482 char **argv; 483 { 484 register int fd; 485 register char *cp1, *cp2; 486 char buf[1024]; 487 char file[MAXPATHLEN]; 488 struct stat stbuf; 489 490 printf("%s:\n", pp->printer); 491 /* 492 * Turn on the group execute bit of the lock file to disable queuing; 493 * turn on the owner execute bit of the lock file to disable printing. 494 */ 495 lock_file_name(pp, file, sizeof file); 496 seteuid(euid); 497 if (stat(file, &stbuf) >= 0) { 498 if (chmod(file, stbuf.st_mode|LFM_PRINT_DIS|LFM_QUEUE_DIS) < 0) 499 printf("\tcannot disable queuing: %s\n", 500 strerror(errno)); 501 else 502 printf("\tprinter and queuing disabled\n"); 503 } else if (errno == ENOENT) { 504 if ((fd = open(file, O_WRONLY|O_CREAT, 505 LOCK_FILE_MODE|LFM_PRINT_DIS|LFM_QUEUE_DIS)) < 0) 506 printf("\tcannot create lock file: %s\n", 507 strerror(errno)); 508 else { 509 (void) close(fd); 510 printf("\tprinter and queuing disabled\n"); 511 } 512 seteuid(uid); 513 return; 514 } else 515 printf("\tcannot stat lock file\n"); 516 /* 517 * Write the message into the status file. 518 */ 519 status_file_name(pp, file, sizeof file); 520 fd = open(file, O_WRONLY|O_CREAT|O_EXLOCK, STAT_FILE_MODE); 521 if (fd < 0) { 522 printf("\tcannot create status file: %s\n", strerror(errno)); 523 seteuid(uid); 524 return; 525 } 526 seteuid(uid); 527 (void) ftruncate(fd, 0); 528 if (argc <= 0) { 529 (void) write(fd, "\n", 1); 530 (void) close(fd); 531 return; 532 } 533 cp1 = buf; 534 while (--argc >= 0) { 535 cp2 = *argv++; 536 while ((cp1 - buf) < sizeof(buf) && (*cp1++ = *cp2++)) 537 ; 538 cp1[-1] = ' '; 539 } 540 cp1[-1] = '\n'; 541 *cp1 = '\0'; 542 (void) write(fd, buf, strlen(buf)); 543 (void) close(fd); 544 } 545 546 /* 547 * Exit lpc 548 */ 549 void 550 quit(argc, argv) 551 int argc; 552 char *argv[]; 553 { 554 exit(0); 555 } 556 557 /* 558 * Kill and restart the daemon. 559 */ 560 void 561 restart(pp) 562 struct printer *pp; 563 { 564 abortpr(pp, 0); 565 startpr(pp, 0); 566 } 567 568 /* 569 * Enable printing on the specified printer and startup the daemon. 570 */ 571 void 572 startcmd(pp) 573 struct printer *pp; 574 { 575 startpr(pp, 1); 576 } 577 578 static void 579 startpr(pp, enable) 580 struct printer *pp; 581 int enable; 582 { 583 struct stat stbuf; 584 char lf[MAXPATHLEN]; 585 586 lock_file_name(pp, lf, sizeof lf); 587 printf("%s:\n", pp->printer); 588 589 /* 590 * For enable==1 ('start'), turn off the LFM_PRINT_DIS bit of the 591 * lock file to re-enable printing. For enable==2 ('up'), also 592 * turn off the LFM_QUEUE_DIS bit to re-enable queueing. 593 */ 594 seteuid(euid); 595 if (enable && stat(lf, &stbuf) >= 0) { 596 mode_t bits = (enable == 2 ? 0 : LFM_QUEUE_DIS); 597 if (chmod(lf, stbuf.st_mode & (LOCK_FILE_MODE | bits)) < 0) 598 printf("\tcannot enable printing\n"); 599 else 600 printf("\tprinting enabled\n"); 601 } 602 if (!startdaemon(pp)) 603 printf("\tcouldn't start daemon\n"); 604 else 605 printf("\tdaemon started\n"); 606 seteuid(uid); 607 } 608 609 /* 610 * Print the status of the printer queue. 611 */ 612 void 613 status(pp) 614 struct printer *pp; 615 { 616 struct stat stbuf; 617 register int fd, i; 618 register struct dirent *dp; 619 DIR *dirp; 620 char file[MAXPATHLEN]; 621 622 printf("%s:\n", pp->printer); 623 lock_file_name(pp, file, sizeof file); 624 if (stat(file, &stbuf) >= 0) { 625 printf("\tqueuing is %s\n", 626 ((stbuf.st_mode & LFM_QUEUE_DIS) ? "disabled" 627 : "enabled")); 628 printf("\tprinting is %s\n", 629 ((stbuf.st_mode & LFM_PRINT_DIS) ? "disabled" 630 : "enabled")); 631 } else { 632 printf("\tqueuing is enabled\n"); 633 printf("\tprinting is enabled\n"); 634 } 635 if ((dirp = opendir(pp->spool_dir)) == NULL) { 636 printf("\tcannot examine spool directory\n"); 637 return; 638 } 639 i = 0; 640 while ((dp = readdir(dirp)) != NULL) { 641 if (*dp->d_name == 'c' && dp->d_name[1] == 'f') 642 i++; 643 } 644 closedir(dirp); 645 if (i == 0) 646 printf("\tno entries in spool area\n"); 647 else if (i == 1) 648 printf("\t1 entry in spool area\n"); 649 else 650 printf("\t%d entries in spool area\n", i); 651 fd = open(file, O_RDONLY); 652 if (fd < 0 || flock(fd, LOCK_SH|LOCK_NB) == 0) { 653 (void) close(fd); /* unlocks as well */ 654 printf("\tprinter idle\n"); 655 return; 656 } 657 (void) close(fd); 658 /* print out the contents of the status file, if it exists */ 659 status_file_name(pp, file, sizeof file); 660 fd = open(file, O_RDONLY|O_SHLOCK); 661 if (fd >= 0) { 662 (void) fstat(fd, &stbuf); 663 if (stbuf.st_size > 0) { 664 putchar('\t'); 665 while ((i = read(fd, line, sizeof(line))) > 0) 666 (void) fwrite(line, 1, i, stdout); 667 } 668 (void) close(fd); /* unlocks as well */ 669 } 670 } 671 672 /* 673 * Stop the specified daemon after completing the current job and disable 674 * printing. 675 */ 676 void 677 stop(pp) 678 struct printer *pp; 679 { 680 register int fd; 681 struct stat stbuf; 682 char lf[MAXPATHLEN]; 683 684 lock_file_name(pp, lf, sizeof lf); 685 printf("%s:\n", pp->printer); 686 687 /* 688 * Turn on the owner execute bit of the lock file to disable printing. 689 */ 690 seteuid(euid); 691 if (stat(lf, &stbuf) >= 0) { 692 if (chmod(lf, stbuf.st_mode | LFM_PRINT_DIS) < 0) 693 printf("\tcannot disable printing: %s\n", 694 strerror(errno)); 695 else { 696 upstat(pp, "printing disabled\n"); 697 printf("\tprinting disabled\n"); 698 } 699 } else if (errno == ENOENT) { 700 if ((fd = open(lf, O_WRONLY|O_CREAT, 701 LOCK_FILE_MODE | LFM_PRINT_DIS)) < 0) 702 printf("\tcannot create lock file: %s\n", 703 strerror(errno)); 704 else { 705 (void) close(fd); 706 upstat(pp, "printing disabled\n"); 707 printf("\tprinting disabled\n"); 708 } 709 } else 710 printf("\tcannot stat lock file\n"); 711 seteuid(uid); 712 } 713 714 struct queue **queue; 715 int nitems; 716 time_t mtime; 717 718 /* 719 * Put the specified jobs at the top of printer queue. 720 */ 721 void 722 topq(argc, argv) 723 int argc; 724 char *argv[]; 725 { 726 register int i; 727 struct stat stbuf; 728 int status, changed; 729 struct printer myprinter, *pp = &myprinter; 730 731 if (argc < 3) { 732 printf("Usage: topq printer [jobnum ...] [user ...]\n"); 733 return; 734 } 735 736 --argc; 737 ++argv; 738 init_printer(pp); 739 status = getprintcap(*argv, pp); 740 switch(status) { 741 default: 742 fatal(pp, pcaperr(status)); 743 case PCAPERR_NOTFOUND: 744 printf("unknown printer %s\n", *argv); 745 return; 746 case PCAPERR_TCOPEN: 747 printf("warning: %s: unresolved tc= reference(s)", *argv); 748 break; 749 case PCAPERR_SUCCESS: 750 break; 751 } 752 printf("%s:\n", pp->printer); 753 754 seteuid(euid); 755 if (chdir(pp->spool_dir) < 0) { 756 printf("\tcannot chdir to %s\n", pp->spool_dir); 757 goto out; 758 } 759 seteuid(uid); 760 nitems = getq(pp, &queue); 761 if (nitems == 0) 762 return; 763 changed = 0; 764 mtime = queue[0]->q_time; 765 for (i = argc; --i; ) { 766 if (doarg(argv[i]) == 0) { 767 printf("\tjob %s is not in the queue\n", argv[i]); 768 continue; 769 } else 770 changed++; 771 } 772 for (i = 0; i < nitems; i++) 773 free(queue[i]); 774 free(queue); 775 if (!changed) { 776 printf("\tqueue order unchanged\n"); 777 return; 778 } 779 /* 780 * Turn on the public execute bit of the lock file to 781 * get lpd to rebuild the queue after the current job. 782 */ 783 seteuid(euid); 784 if (changed && stat(pp->lock_file, &stbuf) >= 0) 785 (void) chmod(pp->lock_file, stbuf.st_mode | LFM_RESET_QUE); 786 787 out: 788 seteuid(uid); 789 } 790 791 /* 792 * Reposition the job by changing the modification time of 793 * the control file. 794 */ 795 static int 796 touch(q) 797 struct queue *q; 798 { 799 struct timeval tvp[2]; 800 int ret; 801 802 tvp[0].tv_sec = tvp[1].tv_sec = --mtime; 803 tvp[0].tv_usec = tvp[1].tv_usec = 0; 804 seteuid(euid); 805 ret = utimes(q->q_name, tvp); 806 seteuid(uid); 807 return (ret); 808 } 809 810 /* 811 * Checks if specified job name is in the printer's queue. 812 * Returns: negative (-1) if argument name is not in the queue. 813 */ 814 static int 815 doarg(job) 816 char *job; 817 { 818 register struct queue **qq; 819 register int jobnum, n; 820 register char *cp, *machine; 821 int cnt = 0; 822 FILE *fp; 823 824 /* 825 * Look for a job item consisting of system name, colon, number 826 * (example: ucbarpa:114) 827 */ 828 if ((cp = strchr(job, ':')) != NULL) { 829 machine = job; 830 *cp++ = '\0'; 831 job = cp; 832 } else 833 machine = NULL; 834 835 /* 836 * Check for job specified by number (example: 112 or 235ucbarpa). 837 */ 838 if (isdigit(*job)) { 839 jobnum = 0; 840 do 841 jobnum = jobnum * 10 + (*job++ - '0'); 842 while (isdigit(*job)); 843 for (qq = queue + nitems; --qq >= queue; ) { 844 n = 0; 845 for (cp = (*qq)->q_name+3; isdigit(*cp); ) 846 n = n * 10 + (*cp++ - '0'); 847 if (jobnum != n) 848 continue; 849 if (*job && strcmp(job, cp) != 0) 850 continue; 851 if (machine != NULL && strcmp(machine, cp) != 0) 852 continue; 853 if (touch(*qq) == 0) { 854 printf("\tmoved %s\n", (*qq)->q_name); 855 cnt++; 856 } 857 } 858 return(cnt); 859 } 860 /* 861 * Process item consisting of owner's name (example: henry). 862 */ 863 for (qq = queue + nitems; --qq >= queue; ) { 864 seteuid(euid); 865 fp = fopen((*qq)->q_name, "r"); 866 seteuid(uid); 867 if (fp == NULL) 868 continue; 869 while (getline(fp) > 0) 870 if (line[0] == 'P') 871 break; 872 (void) fclose(fp); 873 if (line[0] != 'P' || strcmp(job, line+1) != 0) 874 continue; 875 if (touch(*qq) == 0) { 876 printf("\tmoved %s\n", (*qq)->q_name); 877 cnt++; 878 } 879 } 880 return(cnt); 881 } 882 883 /* 884 * Enable everything and start printer (undo `down'). 885 */ 886 void 887 up(pp) 888 struct printer *pp; 889 { 890 startpr(pp, 2); 891 } 892