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 strncpy(lp, cp, sizeof(line) - strlen(line) - 1); 333 line[sizeof(line) - 1] = '\0'; 334 unlinkf(line); 335 } 336 } else { 337 /* 338 * Must be a df with no cf (otherwise, it would have 339 * been skipped above) or a tf file (which can always 340 * be removed). 341 */ 342 strncpy(lp, cp, sizeof(line) - strlen(line) - 1); 343 line[sizeof(line) - 1] = '\0'; 344 unlinkf(line); 345 } 346 } while (++i < nitems); 347 } 348 349 static void 350 unlinkf(name) 351 char *name; 352 { 353 if (unlink(name) < 0) 354 printf("\tcannot remove %s\n", name); 355 else 356 printf("\tremoved %s\n", name); 357 } 358 359 /* 360 * Enable queuing to the printer (allow lpr's). 361 */ 362 void 363 enable(argc, argv) 364 int argc; 365 char *argv[]; 366 { 367 register int c, status; 368 register char *cp1, *cp2; 369 char prbuf[100]; 370 371 if (argc == 1) { 372 printf("Usage: enable {all | printer ...}\n"); 373 return; 374 } 375 if (argc == 2 && !strcmp(argv[1], "all")) { 376 printer = prbuf; 377 while (cgetnext(&bp, printcapdb) > 0) { 378 cp1 = prbuf; 379 cp2 = bp; 380 while ((c = *cp2++) && c != '|' && c != ':') 381 *cp1++ = c; 382 *cp1 = '\0'; 383 enablepr(); 384 } 385 return; 386 } 387 while (--argc) { 388 printer = *++argv; 389 if ((status = cgetent(&bp, printcapdb, printer)) == -2) { 390 printf("cannot open printer description file\n"); 391 continue; 392 } else if (status == -1) { 393 printf("unknown printer %s\n", printer); 394 continue; 395 } else if (status == -3) 396 fatal("potential reference loop detected in printcap file"); 397 398 enablepr(); 399 } 400 } 401 402 static void 403 enablepr() 404 { 405 struct stat stbuf; 406 407 if (cgetstr(bp, "sd", &SD) == -1) 408 SD = _PATH_DEFSPOOL; 409 if (cgetstr(bp, "lo", &LO) == -1) 410 LO = DEFLOCK; 411 (void) sprintf(line, "%s/%s", SD, LO); 412 printf("%s:\n", printer); 413 414 /* 415 * Turn off the group execute bit of the lock file to enable queuing. 416 */ 417 if (stat(line, &stbuf) >= 0) { 418 if (chmod(line, stbuf.st_mode & 0767) < 0) 419 printf("\tcannot enable queuing\n"); 420 else 421 printf("\tqueuing enabled\n"); 422 } 423 } 424 425 /* 426 * Disable queuing. 427 */ 428 void 429 disable(argc, argv) 430 int argc; 431 char *argv[]; 432 { 433 register int c, status; 434 register char *cp1, *cp2; 435 char prbuf[100]; 436 437 if (argc == 1) { 438 printf("Usage: disable {all | printer ...}\n"); 439 return; 440 } 441 if (argc == 2 && !strcmp(argv[1], "all")) { 442 printer = prbuf; 443 while (cgetnext(&bp, printcapdb) > 0) { 444 cp1 = prbuf; 445 cp2 = bp; 446 while ((c = *cp2++) && c != '|' && c != ':') 447 *cp1++ = c; 448 *cp1 = '\0'; 449 disablepr(); 450 } 451 return; 452 } 453 while (--argc) { 454 printer = *++argv; 455 if ((status = cgetent(&bp, printcapdb, printer)) == -2) { 456 printf("cannot open printer description file\n"); 457 continue; 458 } else if (status == -1) { 459 printf("unknown printer %s\n", printer); 460 continue; 461 } else if (status == -3) 462 fatal("potential reference loop detected in printcap file"); 463 464 disablepr(); 465 } 466 } 467 468 static void 469 disablepr() 470 { 471 register int fd; 472 struct stat stbuf; 473 474 if (cgetstr(bp, "sd", &SD) == -1) 475 SD = _PATH_DEFSPOOL; 476 if (cgetstr(bp, "lo", &LO) == -1) 477 LO = DEFLOCK; 478 (void) sprintf(line, "%s/%s", SD, LO); 479 printf("%s:\n", printer); 480 /* 481 * Turn on the group execute bit of the lock file to disable queuing. 482 */ 483 if (stat(line, &stbuf) >= 0) { 484 if (chmod(line, (stbuf.st_mode & 0777) | 010) < 0) 485 printf("\tcannot disable queuing\n"); 486 else 487 printf("\tqueuing disabled\n"); 488 } else if (errno == ENOENT) { 489 if ((fd = open(line, O_WRONLY|O_CREAT, 0670)) < 0) 490 printf("\tcannot create lock file\n"); 491 else { 492 (void) close(fd); 493 printf("\tqueuing disabled\n"); 494 } 495 return; 496 } else 497 printf("\tcannot stat lock file\n"); 498 } 499 500 /* 501 * Disable queuing and printing and put a message into the status file 502 * (reason for being down). 503 */ 504 void 505 down(argc, argv) 506 int argc; 507 char *argv[]; 508 { 509 register int c, status; 510 register char *cp1, *cp2; 511 char prbuf[100]; 512 513 if (argc == 1) { 514 printf("Usage: down {all | printer} [message ...]\n"); 515 return; 516 } 517 if (!strcmp(argv[1], "all")) { 518 printer = prbuf; 519 while (cgetnext(&bp, printcapdb) > 0) { 520 cp1 = prbuf; 521 cp2 = bp; 522 while ((c = *cp2++) && c != '|' && c != ':') 523 *cp1++ = c; 524 *cp1 = '\0'; 525 putmsg(argc - 2, argv + 2); 526 } 527 return; 528 } 529 printer = argv[1]; 530 if ((status = cgetent(&bp, printcapdb, printer)) == -2) { 531 printf("cannot open printer description file\n"); 532 return; 533 } else if (status == -1) { 534 printf("unknown printer %s\n", printer); 535 return; 536 } else if (status == -3) 537 fatal("potential reference loop detected in printcap file"); 538 539 putmsg(argc - 2, argv + 2); 540 } 541 542 static void 543 putmsg(argc, argv) 544 int argc; 545 char **argv; 546 { 547 register int fd; 548 register char *cp1, *cp2; 549 char buf[1024]; 550 struct stat stbuf; 551 552 if (cgetstr(bp, "sd", &SD) == -1) 553 SD = _PATH_DEFSPOOL; 554 if (cgetstr(bp, "lo", &LO) == -1) 555 LO = DEFLOCK; 556 if (cgetstr(bp, "st", &ST) == -1) 557 ST = DEFSTAT; 558 printf("%s:\n", printer); 559 /* 560 * Turn on the group execute bit of the lock file to disable queuing and 561 * turn on the owner execute bit of the lock file to disable printing. 562 */ 563 (void) sprintf(line, "%s/%s", SD, LO); 564 if (stat(line, &stbuf) >= 0) { 565 if (chmod(line, (stbuf.st_mode & 0777) | 0110) < 0) 566 printf("\tcannot disable queuing\n"); 567 else 568 printf("\tprinter and queuing disabled\n"); 569 } else if (errno == ENOENT) { 570 if ((fd = open(line, O_WRONLY|O_CREAT, 0770)) < 0) 571 printf("\tcannot create lock file\n"); 572 else { 573 (void) close(fd); 574 printf("\tprinter and queuing disabled\n"); 575 } 576 return; 577 } else 578 printf("\tcannot stat lock file\n"); 579 /* 580 * Write the message into the status file. 581 */ 582 (void) sprintf(line, "%s/%s", SD, ST); 583 fd = open(line, O_WRONLY|O_CREAT, 0664); 584 if (fd < 0 || flock(fd, LOCK_EX) < 0) { 585 printf("\tcannot create status file\n"); 586 return; 587 } 588 (void) ftruncate(fd, 0); 589 if (argc <= 0) { 590 (void) write(fd, "\n", 1); 591 (void) close(fd); 592 return; 593 } 594 cp1 = buf; 595 while (--argc >= 0) { 596 cp2 = *argv++; 597 while ((*cp1++ = *cp2++)) 598 ; 599 cp1[-1] = ' '; 600 } 601 cp1[-1] = '\n'; 602 *cp1 = '\0'; 603 (void) write(fd, buf, strlen(buf)); 604 (void) close(fd); 605 } 606 607 /* 608 * Exit lpc 609 */ 610 void 611 quit(argc, argv) 612 int argc; 613 char *argv[]; 614 { 615 exit(0); 616 } 617 618 /* 619 * Kill and restart the daemon. 620 */ 621 void 622 restart(argc, argv) 623 int argc; 624 char *argv[]; 625 { 626 register int c, status; 627 register char *cp1, *cp2; 628 char prbuf[100]; 629 630 if (argc == 1) { 631 printf("Usage: restart {all | printer ...}\n"); 632 return; 633 } 634 if (argc == 2 && !strcmp(argv[1], "all")) { 635 printer = prbuf; 636 while (cgetnext(&bp, printcapdb) > 0) { 637 cp1 = prbuf; 638 cp2 = bp; 639 while ((c = *cp2++) && c != '|' && c != ':') 640 *cp1++ = c; 641 *cp1 = '\0'; 642 abortpr(0); 643 startpr(0); 644 } 645 return; 646 } 647 while (--argc) { 648 printer = *++argv; 649 if ((status = cgetent(&bp, printcapdb, printer)) == -2) { 650 printf("cannot open printer description file\n"); 651 continue; 652 } else if (status == -1) { 653 printf("unknown printer %s\n", printer); 654 continue; 655 } else if (status == -3) 656 fatal("potential reference loop detected in printcap file"); 657 658 abortpr(0); 659 startpr(0); 660 } 661 } 662 663 /* 664 * Enable printing on the specified printer and startup the daemon. 665 */ 666 void 667 startcmd(argc, argv) 668 int argc; 669 char *argv[]; 670 { 671 register int c, status; 672 register char *cp1, *cp2; 673 char prbuf[100]; 674 675 if (argc == 1) { 676 printf("Usage: start {all | printer ...}\n"); 677 return; 678 } 679 if (argc == 2 && !strcmp(argv[1], "all")) { 680 printer = prbuf; 681 while (cgetnext(&bp, printcapdb) > 0) { 682 cp1 = prbuf; 683 cp2 = bp; 684 while ((c = *cp2++) && c != '|' && c != ':') 685 *cp1++ = c; 686 *cp1 = '\0'; 687 startpr(1); 688 } 689 return; 690 } 691 while (--argc) { 692 printer = *++argv; 693 if ((status = cgetent(&bp, printcapdb, printer)) == -2) { 694 printf("cannot open printer description file\n"); 695 continue; 696 } else if (status == -1) { 697 printf("unknown printer %s\n", printer); 698 continue; 699 } else if (status == -3) 700 fatal("potential reference loop detected in printcap file"); 701 702 startpr(1); 703 } 704 } 705 706 static void 707 startpr(enable) 708 int enable; 709 { 710 struct stat stbuf; 711 712 if (cgetstr(bp, "sd", &SD) == -1) 713 SD = _PATH_DEFSPOOL; 714 if (cgetstr(bp, "lo", &LO) == -1) 715 LO = DEFLOCK; 716 (void) sprintf(line, "%s/%s", SD, LO); 717 printf("%s:\n", printer); 718 719 /* 720 * Turn off the owner execute bit of the lock file to enable printing. 721 */ 722 if (enable && stat(line, &stbuf) >= 0) { 723 if (chmod(line, stbuf.st_mode & (enable==2 ? 0666 : 0677)) < 0) 724 printf("\tcannot enable printing\n"); 725 else 726 printf("\tprinting enabled\n"); 727 } 728 if (!startdaemon(printer)) 729 printf("\tcouldn't start daemon\n"); 730 else 731 printf("\tdaemon started\n"); 732 } 733 734 /* 735 * Print the status of each queue listed or all the queues. 736 */ 737 void 738 status(argc, argv) 739 int argc; 740 char *argv[]; 741 { 742 register int c, status; 743 register char *cp1, *cp2; 744 char prbuf[100]; 745 746 if (argc == 1) { 747 printer = prbuf; 748 while (cgetnext(&bp, printcapdb) > 0) { 749 cp1 = prbuf; 750 cp2 = bp; 751 while ((c = *cp2++) && c != '|' && c != ':') 752 *cp1++ = c; 753 *cp1 = '\0'; 754 prstat(); 755 } 756 return; 757 } 758 while (--argc) { 759 printer = *++argv; 760 if ((status = cgetent(&bp, printcapdb, printer)) == -2) { 761 printf("cannot open printer description file\n"); 762 continue; 763 } else if (status == -1) { 764 printf("unknown printer %s\n", printer); 765 continue; 766 } else if (status == -3) 767 fatal("potential reference loop detected in printcap file"); 768 769 prstat(); 770 } 771 } 772 773 /* 774 * Print the status of the printer queue. 775 */ 776 static void 777 prstat() 778 { 779 struct stat stbuf; 780 register int fd, i; 781 register struct dirent *dp; 782 DIR *dirp; 783 784 if (cgetstr(bp, "sd", &SD) == -1) 785 SD = _PATH_DEFSPOOL; 786 if (cgetstr(bp, "lo", &LO) == -1) 787 LO = DEFLOCK; 788 if (cgetstr(bp, "st", &ST) == -1) 789 ST = DEFSTAT; 790 printf("%s:\n", printer); 791 (void) sprintf(line, "%s/%s", SD, LO); 792 if (stat(line, &stbuf) >= 0) { 793 printf("\tqueuing is %s\n", 794 (stbuf.st_mode & 010) ? "disabled" : "enabled"); 795 printf("\tprinting is %s\n", 796 (stbuf.st_mode & 0100) ? "disabled" : "enabled"); 797 } else { 798 printf("\tqueuing is enabled\n"); 799 printf("\tprinting is enabled\n"); 800 } 801 if ((dirp = opendir(SD)) == NULL) { 802 printf("\tcannot examine spool directory\n"); 803 return; 804 } 805 i = 0; 806 while ((dp = readdir(dirp)) != NULL) { 807 if (*dp->d_name == 'c' && dp->d_name[1] == 'f') 808 i++; 809 } 810 closedir(dirp); 811 if (i == 0) 812 printf("\tno entries\n"); 813 else if (i == 1) 814 printf("\t1 entry in spool area\n"); 815 else 816 printf("\t%d entries in spool area\n", i); 817 fd = open(line, O_RDONLY); 818 if (fd < 0 || flock(fd, LOCK_SH|LOCK_NB) == 0) { 819 (void) close(fd); /* unlocks as well */ 820 printf("\tprinter idle\n"); 821 return; 822 } 823 (void) close(fd); 824 putchar('\t'); 825 (void) sprintf(line, "%s/%s", SD, ST); 826 fd = open(line, O_RDONLY); 827 if (fd >= 0) { 828 (void) flock(fd, LOCK_SH); 829 while ((i = read(fd, line, sizeof(line))) > 0) 830 (void) fwrite(line, 1, i, stdout); 831 (void) close(fd); /* unlocks as well */ 832 } 833 } 834 835 /* 836 * Stop the specified daemon after completing the current job and disable 837 * printing. 838 */ 839 void 840 stop(argc, argv) 841 int argc; 842 char *argv[]; 843 { 844 register int c, status; 845 register char *cp1, *cp2; 846 char prbuf[100]; 847 848 if (argc == 1) { 849 printf("Usage: stop {all | printer ...}\n"); 850 return; 851 } 852 if (argc == 2 && !strcmp(argv[1], "all")) { 853 printer = prbuf; 854 while (cgetnext(&bp, printcapdb) > 0) { 855 cp1 = prbuf; 856 cp2 = bp; 857 while ((c = *cp2++) && c != '|' && c != ':') 858 *cp1++ = c; 859 *cp1 = '\0'; 860 stoppr(); 861 } 862 return; 863 } 864 while (--argc) { 865 printer = *++argv; 866 if ((status = cgetent(&bp, printcapdb, printer)) == -2) { 867 printf("cannot open printer description file\n"); 868 continue; 869 } else if (status == -1) { 870 printf("unknown printer %s\n", printer); 871 continue; 872 } else if (status == -3) 873 fatal("potential reference loop detected in printcap file"); 874 875 stoppr(); 876 } 877 } 878 879 static void 880 stoppr() 881 { 882 register int fd; 883 struct stat stbuf; 884 885 if (cgetstr(bp, "sd", &SD) == -1) 886 SD = _PATH_DEFSPOOL; 887 if (cgetstr(bp, "lo", &LO) == -1) 888 LO = DEFLOCK; 889 (void) sprintf(line, "%s/%s", SD, LO); 890 printf("%s:\n", printer); 891 892 /* 893 * Turn on the owner execute bit of the lock file to disable printing. 894 */ 895 if (stat(line, &stbuf) >= 0) { 896 if (chmod(line, (stbuf.st_mode & 0777) | 0100) < 0) 897 printf("\tcannot disable printing\n"); 898 else { 899 upstat("printing disabled\n"); 900 printf("\tprinting disabled\n"); 901 } 902 } else if (errno == ENOENT) { 903 if ((fd = open(line, O_WRONLY|O_CREAT, 0760)) < 0) 904 printf("\tcannot create lock file\n"); 905 else { 906 (void) close(fd); 907 upstat("printing disabled\n"); 908 printf("\tprinting disabled\n"); 909 } 910 } else 911 printf("\tcannot stat lock file\n"); 912 } 913 914 struct queue **queue; 915 int nitems; 916 time_t mtime; 917 918 /* 919 * Put the specified jobs at the top of printer queue. 920 */ 921 void 922 topq(argc, argv) 923 int argc; 924 char *argv[]; 925 { 926 register int i; 927 struct stat stbuf; 928 int status, changed; 929 930 if (argc < 3) { 931 printf("Usage: topq printer [jobnum ...] [user ...]\n"); 932 return; 933 } 934 935 --argc; 936 printer = *++argv; 937 status = cgetent(&bp, printcapdb, printer); 938 if (status == -2) { 939 printf("cannot open printer description file\n"); 940 return; 941 } else if (status == -1) { 942 printf("%s: unknown printer\n", printer); 943 return; 944 } else if (status == -3) 945 fatal("potential reference loop detected in printcap file"); 946 947 if (cgetstr(bp, "sd", &SD) == -1) 948 SD = _PATH_DEFSPOOL; 949 if (cgetstr(bp, "lo", &LO) == -1) 950 LO = DEFLOCK; 951 printf("%s:\n", printer); 952 953 if (chdir(SD) < 0) { 954 printf("\tcannot chdir to %s\n", SD); 955 return; 956 } 957 nitems = getq(&queue); 958 if (nitems == 0) 959 return; 960 changed = 0; 961 mtime = queue[0]->q_time; 962 for (i = argc; --i; ) { 963 if (doarg(argv[i]) == 0) { 964 printf("\tjob %s is not in the queue\n", argv[i]); 965 continue; 966 } else 967 changed++; 968 } 969 for (i = 0; i < nitems; i++) 970 free(queue[i]); 971 free(queue); 972 if (!changed) { 973 printf("\tqueue order unchanged\n"); 974 return; 975 } 976 /* 977 * Turn on the public execute bit of the lock file to 978 * get lpd to rebuild the queue after the current job. 979 */ 980 if (changed && stat(LO, &stbuf) >= 0) 981 (void) chmod(LO, (stbuf.st_mode & 0777) | 01); 982 } 983 984 /* 985 * Reposition the job by changing the modification time of 986 * the control file. 987 */ 988 static int 989 touch(q) 990 struct queue *q; 991 { 992 struct timeval tvp[2]; 993 994 tvp[0].tv_sec = tvp[1].tv_sec = --mtime; 995 tvp[0].tv_usec = tvp[1].tv_usec = 0; 996 return(utimes(q->q_name, tvp)); 997 } 998 999 /* 1000 * Checks if specified job name is in the printer's queue. 1001 * Returns: negative (-1) if argument name is not in the queue. 1002 */ 1003 static int 1004 doarg(job) 1005 char *job; 1006 { 1007 register struct queue **qq; 1008 register int jobnum, n; 1009 register char *cp, *machine; 1010 int cnt = 0; 1011 FILE *fp; 1012 1013 /* 1014 * Look for a job item consisting of system name, colon, number 1015 * (example: ucbarpa:114) 1016 */ 1017 if ((cp = index(job, ':')) != NULL) { 1018 machine = job; 1019 *cp++ = '\0'; 1020 job = cp; 1021 } else 1022 machine = NULL; 1023 1024 /* 1025 * Check for job specified by number (example: 112 or 235ucbarpa). 1026 */ 1027 if (isdigit(*job)) { 1028 jobnum = 0; 1029 do 1030 jobnum = jobnum * 10 + (*job++ - '0'); 1031 while (isdigit(*job)); 1032 for (qq = queue + nitems; --qq >= queue; ) { 1033 n = 0; 1034 for (cp = (*qq)->q_name+3; isdigit(*cp); ) 1035 n = n * 10 + (*cp++ - '0'); 1036 if (jobnum != n) 1037 continue; 1038 if (*job && strcmp(job, cp) != 0) 1039 continue; 1040 if (machine != NULL && strcmp(machine, cp) != 0) 1041 continue; 1042 if (touch(*qq) == 0) { 1043 printf("\tmoved %s\n", (*qq)->q_name); 1044 cnt++; 1045 } 1046 } 1047 return(cnt); 1048 } 1049 /* 1050 * Process item consisting of owner's name (example: henry). 1051 */ 1052 for (qq = queue + nitems; --qq >= queue; ) { 1053 if ((fp = fopen((*qq)->q_name, "r")) == NULL) 1054 continue; 1055 while (getline(fp) > 0) 1056 if (line[0] == 'P') 1057 break; 1058 (void) fclose(fp); 1059 if (line[0] != 'P' || strcmp(job, line+1) != 0) 1060 continue; 1061 if (touch(*qq) == 0) { 1062 printf("\tmoved %s\n", (*qq)->q_name); 1063 cnt++; 1064 } 1065 } 1066 return(cnt); 1067 } 1068 1069 /* 1070 * Enable everything and start printer (undo `down'). 1071 */ 1072 void 1073 up(argc, argv) 1074 int argc; 1075 char *argv[]; 1076 { 1077 register int c, status; 1078 register char *cp1, *cp2; 1079 char prbuf[100]; 1080 1081 if (argc == 1) { 1082 printf("Usage: up {all | printer ...}\n"); 1083 return; 1084 } 1085 if (argc == 2 && !strcmp(argv[1], "all")) { 1086 printer = prbuf; 1087 while (cgetnext(&bp, printcapdb) > 0) { 1088 cp1 = prbuf; 1089 cp2 = bp; 1090 while ((c = *cp2++) && c != '|' && c != ':') 1091 *cp1++ = c; 1092 *cp1 = '\0'; 1093 startpr(2); 1094 } 1095 return; 1096 } 1097 while (--argc) { 1098 printer = *++argv; 1099 if ((status = cgetent(&bp, printcapdb, printer)) == -2) { 1100 printf("cannot open printer description file\n"); 1101 continue; 1102 } else if (status == -1) { 1103 printf("unknown printer %s\n", printer); 1104 continue; 1105 } else if (status == -3) 1106 fatal("potential reference loop detected in printcap file"); 1107 1108 startpr(2); 1109 } 1110 } 1111