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