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