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