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