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