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