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