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