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