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