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