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