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