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