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