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