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