1 /* $NetBSD: cmds.c,v 1.15 2003/05/17 20:46:43 itojun 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.15 2003/05/17 20:46:43 itojun 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, *ep; 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 ep = line + sizeof(line); 314 for (lp = line, cp = SD; (lp - line) < sizeof(line) && 315 (*lp++ = *cp++) != '\0'; ) 316 ; 317 lp[-1] = '/'; 318 319 seteuid(euid); 320 nitems = scandir(SD, &queue, doselect, sortq); 321 seteuid(uid); 322 if (nitems < 0) { 323 printf("\tcannot examine spool directory\n"); 324 return; 325 } 326 if (nitems == 0) 327 return; 328 i = 0; 329 do { 330 cp = queue[i]->d_name; 331 if (*cp == 'c') { 332 n = 0; 333 while (i + 1 < nitems) { 334 cp1 = queue[i + 1]->d_name; 335 if (*cp1 != 'd' || strcmp(cp + 3, cp1 + 3)) 336 break; 337 i++; 338 n++; 339 } 340 if (n == 0) { 341 strlcpy(lp, cp, ep - lp); 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 strlcpy(lp, cp, ep - lp); 351 unlinkf(line); 352 } 353 } while (++i < nitems); 354 } 355 356 static void 357 unlinkf(char *name) 358 { 359 seteuid(euid); 360 if (unlink(name) < 0) 361 printf("\tcannot remove %s\n", name); 362 else 363 printf("\tremoved %s\n", name); 364 seteuid(uid); 365 } 366 367 /* 368 * Enable queuing to the printer (allow lpr's). 369 */ 370 void 371 enable(int argc, char *argv[]) 372 { 373 int c, status; 374 char *cp1, *cp2; 375 char prbuf[100]; 376 377 if (argc == 1) { 378 printf("Usage: enable {all | printer ...}\n"); 379 return; 380 } 381 if (argc == 2 && !strcmp(argv[1], "all")) { 382 printer = prbuf; 383 while (cgetnext(&bp, printcapdb) > 0) { 384 cp1 = prbuf; 385 cp2 = bp; 386 while ((c = *cp2++) && c != '|' && c != ':' && 387 (cp1 - prbuf) < sizeof(prbuf)) 388 *cp1++ = c; 389 *cp1 = '\0'; 390 enablepr(); 391 } 392 return; 393 } 394 while (--argc) { 395 printer = *++argv; 396 if ((status = cgetent(&bp, printcapdb, printer)) == -2) { 397 printf("cannot open printer description file\n"); 398 continue; 399 } else if (status == -1) { 400 printf("unknown printer %s\n", printer); 401 continue; 402 } else if (status == -3) 403 fatal("potential reference loop detected in printcap file"); 404 405 enablepr(); 406 } 407 } 408 409 static void 410 enablepr(void) 411 { 412 struct stat stbuf; 413 414 if (cgetstr(bp, "sd", &SD) == -1) 415 SD = _PATH_DEFSPOOL; 416 if (cgetstr(bp, "lo", &LO) == -1) 417 LO = DEFLOCK; 418 (void)snprintf(line, sizeof(line), "%s/%s", SD, LO); 419 printf("%s:\n", printer); 420 421 /* 422 * Turn off the group execute bit of the lock file to enable queuing. 423 */ 424 seteuid(euid); 425 if (stat(line, &stbuf) >= 0) { 426 if (chmod(line, stbuf.st_mode & 0767) < 0) 427 printf("\tcannot enable queuing\n"); 428 else 429 printf("\tqueuing enabled\n"); 430 } 431 seteuid(uid); 432 } 433 434 /* 435 * Disable queuing. 436 */ 437 void 438 disable(int argc, char *argv[]) 439 { 440 int c, status; 441 char *cp1, *cp2; 442 char prbuf[100]; 443 444 if (argc == 1) { 445 printf("Usage: disable {all | printer ...}\n"); 446 return; 447 } 448 if (argc == 2 && !strcmp(argv[1], "all")) { 449 printer = prbuf; 450 while (cgetnext(&bp, printcapdb) > 0) { 451 cp1 = prbuf; 452 cp2 = bp; 453 while ((c = *cp2++) && c != '|' && c != ':' && 454 (cp1 - prbuf) < sizeof(prbuf)) 455 *cp1++ = c; 456 *cp1 = '\0'; 457 disablepr(); 458 } 459 return; 460 } 461 while (--argc) { 462 printer = *++argv; 463 if ((status = cgetent(&bp, printcapdb, printer)) == -2) { 464 printf("cannot open printer description file\n"); 465 continue; 466 } else if (status == -1) { 467 printf("unknown printer %s\n", printer); 468 continue; 469 } else if (status == -3) 470 fatal("potential reference loop detected in printcap file"); 471 472 disablepr(); 473 } 474 } 475 476 static void 477 disablepr(void) 478 { 479 int fd; 480 struct stat stbuf; 481 482 if (cgetstr(bp, "sd", &SD) == -1) 483 SD = _PATH_DEFSPOOL; 484 if (cgetstr(bp, "lo", &LO) == -1) 485 LO = DEFLOCK; 486 (void)snprintf(line, sizeof(line), "%s/%s", SD, LO); 487 printf("%s:\n", printer); 488 /* 489 * Turn on the group execute bit of the lock file to disable queuing. 490 */ 491 seteuid(euid); 492 if (stat(line, &stbuf) >= 0) { 493 if (chmod(line, (stbuf.st_mode & 0777) | 010) < 0) 494 printf("\tcannot disable queuing\n"); 495 else 496 printf("\tqueuing disabled\n"); 497 } else if (errno == ENOENT) { 498 if ((fd = open(line, O_WRONLY|O_CREAT, 0670)) < 0) 499 printf("\tcannot create lock file\n"); 500 else { 501 (void)close(fd); 502 printf("\tqueuing disabled\n"); 503 } 504 } else 505 printf("\tcannot stat lock file\n"); 506 seteuid(uid); 507 } 508 509 /* 510 * Disable queuing and printing and put a message into the status file 511 * (reason for being down). 512 */ 513 void 514 down(int argc, char *argv[]) 515 { 516 int c, status; 517 char *cp1, *cp2; 518 char prbuf[100]; 519 520 if (argc == 1) { 521 printf("Usage: down {all | printer} [message ...]\n"); 522 return; 523 } 524 if (!strcmp(argv[1], "all")) { 525 printer = prbuf; 526 while (cgetnext(&bp, printcapdb) > 0) { 527 cp1 = prbuf; 528 cp2 = bp; 529 while ((c = *cp2++) && c != '|' && c != ':' && 530 (cp1 - prbuf) < sizeof(prbuf)) 531 *cp1++ = c; 532 *cp1 = '\0'; 533 putmsg(argc - 2, argv + 2); 534 } 535 return; 536 } 537 printer = argv[1]; 538 if ((status = cgetent(&bp, printcapdb, printer)) == -2) { 539 printf("cannot open printer description file\n"); 540 return; 541 } else if (status == -1) { 542 printf("unknown printer %s\n", printer); 543 return; 544 } else if (status == -3) 545 fatal("potential reference loop detected in printcap file"); 546 547 putmsg(argc - 2, argv + 2); 548 } 549 550 static void 551 putmsg(int argc, char **argv) 552 { 553 int fd; 554 char *cp1, *cp2; 555 char buf[1024]; 556 struct stat stbuf; 557 558 if (cgetstr(bp, "sd", &SD) == -1) 559 SD = _PATH_DEFSPOOL; 560 if (cgetstr(bp, "lo", &LO) == -1) 561 LO = DEFLOCK; 562 if (cgetstr(bp, "st", &ST) == -1) 563 ST = DEFSTAT; 564 printf("%s:\n", printer); 565 /* 566 * Turn on the group execute bit of the lock file to disable queuing and 567 * turn on the owner execute bit of the lock file to disable printing. 568 */ 569 (void)snprintf(line, sizeof(line), "%s/%s", SD, LO); 570 seteuid(euid); 571 if (stat(line, &stbuf) >= 0) { 572 if (chmod(line, (stbuf.st_mode & 0777) | 0110) < 0) 573 printf("\tcannot disable queuing\n"); 574 else 575 printf("\tprinter and queuing disabled\n"); 576 } else if (errno == ENOENT) { 577 if ((fd = open(line, O_WRONLY|O_CREAT, 0770)) < 0) 578 printf("\tcannot create lock file\n"); 579 else { 580 (void)close(fd); 581 printf("\tprinter and queuing disabled\n"); 582 } 583 seteuid(uid); 584 return; 585 } else 586 printf("\tcannot stat lock file\n"); 587 /* 588 * Write the message into the status file. 589 */ 590 (void)snprintf(line, sizeof(line), "%s/%s", SD, ST); 591 fd = open(line, O_WRONLY|O_CREAT, 0664); 592 if (fd < 0 || flock(fd, LOCK_EX) < 0) { 593 printf("\tcannot create status file\n"); 594 seteuid(uid); 595 return; 596 } 597 seteuid(uid); 598 (void)ftruncate(fd, 0); 599 if (argc <= 0) { 600 (void)write(fd, "\n", 1); 601 (void)close(fd); 602 return; 603 } 604 cp1 = buf; 605 while (--argc >= 0) { 606 cp2 = *argv++; 607 while ((cp1 - buf) < sizeof(buf) && (*cp1++ = *cp2++)) 608 ; 609 cp1[-1] = ' '; 610 } 611 cp1[-1] = '\n'; 612 *cp1 = '\0'; 613 (void)write(fd, buf, strlen(buf)); 614 (void)close(fd); 615 } 616 617 /* 618 * Exit lpc 619 */ 620 void 621 quit(int argc, char *argv[]) 622 { 623 exit(0); 624 } 625 626 /* 627 * Kill and restart the daemon. 628 */ 629 void 630 restart(int argc, char *argv[]) 631 { 632 int c, status; 633 char *cp1, *cp2; 634 char prbuf[100]; 635 636 if (argc == 1) { 637 printf("Usage: restart {all | printer ...}\n"); 638 return; 639 } 640 if (argc == 2 && !strcmp(argv[1], "all")) { 641 printer = prbuf; 642 while (cgetnext(&bp, printcapdb) > 0) { 643 cp1 = prbuf; 644 cp2 = bp; 645 while ((c = *cp2++) && c != '|' && c != ':' && 646 (cp1 - prbuf) < sizeof(prbuf)) 647 *cp1++ = c; 648 *cp1 = '\0'; 649 abortpr(0); 650 startpr(0); 651 } 652 return; 653 } 654 while (--argc) { 655 printer = *++argv; 656 if ((status = cgetent(&bp, printcapdb, printer)) == -2) { 657 printf("cannot open printer description file\n"); 658 continue; 659 } else if (status == -1) { 660 printf("unknown printer %s\n", printer); 661 continue; 662 } else if (status == -3) 663 fatal("potential reference loop detected in printcap file"); 664 665 abortpr(0); 666 startpr(0); 667 } 668 } 669 670 /* 671 * Enable printing on the specified printer and startup the daemon. 672 */ 673 void 674 startcmd(int argc, char *argv[]) 675 { 676 int c, status; 677 char *cp1, *cp2; 678 char prbuf[100]; 679 680 if (argc == 1) { 681 printf("Usage: start {all | printer ...}\n"); 682 return; 683 } 684 if (argc == 2 && !strcmp(argv[1], "all")) { 685 printer = prbuf; 686 while (cgetnext(&bp, printcapdb) > 0) { 687 cp1 = prbuf; 688 cp2 = bp; 689 while ((c = *cp2++) && c != '|' && c != ':' && 690 (cp1 - prbuf) < sizeof(prbuf)) 691 *cp1++ = c; 692 *cp1 = '\0'; 693 startpr(1); 694 } 695 return; 696 } 697 while (--argc) { 698 printer = *++argv; 699 if ((status = cgetent(&bp, printcapdb, printer)) == -2) { 700 printf("cannot open printer description file\n"); 701 continue; 702 } else if (status == -1) { 703 printf("unknown printer %s\n", printer); 704 continue; 705 } else if (status == -3) 706 fatal("potential reference loop detected in printcap file"); 707 708 startpr(1); 709 } 710 } 711 712 static void 713 startpr(int enable) 714 { 715 struct stat stbuf; 716 717 if (cgetstr(bp, "sd", &SD) == -1) 718 SD = _PATH_DEFSPOOL; 719 if (cgetstr(bp, "lo", &LO) == -1) 720 LO = DEFLOCK; 721 (void)snprintf(line, sizeof(line), "%s/%s", SD, LO); 722 printf("%s:\n", printer); 723 724 /* 725 * Turn off the owner execute bit of the lock file to enable printing. 726 */ 727 seteuid(euid); 728 if (enable && stat(line, &stbuf) >= 0) { 729 if (chmod(line, stbuf.st_mode & (enable==2 ? 0666 : 0677)) < 0) 730 printf("\tcannot enable printing\n"); 731 else 732 printf("\tprinting enabled\n"); 733 } 734 if (!startdaemon(printer)) 735 printf("\tcouldn't start daemon\n"); 736 else 737 printf("\tdaemon started\n"); 738 seteuid(uid); 739 } 740 741 /* 742 * Print the status of each queue listed or all the queues. 743 */ 744 void 745 status(int argc, char *argv[]) 746 { 747 int c, status; 748 char *cp1, *cp2; 749 char prbuf[100]; 750 751 if (argc == 1 || (argc == 2 && strcmp(argv[1], "all") == 0)) { 752 printer = prbuf; 753 while (cgetnext(&bp, printcapdb) > 0) { 754 cp1 = prbuf; 755 cp2 = bp; 756 while ((c = *cp2++) && c != '|' && c != ':' && 757 (cp1 - prbuf) < sizeof(prbuf)) 758 *cp1++ = c; 759 *cp1 = '\0'; 760 prstat(); 761 } 762 return; 763 } 764 while (--argc) { 765 printer = *++argv; 766 if ((status = cgetent(&bp, printcapdb, printer)) == -2) { 767 printf("cannot open printer description file\n"); 768 continue; 769 } else if (status == -1) { 770 printf("unknown printer %s\n", printer); 771 continue; 772 } else if (status == -3) 773 fatal("potential reference loop detected in printcap file"); 774 775 prstat(); 776 } 777 } 778 779 /* 780 * Print the status of the printer queue. 781 */ 782 static void 783 prstat(void) 784 { 785 struct stat stbuf; 786 int fd, i; 787 struct dirent *dp; 788 DIR *dirp; 789 790 if (cgetstr(bp, "sd", &SD) == -1) 791 SD = _PATH_DEFSPOOL; 792 if (cgetstr(bp, "lo", &LO) == -1) 793 LO = DEFLOCK; 794 if (cgetstr(bp, "st", &ST) == -1) 795 ST = DEFSTAT; 796 printf("%s:\n", printer); 797 (void)snprintf(line, sizeof(line), "%s/%s", SD, LO); 798 if (stat(line, &stbuf) >= 0) { 799 printf("\tqueuing is %s\n", 800 (stbuf.st_mode & 010) ? "disabled" : "enabled"); 801 printf("\tprinting is %s\n", 802 (stbuf.st_mode & 0100) ? "disabled" : "enabled"); 803 } else { 804 printf("\tqueuing is enabled\n"); 805 printf("\tprinting is enabled\n"); 806 } 807 if ((dirp = opendir(SD)) == NULL) { 808 printf("\tcannot examine spool directory\n"); 809 return; 810 } 811 i = 0; 812 while ((dp = readdir(dirp)) != NULL) { 813 if (*dp->d_name == 'c' && dp->d_name[1] == 'f') 814 i++; 815 } 816 closedir(dirp); 817 if (i == 0) 818 printf("\tno entries\n"); 819 else if (i == 1) 820 printf("\t1 entry in spool area\n"); 821 else 822 printf("\t%d entries in spool area\n", i); 823 fd = open(line, O_RDONLY); 824 if (fd < 0 || flock(fd, LOCK_SH|LOCK_NB) == 0) { 825 (void)close(fd); /* unlocks as well */ 826 printf("\tprinter idle\n"); 827 return; 828 } 829 (void)close(fd); 830 (void)snprintf(line, sizeof(line), "%s/%s", SD, ST); 831 fd = open(line, O_RDONLY); 832 if (fd >= 0) { 833 (void)flock(fd, LOCK_SH); 834 (void)fstat(fd, &stbuf); 835 if (stbuf.st_size > 0) { 836 putchar('\t'); 837 while ((i = read(fd, line, sizeof(line))) > 0) 838 (void)fwrite(line, 1, i, stdout); 839 } 840 (void)close(fd); /* unlocks as well */ 841 } 842 } 843 844 /* 845 * Stop the specified daemon after completing the current job and disable 846 * printing. 847 */ 848 void 849 stop(int argc, char *argv[]) 850 { 851 int c, status; 852 char *cp1, *cp2; 853 char prbuf[100]; 854 855 if (argc == 1) { 856 printf("Usage: stop {all | printer ...}\n"); 857 return; 858 } 859 if (argc == 2 && !strcmp(argv[1], "all")) { 860 printer = prbuf; 861 while (cgetnext(&bp, printcapdb) > 0) { 862 cp1 = prbuf; 863 cp2 = bp; 864 while ((c = *cp2++) && c != '|' && c != ':' && 865 (cp1 - prbuf) < sizeof(prbuf)) 866 *cp1++ = c; 867 *cp1 = '\0'; 868 stoppr(); 869 } 870 return; 871 } 872 while (--argc) { 873 printer = *++argv; 874 if ((status = cgetent(&bp, printcapdb, printer)) == -2) { 875 printf("cannot open printer description file\n"); 876 continue; 877 } else if (status == -1) { 878 printf("unknown printer %s\n", printer); 879 continue; 880 } else if (status == -3) 881 fatal("potential reference loop detected in printcap file"); 882 883 stoppr(); 884 } 885 } 886 887 static void 888 stoppr(void) 889 { 890 int fd; 891 struct stat stbuf; 892 893 if (cgetstr(bp, "sd", &SD) == -1) 894 SD = _PATH_DEFSPOOL; 895 if (cgetstr(bp, "lo", &LO) == -1) 896 LO = DEFLOCK; 897 (void)snprintf(line, sizeof(line), "%s/%s", SD, LO); 898 printf("%s:\n", printer); 899 900 /* 901 * Turn on the owner execute bit of the lock file to disable printing. 902 */ 903 seteuid(euid); 904 if (stat(line, &stbuf) >= 0) { 905 if (chmod(line, (stbuf.st_mode & 0777) | 0100) < 0) 906 printf("\tcannot disable printing\n"); 907 else { 908 upstat("printing disabled\n"); 909 printf("\tprinting disabled\n"); 910 } 911 } else if (errno == ENOENT) { 912 if ((fd = open(line, O_WRONLY|O_CREAT, 0760)) < 0) 913 printf("\tcannot create lock file\n"); 914 else { 915 (void)close(fd); 916 upstat("printing disabled\n"); 917 printf("\tprinting disabled\n"); 918 } 919 } else 920 printf("\tcannot stat lock file\n"); 921 seteuid(uid); 922 } 923 924 struct queue **queue; 925 int nitems; 926 time_t mtime; 927 928 /* 929 * Put the specified jobs at the top of printer queue. 930 */ 931 void 932 topq(int argc, char *argv[]) 933 { 934 int i; 935 struct stat stbuf; 936 int status, changed; 937 938 if (argc < 3) { 939 printf("Usage: topq printer [jobnum ...] [user ...]\n"); 940 return; 941 } 942 943 --argc; 944 printer = *++argv; 945 status = cgetent(&bp, printcapdb, printer); 946 if (status == -2) { 947 printf("cannot open printer description file\n"); 948 return; 949 } else if (status == -1) { 950 printf("%s: unknown printer\n", printer); 951 return; 952 } else if (status == -3) 953 fatal("potential reference loop detected in printcap file"); 954 955 if (cgetstr(bp, "sd", &SD) == -1) 956 SD = _PATH_DEFSPOOL; 957 if (cgetstr(bp, "lo", &LO) == -1) 958 LO = DEFLOCK; 959 printf("%s:\n", printer); 960 961 seteuid(euid); 962 if (chdir(SD) < 0) { 963 printf("\tcannot chdir to %s\n", SD); 964 goto out; 965 } 966 seteuid(uid); 967 nitems = getq(&queue); 968 if (nitems == 0) 969 return; 970 changed = 0; 971 mtime = queue[0]->q_time; 972 for (i = argc; --i; ) { 973 if (doarg(argv[i]) == 0) { 974 printf("\tjob %s is not in the queue\n", argv[i]); 975 continue; 976 } else 977 changed++; 978 } 979 for (i = 0; i < nitems; i++) 980 free(queue[i]); 981 free(queue); 982 if (!changed) { 983 printf("\tqueue order unchanged\n"); 984 return; 985 } 986 /* 987 * Turn on the public execute bit of the lock file to 988 * get lpd to rebuild the queue after the current job. 989 */ 990 seteuid(euid); 991 if (changed && stat(LO, &stbuf) >= 0) 992 (void)chmod(LO, (stbuf.st_mode & 0777) | 01); 993 994 out: 995 seteuid(uid); 996 } 997 998 /* 999 * Reposition the job by changing the modification time of 1000 * the control file. 1001 */ 1002 static int 1003 touch(struct queue *q) 1004 { 1005 struct timeval tvp[2]; 1006 int ret; 1007 1008 tvp[0].tv_sec = tvp[1].tv_sec = --mtime; 1009 tvp[0].tv_usec = tvp[1].tv_usec = 0; 1010 seteuid(euid); 1011 ret = utimes(q->q_name, tvp); 1012 seteuid(uid); 1013 return (ret); 1014 } 1015 1016 /* 1017 * Checks if specified job name is in the printer's queue. 1018 * Returns: negative (-1) if argument name is not in the queue. 1019 */ 1020 static int 1021 doarg(char *job) 1022 { 1023 struct queue **qq; 1024 int jobnum, n; 1025 char *cp, *machine; 1026 int cnt = 0; 1027 FILE *fp; 1028 1029 /* 1030 * Look for a job item consisting of system name, colon, number 1031 * (example: ucbarpa:114) 1032 */ 1033 if ((cp = strchr(job, ':')) != NULL) { 1034 machine = job; 1035 *cp++ = '\0'; 1036 job = cp; 1037 } else 1038 machine = NULL; 1039 1040 /* 1041 * Check for job specified by number (example: 112 or 235ucbarpa). 1042 */ 1043 if (isdigit(*job)) { 1044 jobnum = 0; 1045 do 1046 jobnum = jobnum * 10 + (*job++ - '0'); 1047 while (isdigit(*job)); 1048 for (qq = queue + nitems; --qq >= queue; ) { 1049 n = 0; 1050 for (cp = (*qq)->q_name+3; isdigit(*cp); ) 1051 n = n * 10 + (*cp++ - '0'); 1052 if (jobnum != n) 1053 continue; 1054 if (*job && strcmp(job, cp) != 0) 1055 continue; 1056 if (machine != NULL && strcmp(machine, cp) != 0) 1057 continue; 1058 if (touch(*qq) == 0) { 1059 printf("\tmoved %s\n", (*qq)->q_name); 1060 cnt++; 1061 } 1062 } 1063 return(cnt); 1064 } 1065 /* 1066 * Process item consisting of owner's name (example: henry). 1067 */ 1068 for (qq = queue + nitems; --qq >= queue; ) { 1069 seteuid(euid); 1070 fp = fopen((*qq)->q_name, "r"); 1071 seteuid(uid); 1072 if (fp == NULL) 1073 continue; 1074 while (getline(fp) > 0) 1075 if (line[0] == 'P') 1076 break; 1077 (void)fclose(fp); 1078 if (line[0] != 'P' || strcmp(job, line+1) != 0) 1079 continue; 1080 if (touch(*qq) == 0) { 1081 printf("\tmoved %s\n", (*qq)->q_name); 1082 cnt++; 1083 } 1084 } 1085 return(cnt); 1086 } 1087 1088 /* 1089 * Enable everything and start printer (undo `down'). 1090 */ 1091 void 1092 up(int argc, char *argv[]) 1093 { 1094 int c, status; 1095 char *cp1, *cp2; 1096 char prbuf[100]; 1097 1098 if (argc == 1) { 1099 printf("Usage: up {all | printer ...}\n"); 1100 return; 1101 } 1102 if (argc == 2 && !strcmp(argv[1], "all")) { 1103 printer = prbuf; 1104 while (cgetnext(&bp, printcapdb) > 0) { 1105 cp1 = prbuf; 1106 cp2 = bp; 1107 while ((c = *cp2++) && c != '|' && c != ':' && 1108 (cp1 - prbuf) < sizeof(prbuf)) 1109 *cp1++ = c; 1110 *cp1 = '\0'; 1111 startpr(2); 1112 } 1113 return; 1114 } 1115 while (--argc) { 1116 printer = *++argv; 1117 if ((status = cgetent(&bp, printcapdb, printer)) == -2) { 1118 printf("cannot open printer description file\n"); 1119 continue; 1120 } else if (status == -1) { 1121 printf("unknown printer %s\n", printer); 1122 continue; 1123 } else if (status == -3) 1124 fatal("potential reference loop detected in printcap file"); 1125 1126 startpr(2); 1127 } 1128 } 1129