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