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