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