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