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