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