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