cmds.c revision 39084
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 "$Id: cmds.c,v 1.11 1997/12/02 20:45:37 wollman Exp $"; 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 73static void abortpr __P((struct printer *, int)); 74static int doarg __P((char *)); 75static int doselect __P((struct dirent *)); 76static void putmsg __P((struct printer *, int, char **)); 77static int sortq __P((const void *, const void *)); 78static void startpr __P((struct printer *, int)); 79static int touch __P((struct queue *)); 80static void unlinkf __P((char *)); 81static 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 */ 87void 88generic(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); 108looperr: 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 */ 147void 148doabort(pp) 149 struct printer *pp; 150{ 151 abortpr(pp, 1); 152} 153 154static void 155abortpr(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); 217out: 218 seteuid(uid); 219} 220 221/* 222 * Write a message into the status file. 223 */ 224static void 225upstat(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 247static int 248doselect(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 */ 262static int 263sortq(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 */ 289void 290clean(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 347static void 348unlinkf(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 */ 362void 363enable(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 */ 388void 389disable(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 */ 426void 427down(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); 446looperr: 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 478static void 479putmsg(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 */ 549void 550quit(argc, argv) 551 int argc; 552 char *argv[]; 553{ 554 exit(0); 555} 556 557/* 558 * Kill and restart the daemon. 559 */ 560void 561restart(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 */ 571void 572startcmd(pp) 573 struct printer *pp; 574{ 575 startpr(pp, 1); 576} 577 578static void 579startpr(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 * Turn off the owner execute bit of the lock file to enable printing. 591 */ 592 seteuid(euid); 593 if (enable && stat(lf, &stbuf) >= 0) { 594 mode_t bits = (enable == 2 ? 0 595 : (LFM_PRINT_DIS | LFM_QUEUE_DIS)); 596 if (chmod(lf, stbuf.st_mode & (LOCK_FILE_MODE | bits)) < 0) 597 printf("\tcannot enable printing\n"); 598 else 599 printf("\tprinting enabled\n"); 600 } 601 if (!startdaemon(pp)) 602 printf("\tcouldn't start daemon\n"); 603 else 604 printf("\tdaemon started\n"); 605 seteuid(uid); 606} 607 608/* 609 * Print the status of the printer queue. 610 */ 611void 612status(pp) 613 struct printer *pp; 614{ 615 struct stat stbuf; 616 register int fd, i; 617 register struct dirent *dp; 618 DIR *dirp; 619 char file[MAXPATHLEN]; 620 621 printf("%s:\n", pp->printer); 622 lock_file_name(pp, file, sizeof file); 623 if (stat(file, &stbuf) >= 0) { 624 printf("\tqueuing is %s\n", 625 ((stbuf.st_mode & LFM_QUEUE_DIS) ? "disabled" 626 : "enabled")); 627 printf("\tprinting is %s\n", 628 ((stbuf.st_mode & LFM_PRINT_DIS) ? "disabled" 629 : "enabled")); 630 } else { 631 printf("\tqueuing is enabled\n"); 632 printf("\tprinting is enabled\n"); 633 } 634 if ((dirp = opendir(pp->spool_dir)) == NULL) { 635 printf("\tcannot examine spool directory\n"); 636 return; 637 } 638 i = 0; 639 while ((dp = readdir(dirp)) != NULL) { 640 if (*dp->d_name == 'c' && dp->d_name[1] == 'f') 641 i++; 642 } 643 closedir(dirp); 644 if (i == 0) 645 printf("\tno entries in spool area\n"); 646 else if (i == 1) 647 printf("\t1 entry in spool area\n"); 648 else 649 printf("\t%d entries in spool area\n", i); 650 fd = open(file, O_RDONLY); 651 if (fd < 0 || flock(fd, LOCK_SH|LOCK_NB) == 0) { 652 (void) close(fd); /* unlocks as well */ 653 printf("\tprinter idle\n"); 654 return; 655 } 656 (void) close(fd); 657 /* print out the contents of the status file, if it exists */ 658 status_file_name(pp, file, sizeof file); 659 fd = open(file, O_RDONLY|O_SHLOCK); 660 if (fd >= 0) { 661 (void) fstat(fd, &stbuf); 662 if (stbuf.st_size > 0) { 663 putchar('\t'); 664 while ((i = read(fd, line, sizeof(line))) > 0) 665 (void) fwrite(line, 1, i, stdout); 666 } 667 (void) close(fd); /* unlocks as well */ 668 } 669} 670 671/* 672 * Stop the specified daemon after completing the current job and disable 673 * printing. 674 */ 675void 676stop(pp) 677 struct printer *pp; 678{ 679 register int fd; 680 struct stat stbuf; 681 char lf[MAXPATHLEN]; 682 683 lock_file_name(pp, lf, sizeof lf); 684 printf("%s:\n", pp->printer); 685 686 /* 687 * Turn on the owner execute bit of the lock file to disable printing. 688 */ 689 seteuid(euid); 690 if (stat(lf, &stbuf) >= 0) { 691 if (chmod(lf, stbuf.st_mode | LFM_PRINT_DIS) < 0) 692 printf("\tcannot disable printing: %s\n", 693 strerror(errno)); 694 else { 695 upstat(pp, "printing disabled\n"); 696 printf("\tprinting disabled\n"); 697 } 698 } else if (errno == ENOENT) { 699 if ((fd = open(lf, O_WRONLY|O_CREAT, 700 LOCK_FILE_MODE | LFM_PRINT_DIS)) < 0) 701 printf("\tcannot create lock file: %s\n", 702 strerror(errno)); 703 else { 704 (void) close(fd); 705 upstat(pp, "printing disabled\n"); 706 printf("\tprinting disabled\n"); 707 } 708 } else 709 printf("\tcannot stat lock file\n"); 710 seteuid(uid); 711} 712 713struct queue **queue; 714int nitems; 715time_t mtime; 716 717/* 718 * Put the specified jobs at the top of printer queue. 719 */ 720void 721topq(argc, argv) 722 int argc; 723 char *argv[]; 724{ 725 register int i; 726 struct stat stbuf; 727 int status, changed; 728 struct printer myprinter, *pp = &myprinter; 729 730 if (argc < 3) { 731 printf("Usage: topq printer [jobnum ...] [user ...]\n"); 732 return; 733 } 734 735 --argc; 736 ++argv; 737 init_printer(pp); 738 status = getprintcap(*argv, pp); 739 switch(status) { 740 default: 741 fatal(pp, pcaperr(status)); 742 case PCAPERR_NOTFOUND: 743 printf("unknown printer %s\n", *argv); 744 return; 745 case PCAPERR_TCOPEN: 746 printf("warning: %s: unresolved tc= reference(s)", *argv); 747 break; 748 case PCAPERR_SUCCESS: 749 break; 750 } 751 printf("%s:\n", pp->printer); 752 753 seteuid(euid); 754 if (chdir(pp->spool_dir) < 0) { 755 printf("\tcannot chdir to %s\n", pp->spool_dir); 756 goto out; 757 } 758 seteuid(uid); 759 nitems = getq(pp, &queue); 760 if (nitems == 0) 761 return; 762 changed = 0; 763 mtime = queue[0]->q_time; 764 for (i = argc; --i; ) { 765 if (doarg(argv[i]) == 0) { 766 printf("\tjob %s is not in the queue\n", argv[i]); 767 continue; 768 } else 769 changed++; 770 } 771 for (i = 0; i < nitems; i++) 772 free(queue[i]); 773 free(queue); 774 if (!changed) { 775 printf("\tqueue order unchanged\n"); 776 return; 777 } 778 /* 779 * Turn on the public execute bit of the lock file to 780 * get lpd to rebuild the queue after the current job. 781 */ 782 seteuid(euid); 783 if (changed && stat(pp->lock_file, &stbuf) >= 0) 784 (void) chmod(pp->lock_file, stbuf.st_mode | LFM_RESET_QUE); 785 786out: 787 seteuid(uid); 788} 789 790/* 791 * Reposition the job by changing the modification time of 792 * the control file. 793 */ 794static int 795touch(q) 796 struct queue *q; 797{ 798 struct timeval tvp[2]; 799 int ret; 800 801 tvp[0].tv_sec = tvp[1].tv_sec = --mtime; 802 tvp[0].tv_usec = tvp[1].tv_usec = 0; 803 seteuid(euid); 804 ret = utimes(q->q_name, tvp); 805 seteuid(uid); 806 return (ret); 807} 808 809/* 810 * Checks if specified job name is in the printer's queue. 811 * Returns: negative (-1) if argument name is not in the queue. 812 */ 813static int 814doarg(job) 815 char *job; 816{ 817 register struct queue **qq; 818 register int jobnum, n; 819 register char *cp, *machine; 820 int cnt = 0; 821 FILE *fp; 822 823 /* 824 * Look for a job item consisting of system name, colon, number 825 * (example: ucbarpa:114) 826 */ 827 if ((cp = strchr(job, ':')) != NULL) { 828 machine = job; 829 *cp++ = '\0'; 830 job = cp; 831 } else 832 machine = NULL; 833 834 /* 835 * Check for job specified by number (example: 112 or 235ucbarpa). 836 */ 837 if (isdigit(*job)) { 838 jobnum = 0; 839 do 840 jobnum = jobnum * 10 + (*job++ - '0'); 841 while (isdigit(*job)); 842 for (qq = queue + nitems; --qq >= queue; ) { 843 n = 0; 844 for (cp = (*qq)->q_name+3; isdigit(*cp); ) 845 n = n * 10 + (*cp++ - '0'); 846 if (jobnum != n) 847 continue; 848 if (*job && strcmp(job, cp) != 0) 849 continue; 850 if (machine != NULL && strcmp(machine, cp) != 0) 851 continue; 852 if (touch(*qq) == 0) { 853 printf("\tmoved %s\n", (*qq)->q_name); 854 cnt++; 855 } 856 } 857 return(cnt); 858 } 859 /* 860 * Process item consisting of owner's name (example: henry). 861 */ 862 for (qq = queue + nitems; --qq >= queue; ) { 863 seteuid(euid); 864 fp = fopen((*qq)->q_name, "r"); 865 seteuid(uid); 866 if (fp == NULL) 867 continue; 868 while (getline(fp) > 0) 869 if (line[0] == 'P') 870 break; 871 (void) fclose(fp); 872 if (line[0] != 'P' || strcmp(job, line+1) != 0) 873 continue; 874 if (touch(*qq) == 0) { 875 printf("\tmoved %s\n", (*qq)->q_name); 876 cnt++; 877 } 878 } 879 return(cnt); 880} 881 882/* 883 * Enable everything and start printer (undo `down'). 884 */ 885void 886up(pp) 887 struct printer *pp; 888{ 889 startpr(pp, 2); 890} 891