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