1 /* $OpenBSD: cmds.c,v 1.21 2009/10/29 20:11:09 sobrado 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 void *, const void *); 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 (!getline(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 void *a, const void *b) 269 { 270 const struct dirent **d1, **d2; 271 int c1, c2; 272 273 d1 = (const struct dirent **)a; 274 d2 = (const struct dirent **)b; 275 if ((c1 = strcmp((*d1)->d_name + 3, (*d2)->d_name + 3)) != 0) 276 return(c1); 277 c1 = (*d1)->d_name[0]; 278 c2 = (*d2)->d_name[0]; 279 if (c1 == c2) 280 return((*d1)->d_name[2] - (*d2)->d_name[2]); 281 if (c1 == 'c') 282 return(-1); 283 if (c1 == 'd' || c2 == 'c') 284 return(1); 285 return(-1); 286 } 287 288 /* 289 * Remove incomplete jobs from spooling area. 290 */ 291 static void 292 cleanpr(void) 293 { 294 int i, n; 295 char *cp, *cp1, *lp; 296 struct dirent **queue; 297 int nitems; 298 299 if (cgetstr(bp, "sd", &SD) == -1) 300 SD = _PATH_DEFSPOOL; 301 printf("%s:\n", printer); 302 303 /* XXX depends on SD being non-NUL */ 304 for (lp = line, cp = SD; (lp - line) < sizeof(line) && 305 (*lp++ = *cp++) != '\0'; ) 306 ; 307 lp[-1] = '/'; 308 if (lp - line >= sizeof(line)) { 309 printf("\tspool directory name too long\n"); 310 return; 311 } 312 313 PRIV_START; 314 nitems = scandir(SD, &queue, doselect, sortq); 315 PRIV_END; 316 if (nitems < 0) { 317 printf("\tcannot examine spool directory\n"); 318 return; 319 } 320 if (nitems == 0) 321 return; 322 i = 0; 323 do { 324 cp = queue[i]->d_name; 325 if (*cp == 'c') { 326 n = 0; 327 while (i + 1 < nitems) { 328 cp1 = queue[i + 1]->d_name; 329 if (*cp1 != 'd' || strcmp(cp + 3, cp1 + 3)) 330 break; 331 i++; 332 n++; 333 } 334 if (n == 0) { 335 if (strlcpy(lp, cp, sizeof(line) - (lp - line)) 336 >= sizeof(line) - (lp - line)) 337 printf("\tpath too long, %s/%s", SD, cp); 338 else 339 unlinkf(line); 340 } 341 } else { 342 /* 343 * Must be a df with no cf (otherwise, it would have 344 * been skipped above) or a tf file (which can always 345 * be removed). 346 */ 347 if (strlcpy(lp, cp, sizeof(line) - (lp - line)) >= 348 sizeof(line) - (lp - line)) 349 printf("\tpath too long, %s/%s", SD, cp); 350 else 351 unlinkf(line); 352 } 353 } while (++i < nitems); 354 } 355 356 static void 357 unlinkf(char *name) 358 { 359 PRIV_START; 360 if (unlink(name) < 0) 361 printf("\tcannot remove %s\n", name); 362 else 363 printf("\tremoved %s\n", name); 364 PRIV_END; 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") == 0) { 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) - 1) 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 PRIV_START; 425 if (stat(line, &stbuf) >= 0) { 426 stbuf.st_mode &= ~S_IXGRP; 427 if (chmod(line, stbuf.st_mode & 0777) < 0) 428 printf("\tcannot enable queuing\n"); 429 else 430 printf("\tqueuing enabled\n"); 431 } 432 PRIV_END; 433 } 434 435 /* 436 * Disable queuing. 437 */ 438 void 439 disable(int argc, char **argv) 440 { 441 int c, status; 442 char *cp1, *cp2; 443 char prbuf[100]; 444 445 if (argc == 1) { 446 printf("usage: disable {all | printer ...}\n"); 447 return; 448 } 449 if (argc == 2 && strcmp(argv[1], "all") == 0) { 450 printer = prbuf; 451 while (cgetnext(&bp, printcapdb) > 0) { 452 cp1 = prbuf; 453 cp2 = bp; 454 while ((c = *cp2++) && c != '|' && c != ':' && 455 (cp1 - prbuf) < sizeof(prbuf) - 1) 456 *cp1++ = c; 457 *cp1 = '\0'; 458 disablepr(); 459 } 460 return; 461 } 462 while (--argc) { 463 printer = *++argv; 464 if ((status = cgetent(&bp, printcapdb, printer)) == -2) { 465 printf("cannot open printer description file\n"); 466 continue; 467 } else if (status == -1) { 468 printf("unknown printer %s\n", printer); 469 continue; 470 } else if (status == -3) 471 fatal("potential reference loop detected in printcap file"); 472 473 disablepr(); 474 } 475 } 476 477 static void 478 disablepr(void) 479 { 480 int fd; 481 struct stat stbuf; 482 483 if (cgetstr(bp, "sd", &SD) == -1) 484 SD = _PATH_DEFSPOOL; 485 if (cgetstr(bp, "lo", &LO) == -1) 486 LO = DEFLOCK; 487 (void)snprintf(line, sizeof(line), "%s/%s", SD, LO); 488 printf("%s:\n", printer); 489 /* 490 * Turn on the group execute bit of the lock file to disable queuing. 491 */ 492 PRIV_START; 493 if (stat(line, &stbuf) >= 0) { 494 stbuf.st_mode |= S_IXGRP; 495 if (chmod(line, stbuf.st_mode & 0777) < 0) 496 printf("\tcannot disable queuing\n"); 497 else 498 printf("\tqueuing disabled\n"); 499 } else if (errno == ENOENT) { 500 if ((fd = safe_open(line, O_WRONLY|O_CREAT|O_NOFOLLOW, 0670)) < 0) 501 printf("\tcannot create lock file\n"); 502 else { 503 (void)fchown(fd, DEFUID, -1); 504 (void)close(fd); 505 printf("\tqueuing disabled\n"); 506 } 507 } else 508 printf("\tcannot stat lock file\n"); 509 PRIV_END; 510 } 511 512 /* 513 * Disable queuing and printing and put a message into the status file 514 * (reason for being down). 515 */ 516 void 517 down(int argc, char **argv) 518 { 519 int c, status; 520 char *cp1, *cp2; 521 char prbuf[100]; 522 523 if (argc == 1) { 524 printf("usage: down {all | printer} [message ...]\n"); 525 return; 526 } 527 if (strcmp(argv[1], "all") == 0) { 528 printer = prbuf; 529 while (cgetnext(&bp, printcapdb) > 0) { 530 cp1 = prbuf; 531 cp2 = bp; 532 while ((c = *cp2++) && c != '|' && c != ':' && 533 (cp1 - prbuf) < sizeof(prbuf) - 1) 534 *cp1++ = c; 535 *cp1 = '\0'; 536 putmsg(argc - 2, argv + 2); 537 } 538 return; 539 } 540 printer = argv[1]; 541 if ((status = cgetent(&bp, printcapdb, printer)) == -2) { 542 printf("cannot open printer description file\n"); 543 return; 544 } else if (status == -1) { 545 printf("unknown printer %s\n", printer); 546 return; 547 } else if (status == -3) 548 fatal("potential reference loop detected in printcap file"); 549 550 putmsg(argc - 2, argv + 2); 551 } 552 553 static void 554 putmsg(int argc, char **argv) 555 { 556 int fd; 557 char *cp1, *cp2; 558 char buf[1024]; 559 struct stat stbuf; 560 561 if (cgetstr(bp, "sd", &SD) == -1) 562 SD = _PATH_DEFSPOOL; 563 if (cgetstr(bp, "lo", &LO) == -1) 564 LO = DEFLOCK; 565 if (cgetstr(bp, "st", &ST) == -1) 566 ST = DEFSTAT; 567 printf("%s:\n", printer); 568 /* 569 * Turn on the group execute bit of the lock file to disable queuing and 570 * turn on the owner execute bit of the lock file to disable printing. 571 */ 572 (void)snprintf(line, sizeof(line), "%s/%s", SD, LO); 573 PRIV_START; 574 if (stat(line, &stbuf) >= 0) { 575 stbuf.st_mode |= (S_IXGRP|S_IXUSR); 576 if (chmod(line, stbuf.st_mode & 0777) < 0) 577 printf("\tcannot disable queuing\n"); 578 else 579 printf("\tprinter and queuing disabled\n"); 580 } else if (errno == ENOENT) { 581 if ((fd = safe_open(line, O_WRONLY|O_CREAT|O_NOFOLLOW, 0770)) < 0) 582 printf("\tcannot create lock file\n"); 583 else { 584 (void)fchown(fd, DEFUID, -1); 585 (void)close(fd); 586 printf("\tprinter and queuing disabled\n"); 587 } 588 PRIV_END; 589 return; 590 } else 591 printf("\tcannot stat lock file\n"); 592 /* 593 * Write the message into the status file. 594 */ 595 (void)snprintf(line, sizeof(line), "%s/%s", SD, ST); 596 fd = safe_open(line, O_WRONLY|O_CREAT|O_NOFOLLOW, 0660); 597 if (fd < 0 || flock(fd, LOCK_EX) < 0) { 598 printf("\tcannot create status file\n"); 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 (void)close(fd); /* unlocks as well */ 845 printf("\tprinter idle\n"); 846 return; 847 } 848 (void)close(fd); 849 (void)snprintf(line, sizeof(line), "%s/%s", SD, ST); 850 PRIV_START; 851 fd = safe_open(line, O_RDONLY|O_NOFOLLOW, 0); 852 PRIV_END; 853 if (fd >= 0) { 854 (void)flock(fd, LOCK_SH); 855 if (fstat(fd, &stbuf) == 0 && stbuf.st_size > 0) { 856 putchar('\t'); 857 while ((i = read(fd, line, sizeof(line))) > 0) 858 (void)fwrite(line, 1, i, stdout); 859 } 860 (void)close(fd); /* unlocks as well */ 861 } 862 } 863 864 /* 865 * Stop the specified daemon after completing the current job and disable 866 * printing. 867 */ 868 void 869 stop(int argc, char **argv) 870 { 871 int c, status; 872 char *cp1, *cp2; 873 char prbuf[100]; 874 875 if (argc == 1) { 876 printf("usage: stop {all | printer ...}\n"); 877 return; 878 } 879 if (argc == 2 && strcmp(argv[1], "all") == 0) { 880 printer = prbuf; 881 while (cgetnext(&bp, printcapdb) > 0) { 882 cp1 = prbuf; 883 cp2 = bp; 884 while ((c = *cp2++) && c != '|' && c != ':' && 885 (cp1 - prbuf) < sizeof(prbuf) - 1) 886 *cp1++ = c; 887 *cp1 = '\0'; 888 stoppr(); 889 } 890 return; 891 } 892 while (--argc) { 893 printer = *++argv; 894 if ((status = cgetent(&bp, printcapdb, printer)) == -2) { 895 printf("cannot open printer description file\n"); 896 continue; 897 } else if (status == -1) { 898 printf("unknown printer %s\n", printer); 899 continue; 900 } else if (status == -3) 901 fatal("potential reference loop detected in printcap file"); 902 903 stoppr(); 904 } 905 } 906 907 static void 908 stoppr(void) 909 { 910 int fd; 911 struct stat stbuf; 912 913 if (cgetstr(bp, "sd", &SD) == -1) 914 SD = _PATH_DEFSPOOL; 915 if (cgetstr(bp, "lo", &LO) == -1) 916 LO = DEFLOCK; 917 (void)snprintf(line, sizeof(line), "%s/%s", SD, LO); 918 printf("%s:\n", printer); 919 920 /* 921 * Turn on the owner execute bit of the lock file to disable printing. 922 */ 923 PRIV_START; 924 if (stat(line, &stbuf) >= 0) { 925 stbuf.st_mode |= S_IXUSR; 926 if (chmod(line, stbuf.st_mode & 0777) < 0) 927 printf("\tcannot disable printing\n"); 928 else { 929 upstat("printing disabled\n"); 930 printf("\tprinting disabled\n"); 931 } 932 } else if (errno == ENOENT) { 933 if ((fd = safe_open(line, O_WRONLY|O_CREAT|O_NOFOLLOW, 0760)) < 0) 934 printf("\tcannot create lock file\n"); 935 else { 936 (void)fchown(fd, DEFUID, -1); 937 (void)close(fd); 938 upstat("printing disabled\n"); 939 printf("\tprinting disabled\n"); 940 } 941 } else 942 printf("\tcannot stat lock file\n"); 943 PRIV_END; 944 } 945 946 struct queue **queue; 947 int nitems; 948 time_t mtime; 949 950 /* 951 * Put the specified jobs at the top of printer queue. 952 */ 953 void 954 topq(int argc, char **argv) 955 { 956 int i; 957 struct stat stbuf; 958 int status, changed; 959 960 if (argc < 3) { 961 printf("usage: topq printer [jobnum ...] [user ...]\n"); 962 return; 963 } 964 965 --argc; 966 printer = *++argv; 967 status = cgetent(&bp, printcapdb, printer); 968 if (status == -2) { 969 printf("cannot open printer description file\n"); 970 return; 971 } else if (status == -1) { 972 printf("%s: unknown printer\n", printer); 973 return; 974 } else if (status == -3) 975 fatal("potential reference loop detected in printcap file"); 976 977 if (cgetstr(bp, "sd", &SD) == -1) 978 SD = _PATH_DEFSPOOL; 979 if (cgetstr(bp, "lo", &LO) == -1) 980 LO = DEFLOCK; 981 printf("%s:\n", printer); 982 983 PRIV_START; 984 if (chdir(SD) < 0) { 985 printf("\tcannot chdir to %s\n", SD); 986 goto out; 987 } 988 PRIV_END; 989 nitems = getq(&queue); 990 if (nitems == 0) 991 return; 992 changed = 0; 993 mtime = queue[0]->q_time; 994 for (i = argc; --i; ) { 995 if (doarg(argv[i]) == 0) { 996 printf("\tjob %s is not in the queue\n", argv[i]); 997 continue; 998 } else 999 changed++; 1000 } 1001 for (i = 0; i < nitems; i++) 1002 free(queue[i]); 1003 free(queue); 1004 if (!changed) { 1005 printf("\tqueue order unchanged\n"); 1006 return; 1007 } 1008 /* 1009 * Turn on the public execute bit of the lock file to 1010 * get lpd to rebuild the queue after the current job. 1011 */ 1012 PRIV_START; 1013 if (changed && stat(LO, &stbuf) >= 0) { 1014 stbuf.st_mode |= S_IXOTH; 1015 (void)chmod(LO, stbuf.st_mode & 0777); 1016 } 1017 1018 out: 1019 PRIV_END; 1020 } 1021 1022 /* 1023 * Reposition the job by changing the modification time of 1024 * the control file. 1025 */ 1026 static int 1027 touch(struct queue *q) 1028 { 1029 struct timeval tvp[2]; 1030 int ret; 1031 1032 tvp[0].tv_sec = tvp[1].tv_sec = --mtime; 1033 tvp[0].tv_usec = tvp[1].tv_usec = 0; 1034 PRIV_START; 1035 ret = utimes(q->q_name, tvp); 1036 PRIV_END; 1037 return (ret); 1038 } 1039 1040 /* 1041 * Checks if specified job name is in the printer's queue. 1042 * Returns: negative (-1) if argument name is not in the queue. 1043 */ 1044 int 1045 doarg(char *job) 1046 { 1047 struct queue **qq; 1048 int jobnum, fd, n; 1049 char *cp, *machine; 1050 int cnt = 0; 1051 FILE *fp; 1052 1053 /* 1054 * Look for a job item consisting of system name, colon, number 1055 * (example: ucbarpa:114) 1056 */ 1057 if ((cp = strchr(job, ':')) != NULL) { 1058 machine = job; 1059 *cp++ = '\0'; 1060 job = cp; 1061 } else 1062 machine = NULL; 1063 1064 /* 1065 * Check for job specified by number (example: 112 or 235ucbarpa). 1066 */ 1067 if (isdigit(*job)) { 1068 jobnum = 0; 1069 do 1070 jobnum = jobnum * 10 + (*job++ - '0'); 1071 while (isdigit(*job)); 1072 for (qq = queue + nitems; --qq >= queue; ) { 1073 n = 0; 1074 for (cp = (*qq)->q_name+3; isdigit(*cp); ) 1075 n = n * 10 + (*cp++ - '0'); 1076 if (jobnum != n) 1077 continue; 1078 if (*job && strcmp(job, cp) != 0) 1079 continue; 1080 if (machine != NULL && strcmp(machine, cp) != 0) 1081 continue; 1082 if (touch(*qq) == 0) { 1083 printf("\tmoved %s\n", (*qq)->q_name); 1084 cnt++; 1085 } 1086 } 1087 return(cnt); 1088 } 1089 /* 1090 * Process item consisting of owner's name (example: henry). 1091 */ 1092 for (qq = queue + nitems; --qq >= queue; ) { 1093 PRIV_START; 1094 fd = safe_open((*qq)->q_name, O_RDONLY|O_NOFOLLOW, 0); 1095 PRIV_END; 1096 if (fd < 0 || (fp = fdopen(fd, "r")) == NULL) { 1097 if (fd >= 0) 1098 close(fd); 1099 continue; 1100 } 1101 while (getline(fp) > 0) 1102 if (line[0] == 'P') 1103 break; 1104 (void)fclose(fp); 1105 if (line[0] != 'P' || strcmp(job, line+1) != 0) 1106 continue; 1107 if (touch(*qq) == 0) { 1108 printf("\tmoved %s\n", (*qq)->q_name); 1109 cnt++; 1110 } 1111 } 1112 return(cnt); 1113 } 1114 1115 /* 1116 * Enable everything and start printer (undo `down'). 1117 */ 1118 void 1119 up(int argc, char **argv) 1120 { 1121 int c, status; 1122 char *cp1, *cp2; 1123 char prbuf[100]; 1124 1125 if (argc == 1) { 1126 printf("usage: up {all | printer ...}\n"); 1127 return; 1128 } 1129 if (argc == 2 && strcmp(argv[1], "all") == 0) { 1130 printer = prbuf; 1131 while (cgetnext(&bp, printcapdb) > 0) { 1132 cp1 = prbuf; 1133 cp2 = bp; 1134 while ((c = *cp2++) && c != '|' && c != ':' && 1135 (cp1 - prbuf) < sizeof(prbuf) - 1) 1136 *cp1++ = c; 1137 *cp1 = '\0'; 1138 startpr(2); 1139 } 1140 return; 1141 } 1142 while (--argc) { 1143 printer = *++argv; 1144 if ((status = cgetent(&bp, printcapdb, printer)) == -2) { 1145 printf("cannot open printer description file\n"); 1146 continue; 1147 } else if (status == -1) { 1148 printf("unknown printer %s\n", printer); 1149 continue; 1150 } else if (status == -3) 1151 fatal("potential reference loop detected in printcap file"); 1152 1153 startpr(2); 1154 } 1155 } 1156