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