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