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