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