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