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