1 /* $NetBSD: cmds.c,v 1.18 2005/11/28 03:26:06 christos Exp $ */ 2 /* 3 * Copyright (c) 1983, 1993 4 * The Regents of the University of California. All rights reserved. 5 * 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. Neither the name of the University nor the names of its contributors 16 * may be used to endorse or promote products derived from this software 17 * without specific prior written permission. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29 * SUCH DAMAGE. 30 */ 31 32 #include <sys/cdefs.h> 33 #ifndef lint 34 __COPYRIGHT("@(#) Copyright (c) 1983, 1993\n\ 35 The Regents of the University of California. All rights reserved.\n"); 36 #if 0 37 static char sccsid[] = "@(#)cmds.c 8.2 (Berkeley) 4/28/95"; 38 #else 39 __RCSID("$NetBSD: cmds.c,v 1.18 2005/11/28 03:26:06 christos Exp $"); 40 #endif 41 #endif /* not lint */ 42 43 /* 44 * lpc -- line printer control program -- commands: 45 */ 46 47 #include <sys/param.h> 48 #include <sys/time.h> 49 #include <sys/stat.h> 50 #include <sys/file.h> 51 52 #include <signal.h> 53 #include <fcntl.h> 54 #include <errno.h> 55 #include <dirent.h> 56 #include <unistd.h> 57 #include <stdlib.h> 58 #include <stdio.h> 59 #include <ctype.h> 60 #include <string.h> 61 #include "lp.h" 62 #include "lp.local.h" 63 #include "lpc.h" 64 #include "extern.h" 65 #include "pathnames.h" 66 67 extern uid_t uid, euid; 68 69 static void abortpr(int); 70 static void cleanpr(void); 71 static void disablepr(void); 72 static int doarg(const char *); 73 static int doselect(const struct dirent *); 74 static void enablepr(void); 75 static void prstat(void); 76 static void putmsg(int, char **); 77 static int sortq(const void *, const void *); 78 static void startpr(int); 79 static void stoppr(void); 80 static int touch(struct queue *); 81 static void unlinkf(const char *); 82 static void upstat(const char *); 83 static int getcapdesc(void); 84 static void getcaps(void); 85 86 /* 87 * kill an existing daemon and disable printing. 88 */ 89 void 90 doabort(int argc, char *argv[]) 91 { 92 int c; 93 char *cp1, *cp2; 94 char prbuf[100]; 95 96 if (argc == 1) { 97 printf("Usage: abort {all | printer ...}\n"); 98 return; 99 } 100 if (argc == 2 && !strcmp(argv[1], "all")) { 101 printer = prbuf; 102 while (cgetnext(&bp, printcapdb) > 0) { 103 cp1 = prbuf; 104 cp2 = bp; 105 while ((c = *cp2++) && c != '|' && c != ':' && 106 (cp1 - prbuf) < sizeof(prbuf)) 107 *cp1++ = c; 108 *cp1 = '\0'; 109 abortpr(1); 110 } 111 return; 112 } 113 while (--argc) { 114 printer = *++argv; 115 if (!getcapdesc()) 116 continue; 117 abortpr(1); 118 } 119 } 120 121 static void 122 abortpr(int dis) 123 { 124 FILE *fp; 125 struct stat stbuf; 126 int pid, fd; 127 128 getcaps(); 129 printf("%s:\n", printer); 130 131 /* 132 * Turn on the owner execute bit of the lock file to disable printing. 133 */ 134 if (dis) { 135 seteuid(euid); 136 if (stat(line, &stbuf) >= 0) { 137 if (chmod(line, (stbuf.st_mode & 0777) | 0100) < 0) 138 printf("\tcannot disable printing\n"); 139 else { 140 upstat("printing disabled\n"); 141 printf("\tprinting disabled\n"); 142 } 143 } else if (errno == ENOENT) { 144 if ((fd = open(line, O_WRONLY|O_CREAT, 0760)) < 0) 145 printf("\tcannot create lock file\n"); 146 else { 147 (void)close(fd); 148 upstat("printing disabled\n"); 149 printf("\tprinting disabled\n"); 150 printf("\tno daemon to abort\n"); 151 } 152 goto out; 153 } else { 154 printf("\tcannot stat lock file\n"); 155 goto out; 156 } 157 } 158 /* 159 * Kill the current daemon to stop printing now. 160 */ 161 if ((fp = fopen(line, "r")) == NULL) { 162 printf("\tcannot open lock file\n"); 163 goto out; 164 } 165 if (!getline(fp) || flock(fileno(fp), LOCK_SH|LOCK_NB) == 0) { 166 (void)fclose(fp); /* unlocks as well */ 167 printf("\tno daemon to abort\n"); 168 goto out; 169 } 170 (void)fclose(fp); 171 if (kill(pid = atoi(line), SIGTERM) < 0) { 172 if (errno == ESRCH) 173 printf("\tno daemon to abort\n"); 174 else 175 printf("\tWarning: daemon (pid %d) not killed\n", pid); 176 } else 177 printf("\tdaemon (pid %d) killed\n", pid); 178 out: 179 seteuid(uid); 180 } 181 182 /* 183 * Write a message into the status file. 184 */ 185 static void 186 upstat(const char *msg) 187 { 188 int fd; 189 char statfile[MAXPATHLEN]; 190 191 getcaps(); 192 (void)snprintf(statfile, sizeof(statfile), "%s/%s", SD, ST); 193 umask(0); 194 fd = open(statfile, O_WRONLY|O_CREAT, 0664); 195 if (fd < 0 || flock(fd, LOCK_EX) < 0) { 196 printf("\tcannot create status file\n"); 197 return; 198 } 199 (void)ftruncate(fd, 0); 200 if (msg == (char *)NULL) 201 (void)write(fd, "\n", 1); 202 else 203 (void)write(fd, msg, strlen(msg)); 204 (void)close(fd); 205 } 206 207 /* 208 * Remove all spool files and temporaries from the spooling area. 209 */ 210 void 211 clean(int argc, char *argv[]) 212 { 213 int c; 214 char *cp1, *cp2; 215 char prbuf[100]; 216 217 if (argc == 1) { 218 printf("Usage: clean {all | printer ...}\n"); 219 return; 220 } 221 if (argc == 2 && !strcmp(argv[1], "all")) { 222 printer = prbuf; 223 while (cgetnext(&bp, printcapdb) > 0) { 224 cp1 = prbuf; 225 cp2 = bp; 226 while ((c = *cp2++) && c != '|' && c != ':' && 227 (cp1 - prbuf) < sizeof(prbuf)) 228 *cp1++ = c; 229 *cp1 = '\0'; 230 cleanpr(); 231 } 232 return; 233 } 234 while (--argc) { 235 printer = *++argv; 236 if (!getcapdesc()) 237 continue; 238 cleanpr(); 239 } 240 } 241 242 static int 243 doselect(const struct dirent *d) 244 { 245 int c = d->d_name[0]; 246 247 if ((c == 't' || c == 'c' || c == 'd') && d->d_name[1] == 'f') 248 return(1); 249 return(0); 250 } 251 252 /* 253 * Comparison routine for scandir. Sort by job number and machine, then 254 * by `cf', `tf', or `df', then by the sequence letter A-Z, a-z. 255 */ 256 static int 257 sortq(const void *a, const void *b) 258 { 259 const struct dirent *const *d1, *const *d2; 260 int c1, c2; 261 262 d1 = (const struct dirent *const *)a; 263 d2 = (const struct dirent *const *)b; 264 if ((c1 = strcmp((*d1)->d_name + 3, (*d2)->d_name + 3)) != 0) 265 return(c1); 266 c1 = (*d1)->d_name[0]; 267 c2 = (*d2)->d_name[0]; 268 if (c1 == c2) 269 return((*d1)->d_name[2] - (*d2)->d_name[2]); 270 if (c1 == 'c') 271 return(-1); 272 if (c1 == 'd' || c2 == 'c') 273 return(1); 274 return(-1); 275 } 276 277 /* 278 * Remove incomplete jobs from spooling area. 279 */ 280 static void 281 cleanpr(void) 282 { 283 int i, n; 284 char *cp1, *lp, *ep; 285 const char *cp; 286 struct dirent **queue; 287 int nitems; 288 289 getcaps(); 290 printf("%s:\n", printer); 291 292 /* XXX depends on SD being non nul */ 293 ep = line + sizeof(line); 294 for (lp = line, cp = SD; (lp - line) < sizeof(line) && 295 (*lp++ = *cp++) != '\0'; ) 296 ; 297 lp[-1] = '/'; 298 299 seteuid(euid); 300 nitems = scandir(SD, &queue, doselect, sortq); 301 seteuid(uid); 302 if (nitems < 0) { 303 printf("\tcannot examine spool directory\n"); 304 return; 305 } 306 if (nitems == 0) 307 return; 308 i = 0; 309 do { 310 cp = queue[i]->d_name; 311 if (*cp == 'c') { 312 n = 0; 313 while (i + 1 < nitems) { 314 cp1 = queue[i + 1]->d_name; 315 if (*cp1 != 'd' || strcmp(cp + 3, cp1 + 3)) 316 break; 317 i++; 318 n++; 319 } 320 if (n == 0) { 321 strlcpy(lp, cp, ep - lp); 322 unlinkf(line); 323 } 324 } else { 325 /* 326 * Must be a df with no cf (otherwise, it would have 327 * been skipped above) or a tf file (which can always 328 * be removed). 329 */ 330 strlcpy(lp, cp, ep - lp); 331 unlinkf(line); 332 } 333 } while (++i < nitems); 334 } 335 336 static void 337 unlinkf(const 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 */ 350 void 351 enable(int argc, char *argv[]) 352 { 353 int c; 354 char *cp1, *cp2; 355 char prbuf[100]; 356 357 if (argc == 1) { 358 printf("Usage: enable {all | printer ...}\n"); 359 return; 360 } 361 if (argc == 2 && !strcmp(argv[1], "all")) { 362 printer = prbuf; 363 while (cgetnext(&bp, printcapdb) > 0) { 364 cp1 = prbuf; 365 cp2 = bp; 366 while ((c = *cp2++) && c != '|' && c != ':' && 367 (cp1 - prbuf) < sizeof(prbuf)) 368 *cp1++ = c; 369 *cp1 = '\0'; 370 enablepr(); 371 } 372 return; 373 } 374 while (--argc) { 375 printer = *++argv; 376 if (!getcapdesc()) 377 continue; 378 enablepr(); 379 } 380 } 381 382 static int 383 getcapdesc(void) 384 { 385 int st; 386 if ((st = cgetent(&bp, printcapdb, printer)) == -2) { 387 printf("cannot open printer description file\n"); 388 return 0; 389 } else if (st == -1) { 390 printf("unknown printer %s\n", printer); 391 return 0; 392 } else if (st == -3) 393 fatal("potential reference loop detected in printcap file"); 394 return 1; 395 } 396 397 static void 398 enablepr(void) 399 { 400 struct stat stbuf; 401 402 getcaps(); 403 printf("%s:\n", printer); 404 405 /* 406 * Turn off the group execute bit of the lock file to enable queuing. 407 */ 408 seteuid(euid); 409 if (stat(line, &stbuf) >= 0) { 410 if (chmod(line, stbuf.st_mode & 0767) < 0) 411 printf("\tcannot enable queuing\n"); 412 else 413 printf("\tqueuing enabled\n"); 414 } 415 seteuid(uid); 416 } 417 418 /* 419 * Disable queuing. 420 */ 421 void 422 disable(int argc, char *argv[]) 423 { 424 int c; 425 char *cp1, *cp2; 426 char prbuf[100]; 427 428 if (argc == 1) { 429 printf("Usage: disable {all | printer ...}\n"); 430 return; 431 } 432 if (argc == 2 && !strcmp(argv[1], "all")) { 433 printer = prbuf; 434 while (cgetnext(&bp, printcapdb) > 0) { 435 cp1 = prbuf; 436 cp2 = bp; 437 while ((c = *cp2++) && c != '|' && c != ':' && 438 (cp1 - prbuf) < sizeof(prbuf)) 439 *cp1++ = c; 440 *cp1 = '\0'; 441 disablepr(); 442 } 443 return; 444 } 445 while (--argc) { 446 printer = *++argv; 447 if (!getcapdesc()) 448 continue; 449 disablepr(); 450 } 451 } 452 453 static void 454 disablepr(void) 455 { 456 int fd; 457 struct stat stbuf; 458 459 getcaps(); 460 printf("%s:\n", printer); 461 /* 462 * Turn on the group execute bit of the lock file to disable queuing. 463 */ 464 seteuid(euid); 465 if (stat(line, &stbuf) >= 0) { 466 if (chmod(line, (stbuf.st_mode & 0777) | 010) < 0) 467 printf("\tcannot disable queuing\n"); 468 else 469 printf("\tqueuing disabled\n"); 470 } else if (errno == ENOENT) { 471 if ((fd = open(line, O_WRONLY|O_CREAT, 0670)) < 0) 472 printf("\tcannot create lock file\n"); 473 else { 474 (void)close(fd); 475 printf("\tqueuing disabled\n"); 476 } 477 } else 478 printf("\tcannot stat lock file\n"); 479 seteuid(uid); 480 } 481 482 /* 483 * Disable queuing and printing and put a message into the status file 484 * (reason for being down). 485 */ 486 void 487 down(int argc, char *argv[]) 488 { 489 int c; 490 char *cp1, *cp2; 491 char prbuf[100]; 492 493 if (argc == 1) { 494 printf("Usage: down {all | printer} [message ...]\n"); 495 return; 496 } 497 if (!strcmp(argv[1], "all")) { 498 printer = prbuf; 499 while (cgetnext(&bp, printcapdb) > 0) { 500 cp1 = prbuf; 501 cp2 = bp; 502 while ((c = *cp2++) && c != '|' && c != ':' && 503 (cp1 - prbuf) < sizeof(prbuf)) 504 *cp1++ = c; 505 *cp1 = '\0'; 506 putmsg(argc - 2, argv + 2); 507 } 508 return; 509 } 510 printer = argv[1]; 511 if (!getcapdesc()) 512 return; 513 putmsg(argc - 2, argv + 2); 514 } 515 516 static void 517 getcaps(void) 518 { 519 char *cp; 520 SD = cgetstr(bp, "sd", &cp) == -1 ? _PATH_DEFSPOOL : cp; 521 LO = cgetstr(bp, "lo", &cp) == -1 ? DEFLOCK : cp; 522 ST = cgetstr(bp, "st", &cp) == -1 ? DEFSTAT : cp; 523 (void)snprintf(line, sizeof(line), "%s/%s", SD, LO); 524 } 525 526 static void 527 putmsg(int argc, char **argv) 528 { 529 int fd; 530 char *cp1, *cp2; 531 char buf[1024]; 532 struct stat stbuf; 533 534 printf("%s:\n", printer); 535 /* 536 * Turn on the group execute bit of the lock file to disable queuing and 537 * turn on the owner execute bit of the lock file to disable printing. 538 */ 539 seteuid(euid); 540 if (stat(line, &stbuf) >= 0) { 541 if (chmod(line, (stbuf.st_mode & 0777) | 0110) < 0) 542 printf("\tcannot disable queuing\n"); 543 else 544 printf("\tprinter and queuing disabled\n"); 545 } else if (errno == ENOENT) { 546 if ((fd = open(line, O_WRONLY|O_CREAT, 0770)) < 0) 547 printf("\tcannot create lock file\n"); 548 else { 549 (void)close(fd); 550 printf("\tprinter and queuing disabled\n"); 551 } 552 seteuid(uid); 553 return; 554 } else 555 printf("\tcannot stat lock file\n"); 556 /* 557 * Write the message into the status file. 558 */ 559 (void)snprintf(line, sizeof(line), "%s/%s", SD, ST); 560 fd = open(line, O_WRONLY|O_CREAT, 0664); 561 if (fd < 0 || flock(fd, LOCK_EX) < 0) { 562 printf("\tcannot create status file\n"); 563 seteuid(uid); 564 return; 565 } 566 seteuid(uid); 567 (void)ftruncate(fd, 0); 568 if (argc <= 0) { 569 (void)write(fd, "\n", 1); 570 (void)close(fd); 571 return; 572 } 573 cp1 = buf; 574 while (--argc >= 0) { 575 cp2 = *argv++; 576 while ((cp1 - buf) < sizeof(buf) && (*cp1++ = *cp2++)) 577 ; 578 cp1[-1] = ' '; 579 } 580 cp1[-1] = '\n'; 581 *cp1 = '\0'; 582 (void)write(fd, buf, strlen(buf)); 583 (void)close(fd); 584 } 585 586 /* 587 * Exit lpc 588 */ 589 void 590 quit(int argc, char *argv[]) 591 { 592 exit(0); 593 } 594 595 /* 596 * Kill and restart the daemon. 597 */ 598 void 599 restart(int argc, char *argv[]) 600 { 601 int c; 602 char *cp1, *cp2; 603 char prbuf[100]; 604 605 if (argc == 1) { 606 printf("Usage: restart {all | printer ...}\n"); 607 return; 608 } 609 if (argc == 2 && !strcmp(argv[1], "all")) { 610 printer = prbuf; 611 while (cgetnext(&bp, printcapdb) > 0) { 612 cp1 = prbuf; 613 cp2 = bp; 614 while ((c = *cp2++) && c != '|' && c != ':' && 615 (cp1 - prbuf) < sizeof(prbuf)) 616 *cp1++ = c; 617 *cp1 = '\0'; 618 abortpr(0); 619 startpr(0); 620 } 621 return; 622 } 623 while (--argc) { 624 printer = *++argv; 625 if (!getcapdesc()) 626 continue; 627 abortpr(0); 628 startpr(0); 629 } 630 } 631 632 /* 633 * Enable printing on the specified printer and startup the daemon. 634 */ 635 void 636 startcmd(int argc, char *argv[]) 637 { 638 int c; 639 char *cp1, *cp2; 640 char prbuf[100]; 641 642 if (argc == 1) { 643 printf("Usage: start {all | printer ...}\n"); 644 return; 645 } 646 if (argc == 2 && !strcmp(argv[1], "all")) { 647 printer = prbuf; 648 while (cgetnext(&bp, printcapdb) > 0) { 649 cp1 = prbuf; 650 cp2 = bp; 651 while ((c = *cp2++) && c != '|' && c != ':' && 652 (cp1 - prbuf) < sizeof(prbuf)) 653 *cp1++ = c; 654 *cp1 = '\0'; 655 startpr(1); 656 } 657 return; 658 } 659 while (--argc) { 660 printer = *++argv; 661 if (!getcapdesc()) 662 continue; 663 startpr(1); 664 } 665 } 666 667 static void 668 startpr(int ena) 669 { 670 struct stat stbuf; 671 672 getcaps(); 673 printf("%s:\n", printer); 674 675 /* 676 * Turn off the owner execute bit of the lock file to enable printing. 677 */ 678 seteuid(euid); 679 if (ena && stat(line, &stbuf) >= 0) { 680 if (chmod(line, stbuf.st_mode & (ena == 2 ? 0666 : 0677)) < 0) 681 printf("\tcannot enable printing\n"); 682 else 683 printf("\tprinting enabled\n"); 684 } 685 if (!startdaemon(printer)) 686 printf("\tcouldn't start daemon\n"); 687 else 688 printf("\tdaemon started\n"); 689 seteuid(uid); 690 } 691 692 /* 693 * Print the status of each queue listed or all the queues. 694 */ 695 void 696 status(int argc, char *argv[]) 697 { 698 int c; 699 char *cp1, *cp2; 700 char prbuf[100]; 701 702 if (argc == 1 || (argc == 2 && strcmp(argv[1], "all") == 0)) { 703 printer = prbuf; 704 while (cgetnext(&bp, printcapdb) > 0) { 705 cp1 = prbuf; 706 cp2 = bp; 707 while ((c = *cp2++) && c != '|' && c != ':' && 708 (cp1 - prbuf) < sizeof(prbuf)) 709 *cp1++ = c; 710 *cp1 = '\0'; 711 prstat(); 712 } 713 return; 714 } 715 while (--argc) { 716 printer = *++argv; 717 if (!getcapdesc()) 718 continue; 719 prstat(); 720 } 721 } 722 723 /* 724 * Print the status of the printer queue. 725 */ 726 static void 727 prstat(void) 728 { 729 struct stat stbuf; 730 int fd, i; 731 struct dirent *dp; 732 DIR *dirp; 733 734 getcaps(); 735 printf("%s:\n", printer); 736 if (stat(line, &stbuf) >= 0) { 737 printf("\tqueuing is %s\n", 738 (stbuf.st_mode & 010) ? "disabled" : "enabled"); 739 printf("\tprinting is %s\n", 740 (stbuf.st_mode & 0100) ? "disabled" : "enabled"); 741 } else { 742 printf("\tqueuing is enabled\n"); 743 printf("\tprinting is enabled\n"); 744 } 745 if ((dirp = opendir(SD)) == NULL) { 746 printf("\tcannot examine spool directory\n"); 747 return; 748 } 749 i = 0; 750 while ((dp = readdir(dirp)) != NULL) { 751 if (*dp->d_name == 'c' && dp->d_name[1] == 'f') 752 i++; 753 } 754 closedir(dirp); 755 if (i == 0) 756 printf("\tno entries\n"); 757 else if (i == 1) 758 printf("\t1 entry in spool area\n"); 759 else 760 printf("\t%d entries in spool area\n", i); 761 fd = open(line, O_RDONLY); 762 if (fd < 0 || flock(fd, LOCK_SH|LOCK_NB) == 0) { 763 (void)close(fd); /* unlocks as well */ 764 printf("\tprinter idle\n"); 765 return; 766 } 767 (void)close(fd); 768 (void)snprintf(line, sizeof(line), "%s/%s", SD, ST); 769 fd = open(line, O_RDONLY); 770 if (fd >= 0) { 771 (void)flock(fd, LOCK_SH); 772 (void)fstat(fd, &stbuf); 773 if (stbuf.st_size > 0) { 774 putchar('\t'); 775 while ((i = read(fd, line, sizeof(line))) > 0) 776 (void)fwrite(line, 1, i, stdout); 777 } 778 (void)close(fd); /* unlocks as well */ 779 } 780 } 781 782 /* 783 * Stop the specified daemon after completing the current job and disable 784 * printing. 785 */ 786 void 787 stop(int argc, char *argv[]) 788 { 789 int c; 790 char *cp1, *cp2; 791 char prbuf[100]; 792 793 if (argc == 1) { 794 printf("Usage: stop {all | printer ...}\n"); 795 return; 796 } 797 if (argc == 2 && !strcmp(argv[1], "all")) { 798 printer = prbuf; 799 while (cgetnext(&bp, printcapdb) > 0) { 800 cp1 = prbuf; 801 cp2 = bp; 802 while ((c = *cp2++) && c != '|' && c != ':' && 803 (cp1 - prbuf) < sizeof(prbuf)) 804 *cp1++ = c; 805 *cp1 = '\0'; 806 stoppr(); 807 } 808 return; 809 } 810 while (--argc) { 811 printer = *++argv; 812 if (!getcapdesc()) 813 continue; 814 stoppr(); 815 } 816 } 817 818 static void 819 stoppr(void) 820 { 821 int fd; 822 struct stat stbuf; 823 824 getcaps(); 825 printf("%s:\n", printer); 826 827 /* 828 * Turn on the owner execute bit of the lock file to disable printing. 829 */ 830 seteuid(euid); 831 if (stat(line, &stbuf) >= 0) { 832 if (chmod(line, (stbuf.st_mode & 0777) | 0100) < 0) 833 printf("\tcannot disable printing\n"); 834 else { 835 upstat("printing disabled\n"); 836 printf("\tprinting disabled\n"); 837 } 838 } else if (errno == ENOENT) { 839 if ((fd = open(line, O_WRONLY|O_CREAT, 0760)) < 0) 840 printf("\tcannot create lock file\n"); 841 else { 842 (void)close(fd); 843 upstat("printing disabled\n"); 844 printf("\tprinting disabled\n"); 845 } 846 } else 847 printf("\tcannot stat lock file\n"); 848 seteuid(uid); 849 } 850 851 struct queue **queue; 852 int nitems; 853 time_t mtime; 854 855 /* 856 * Put the specified jobs at the top of printer queue. 857 */ 858 void 859 topq(int argc, char *argv[]) 860 { 861 int i; 862 struct stat stbuf; 863 int changed; 864 865 if (argc < 3) { 866 printf("Usage: topq printer [jobnum ...] [user ...]\n"); 867 return; 868 } 869 870 --argc; 871 printer = *++argv; 872 if (!getcapdesc()) 873 return; 874 875 getcaps(); 876 printf("%s:\n", printer); 877 878 seteuid(euid); 879 if (chdir(SD) < 0) { 880 printf("\tcannot chdir to %s\n", SD); 881 goto out; 882 } 883 seteuid(uid); 884 nitems = getq(&queue); 885 if (nitems == 0) 886 return; 887 changed = 0; 888 mtime = queue[0]->q_time; 889 for (i = argc; --i; ) { 890 if (doarg(argv[i]) == 0) { 891 printf("\tjob %s is not in the queue\n", argv[i]); 892 continue; 893 } else 894 changed++; 895 } 896 for (i = 0; i < nitems; i++) 897 free(queue[i]); 898 free(queue); 899 if (!changed) { 900 printf("\tqueue order unchanged\n"); 901 return; 902 } 903 /* 904 * Turn on the public execute bit of the lock file to 905 * get lpd to rebuild the queue after the current job. 906 */ 907 seteuid(euid); 908 if (changed && stat(LO, &stbuf) >= 0) 909 (void)chmod(LO, (stbuf.st_mode & 0777) | 01); 910 911 out: 912 seteuid(uid); 913 } 914 915 /* 916 * Reposition the job by changing the modification time of 917 * the control file. 918 */ 919 static int 920 touch(struct queue *q) 921 { 922 struct timeval tvp[2]; 923 int ret; 924 925 tvp[0].tv_sec = tvp[1].tv_sec = --mtime; 926 tvp[0].tv_usec = tvp[1].tv_usec = 0; 927 seteuid(euid); 928 ret = utimes(q->q_name, tvp); 929 seteuid(uid); 930 return (ret); 931 } 932 933 /* 934 * Checks if specified job name is in the printer's queue. 935 * Returns: negative (-1) if argument name is not in the queue. 936 */ 937 static int 938 doarg(const char *job) 939 { 940 struct queue **qq; 941 int jobnum, n; 942 char *cp; 943 const char *machine; 944 int cnt = 0; 945 FILE *fp; 946 947 /* 948 * Look for a job item consisting of system name, colon, number 949 * (example: ucbarpa:114) 950 */ 951 if ((cp = strchr(job, ':')) != NULL) { 952 machine = job; 953 *cp++ = '\0'; 954 job = cp; 955 } else 956 machine = NULL; 957 958 /* 959 * Check for job specified by number (example: 112 or 235ucbarpa). 960 */ 961 if (isdigit((unsigned char)*job)) { 962 jobnum = 0; 963 do 964 jobnum = jobnum * 10 + (*job++ - '0'); 965 while (isdigit((unsigned char)*job)); 966 for (qq = queue + nitems; --qq >= queue; ) { 967 n = 0; 968 for (cp = (*qq)->q_name+3; isdigit((unsigned char)*cp); ) 969 n = n * 10 + (*cp++ - '0'); 970 if (jobnum != n) 971 continue; 972 if (*job && strcmp(job, cp) != 0) 973 continue; 974 if (machine != NULL && strcmp(machine, cp) != 0) 975 continue; 976 if (touch(*qq) == 0) { 977 printf("\tmoved %s\n", (*qq)->q_name); 978 cnt++; 979 } 980 } 981 return(cnt); 982 } 983 /* 984 * Process item consisting of owner's name (example: henry). 985 */ 986 for (qq = queue + nitems; --qq >= queue; ) { 987 seteuid(euid); 988 fp = fopen((*qq)->q_name, "r"); 989 seteuid(uid); 990 if (fp == NULL) 991 continue; 992 while (getline(fp) > 0) 993 if (line[0] == 'P') 994 break; 995 (void)fclose(fp); 996 if (line[0] != 'P' || strcmp(job, line+1) != 0) 997 continue; 998 if (touch(*qq) == 0) { 999 printf("\tmoved %s\n", (*qq)->q_name); 1000 cnt++; 1001 } 1002 } 1003 return(cnt); 1004 } 1005 1006 /* 1007 * Enable everything and start printer (undo `down'). 1008 */ 1009 void 1010 up(int argc, char *argv[]) 1011 { 1012 int c; 1013 char *cp1, *cp2; 1014 char prbuf[100]; 1015 1016 if (argc == 1) { 1017 printf("Usage: up {all | printer ...}\n"); 1018 return; 1019 } 1020 if (argc == 2 && !strcmp(argv[1], "all")) { 1021 printer = prbuf; 1022 while (cgetnext(&bp, printcapdb) > 0) { 1023 cp1 = prbuf; 1024 cp2 = bp; 1025 while ((c = *cp2++) && c != '|' && c != ':' && 1026 (cp1 - prbuf) < sizeof(prbuf)) 1027 *cp1++ = c; 1028 *cp1 = '\0'; 1029 startpr(2); 1030 } 1031 return; 1032 } 1033 while (--argc) { 1034 printer = *++argv; 1035 if (!getcapdesc()) 1036 continue; 1037 startpr(2); 1038 } 1039 } 1040