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