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