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