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