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