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