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