xref: /freebsd/usr.sbin/lpr/lpc/cmds.c (revision 23f282aa31e9b6fceacd449020e936e98d6f2298)
1 /*
2  * Copyright (c) 1983, 1993
3  *	The Regents of the University of California.  All rights reserved.
4  *
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  * 3. All advertising materials mentioning features or use of this software
15  *    must display the following acknowledgement:
16  *	This product includes software developed by the University of
17  *	California, Berkeley and its contributors.
18  * 4. Neither the name of the University nor the names of its contributors
19  *    may be used to endorse or promote products derived from this software
20  *    without specific prior written permission.
21  *
22  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32  * SUCH DAMAGE.
33  */
34 
35 #ifndef lint
36 static const char copyright[] =
37 "@(#) Copyright (c) 1983, 1993\n\
38 	The Regents of the University of California.  All rights reserved.\n";
39 #endif /* not lint */
40 
41 #ifndef lint
42 /*
43 static char sccsid[] = "@(#)cmds.c	8.2 (Berkeley) 4/28/95";
44 */
45 static const char rcsid[] =
46   "$FreeBSD$";
47 #endif /* not lint */
48 
49 /*
50  * lpc -- line printer control program -- commands:
51  */
52 
53 #include <sys/param.h>
54 #include <sys/time.h>
55 #include <sys/stat.h>
56 #include <sys/file.h>
57 
58 #include <signal.h>
59 #include <fcntl.h>
60 #include <errno.h>
61 #include <dirent.h>
62 #include <unistd.h>
63 #include <stdlib.h>
64 #include <stdio.h>
65 #include <ctype.h>
66 #include <string.h>
67 #include "lp.h"
68 #include "lp.local.h"
69 #include "lpc.h"
70 #include "extern.h"
71 #include "pathnames.h"
72 
73 static void	abortpr __P((struct printer *, int));
74 static int	doarg __P((char *));
75 static int	doselect __P((struct dirent *));
76 static void	putmsg __P((struct printer *, int, char **));
77 static int	sortq __P((const void *, const void *));
78 static void	startpr __P((struct printer *, int));
79 static int	touch __P((struct queue *));
80 static void	unlinkf __P((char *));
81 static void	upstat __P((struct printer *, char *));
82 
83 /*
84  * generic framework for commands which operate on all or a specified
85  * set of printers
86  */
87 void
88 generic(doit, argc, argv)
89 	void (*doit) __P((struct printer *));
90 	int argc;
91 	char *argv[];
92 {
93 	int status, more;
94 	struct printer myprinter, *pp = &myprinter;
95 
96 	if (argc == 1) {
97 		printf("Usage: %s {all | printer ...}\n", argv[0]);
98 		return;
99 	}
100 	if (argc == 2 && strcmp(argv[1], "all") == 0) {
101 		more = firstprinter(pp, &status);
102 		if (status)
103 			goto looperr;
104 		while (more) {
105 			(*doit)(pp);
106 			do {
107 				more = nextprinter(pp, &status);
108 looperr:
109 				switch (status) {
110 				case PCAPERR_TCOPEN:
111 					printf("warning: %s: unresolved "
112 					       "tc= reference(s) ",
113 					       pp->printer);
114 				case PCAPERR_SUCCESS:
115 					break;
116 				default:
117 					fatal(pp, pcaperr(status));
118 				}
119 			} while (more && status);
120 		}
121 		return;
122 	}
123 	while (--argc) {
124 		++argv;
125 		init_printer(pp);
126 		status = getprintcap(*argv, pp);
127 		switch(status) {
128 		default:
129 			fatal(pp, pcaperr(status));
130 		case PCAPERR_NOTFOUND:
131 			printf("unknown printer %s\n", *argv);
132 			continue;
133 		case PCAPERR_TCOPEN:
134 			printf("warning: %s: unresolved tc= reference(s)\n",
135 			       *argv);
136 			break;
137 		case PCAPERR_SUCCESS:
138 			break;
139 		}
140 		(*doit)(pp);
141 	}
142 }
143 
144 /*
145  * kill an existing daemon and disable printing.
146  */
147 void
148 doabort(pp)
149 	struct printer *pp;
150 {
151 	abortpr(pp, 1);
152 }
153 
154 static void
155 abortpr(pp, dis)
156 	struct printer *pp;
157 	int dis;
158 {
159 	register FILE *fp;
160 	struct stat stbuf;
161 	int pid, fd;
162 	char lf[MAXPATHLEN];
163 
164 	lock_file_name(pp, lf, sizeof lf);
165 	printf("%s:\n", pp->printer);
166 
167 	/*
168 	 * Turn on the owner execute bit of the lock file to disable printing.
169 	 */
170 	if (dis) {
171 		seteuid(euid);
172 		if (stat(lf, &stbuf) >= 0) {
173 			if (chmod(lf, stbuf.st_mode | LFM_PRINT_DIS) < 0)
174 				printf("\tcannot disable printing: %s\n",
175 				       strerror(errno));
176 			else {
177 				upstat(pp, "printing disabled\n");
178 				printf("\tprinting disabled\n");
179 			}
180 		} else if (errno == ENOENT) {
181 			if ((fd = open(lf, O_WRONLY|O_CREAT,
182 				       LOCK_FILE_MODE | LFM_PRINT_DIS)) < 0)
183 				printf("\tcannot create lock file: %s\n",
184 				       strerror(errno));
185 			else {
186 				(void) close(fd);
187 				upstat(pp, "printing disabled\n");
188 				printf("\tprinting disabled\n");
189 				printf("\tno daemon to abort\n");
190 			}
191 			goto out;
192 		} else {
193 			printf("\tcannot stat lock file\n");
194 			goto out;
195 		}
196 	}
197 	/*
198 	 * Kill the current daemon to stop printing now.
199 	 */
200 	if ((fp = fopen(lf, "r")) == NULL) {
201 		printf("\tcannot open lock file\n");
202 		goto out;
203 	}
204 	if (!getline(fp) || flock(fileno(fp), LOCK_SH|LOCK_NB) == 0) {
205 		(void) fclose(fp);	/* unlocks as well */
206 		printf("\tno daemon to abort\n");
207 		goto out;
208 	}
209 	(void) fclose(fp);
210 	if (kill(pid = atoi(line), SIGTERM) < 0) {
211 		if (errno == ESRCH)
212 			printf("\tno daemon to abort\n");
213 		else
214 			printf("\tWarning: daemon (pid %d) not killed\n", pid);
215 	} else
216 		printf("\tdaemon (pid %d) killed\n", pid);
217 out:
218 	seteuid(uid);
219 }
220 
221 /*
222  * Write a message into the status file.
223  */
224 static void
225 upstat(pp, msg)
226 	struct printer *pp;
227 	char *msg;
228 {
229 	register int fd;
230 	char statfile[MAXPATHLEN];
231 
232 	status_file_name(pp, statfile, sizeof statfile);
233 	umask(0);
234 	fd = open(statfile, O_WRONLY|O_CREAT|O_EXLOCK, STAT_FILE_MODE);
235 	if (fd < 0) {
236 		printf("\tcannot create status file: %s\n", strerror(errno));
237 		return;
238 	}
239 	(void) ftruncate(fd, 0);
240 	if (msg == (char *)NULL)
241 		(void) write(fd, "\n", 1);
242 	else
243 		(void) write(fd, msg, strlen(msg));
244 	(void) close(fd);
245 }
246 
247 static int
248 doselect(d)
249 	struct dirent *d;
250 {
251 	int c = d->d_name[0];
252 
253 	if ((c == 't' || c == 'c' || c == 'd') && d->d_name[1] == 'f')
254 		return(1);
255 	return(0);
256 }
257 
258 /*
259  * Comparison routine for scandir. Sort by job number and machine, then
260  * by `cf', `tf', or `df', then by the sequence letter A-Z, a-z.
261  */
262 static int
263 sortq(a, b)
264 	const void *a, *b;
265 {
266 	struct dirent **d1, **d2;
267 	int c1, c2;
268 
269 	d1 = (struct dirent **)a;
270 	d2 = (struct dirent **)b;
271 	if ((c1 = strcmp((*d1)->d_name + 3, (*d2)->d_name + 3)))
272 		return(c1);
273 	c1 = (*d1)->d_name[0];
274 	c2 = (*d2)->d_name[0];
275 	if (c1 == c2)
276 		return((*d1)->d_name[2] - (*d2)->d_name[2]);
277 	if (c1 == 'c')
278 		return(-1);
279 	if (c1 == 'd' || c2 == 'c')
280 		return(1);
281 	return(-1);
282 }
283 
284 /*
285  * Remove all spool files and temporaries from the spooling area.
286  * Or, perhaps:
287  * Remove incomplete jobs from spooling area.
288  */
289 void
290 clean(pp)
291 	struct printer *pp;
292 {
293 	register int i, n;
294 	register char *cp, *cp1, *lp;
295 	struct dirent **queue;
296 	int nitems;
297 
298 	printf("%s:\n", pp->printer);
299 
300 	lp = line;
301 	cp = pp->spool_dir;
302 	while (lp < &line[sizeof(line) - 1]) {
303 		if ((*lp++ = *cp++) == 0)
304 			break;
305 	}
306 	lp[-1] = '/';
307 
308 	seteuid(euid);
309 	nitems = scandir(pp->spool_dir, &queue, doselect, sortq);
310 	seteuid(uid);
311 	if (nitems < 0) {
312 		printf("\tcannot examine spool directory\n");
313 		return;
314 	}
315 	if (nitems == 0)
316 		return;
317 	i = 0;
318 	do {
319 		cp = queue[i]->d_name;
320 		if (*cp == 'c') {
321 			n = 0;
322 			while (i + 1 < nitems) {
323 				cp1 = queue[i + 1]->d_name;
324 				if (*cp1 != 'd' || strcmp(cp + 3, cp1 + 3))
325 					break;
326 				i++;
327 				n++;
328 			}
329 			if (n == 0) {
330 				strncpy(lp, cp, sizeof(line) - strlen(line) - 1);
331 				line[sizeof(line) - 1] = '\0';
332 				unlinkf(line);
333 			}
334 		} else {
335 			/*
336 			 * Must be a df with no cf (otherwise, it would have
337 			 * been skipped above) or a tf file (which can always
338 			 * be removed).
339 			 */
340 			strncpy(lp, cp, sizeof(line) - strlen(line) - 1);
341 			line[sizeof(line) - 1] = '\0';
342 			unlinkf(line);
343 		}
344      	} while (++i < nitems);
345 }
346 
347 static void
348 unlinkf(name)
349 	char	*name;
350 {
351 	seteuid(euid);
352 	if (unlink(name) < 0)
353 		printf("\tcannot remove %s\n", name);
354 	else
355 		printf("\tremoved %s\n", name);
356 	seteuid(uid);
357 }
358 
359 /*
360  * Enable queuing to the printer (allow lpr's).
361  */
362 void
363 enable(pp)
364 	struct printer *pp;
365 {
366 	struct stat stbuf;
367 	char lf[MAXPATHLEN];
368 
369 	lock_file_name(pp, lf, sizeof lf);
370 	printf("%s:\n", pp->printer);
371 
372 	/*
373 	 * Turn off the group execute bit of the lock file to enable queuing.
374 	 */
375 	seteuid(euid);
376 	if (stat(lf, &stbuf) >= 0) {
377 		if (chmod(lf, stbuf.st_mode & ~LFM_QUEUE_DIS) < 0)
378 			printf("\tcannot enable queuing\n");
379 		else
380 			printf("\tqueuing enabled\n");
381 	}
382 	seteuid(uid);
383 }
384 
385 /*
386  * Disable queuing.
387  */
388 void
389 disable(pp)
390 	struct printer *pp;
391 {
392 	register int fd;
393 	struct stat stbuf;
394 	char lf[MAXPATHLEN];
395 
396 	lock_file_name(pp, lf, sizeof lf);
397 	printf("%s:\n", pp->printer);
398 	/*
399 	 * Turn on the group execute bit of the lock file to disable queuing.
400 	 */
401 	seteuid(euid);
402 	if (stat(lf, &stbuf) >= 0) {
403 		if (chmod(lf, stbuf.st_mode | LFM_QUEUE_DIS) < 0)
404 			printf("\tcannot disable queuing: %s\n",
405 			       strerror(errno));
406 		else
407 			printf("\tqueuing disabled\n");
408 	} else if (errno == ENOENT) {
409 		if ((fd = open(lf, O_WRONLY|O_CREAT,
410 			       LOCK_FILE_MODE | LFM_QUEUE_DIS)) < 0)
411 			printf("\tcannot create lock file: %s\n",
412 			       strerror(errno));
413 		else {
414 			(void) close(fd);
415 			printf("\tqueuing disabled\n");
416 		}
417 	} else
418 		printf("\tcannot stat lock file\n");
419 	seteuid(uid);
420 }
421 
422 /*
423  * Disable queuing and printing and put a message into the status file
424  * (reason for being down).
425  */
426 void
427 down(argc, argv)
428 	int argc;
429 	char *argv[];
430 {
431         int status, more;
432 	struct printer myprinter, *pp = &myprinter;
433 
434 	if (argc == 1) {
435 		printf("Usage: down {all | printer} [message ...]\n");
436 		return;
437 	}
438 	if (!strcmp(argv[1], "all")) {
439 		more = firstprinter(pp, &status);
440 		if (status)
441 			goto looperr;
442 		while (more) {
443 			putmsg(pp, argc - 2, argv + 2);
444 			do {
445 				more = nextprinter(pp, &status);
446 looperr:
447 				switch (status) {
448 				case PCAPERR_TCOPEN:
449 					printf("warning: %s: unresolved "
450 					       "tc= reference(s) ",
451 					       pp->printer);
452 				case PCAPERR_SUCCESS:
453 					break;
454 				default:
455 					fatal(pp, pcaperr(status));
456 				}
457 			} while (more && status);
458 		}
459 		return;
460 	}
461 	init_printer(pp);
462 	status = getprintcap(argv[1], pp);
463 	switch(status) {
464 	default:
465 		fatal(pp, pcaperr(status));
466 	case PCAPERR_NOTFOUND:
467 		printf("unknown printer %s\n", argv[1]);
468 		return;
469 	case PCAPERR_TCOPEN:
470 		printf("warning: %s: unresolved tc= reference(s)", argv[1]);
471 		break;
472 	case PCAPERR_SUCCESS:
473 		break;
474 	}
475 	putmsg(pp, argc - 2, argv + 2);
476 }
477 
478 static void
479 putmsg(pp, argc, argv)
480 	struct printer *pp;
481 	int argc;
482 	char **argv;
483 {
484 	register int fd;
485 	register char *cp1, *cp2;
486 	char buf[1024];
487 	char file[MAXPATHLEN];
488 	struct stat stbuf;
489 
490 	printf("%s:\n", pp->printer);
491 	/*
492 	 * Turn on the group execute bit of the lock file to disable queuing;
493 	 * turn on the owner execute bit of the lock file to disable printing.
494 	 */
495 	lock_file_name(pp, file, sizeof file);
496 	seteuid(euid);
497 	if (stat(file, &stbuf) >= 0) {
498 		if (chmod(file, stbuf.st_mode|LFM_PRINT_DIS|LFM_QUEUE_DIS) < 0)
499 			printf("\tcannot disable queuing: %s\n",
500 			       strerror(errno));
501 		else
502 			printf("\tprinter and queuing disabled\n");
503 	} else if (errno == ENOENT) {
504 		if ((fd = open(file, O_WRONLY|O_CREAT,
505 			       LOCK_FILE_MODE|LFM_PRINT_DIS|LFM_QUEUE_DIS)) < 0)
506 			printf("\tcannot create lock file: %s\n",
507 			       strerror(errno));
508 		else {
509 			(void) close(fd);
510 			printf("\tprinter and queuing disabled\n");
511 		}
512 		seteuid(uid);
513 		return;
514 	} else
515 		printf("\tcannot stat lock file\n");
516 	/*
517 	 * Write the message into the status file.
518 	 */
519 	status_file_name(pp, file, sizeof file);
520 	fd = open(file, O_WRONLY|O_CREAT|O_EXLOCK, STAT_FILE_MODE);
521 	if (fd < 0) {
522 		printf("\tcannot create status file: %s\n", strerror(errno));
523 		seteuid(uid);
524 		return;
525 	}
526 	seteuid(uid);
527 	(void) ftruncate(fd, 0);
528 	if (argc <= 0) {
529 		(void) write(fd, "\n", 1);
530 		(void) close(fd);
531 		return;
532 	}
533 	cp1 = buf;
534 	while (--argc >= 0) {
535 		cp2 = *argv++;
536 		while ((cp1 - buf) < sizeof(buf) && (*cp1++ = *cp2++))
537 			;
538 		cp1[-1] = ' ';
539 	}
540 	cp1[-1] = '\n';
541 	*cp1 = '\0';
542 	(void) write(fd, buf, strlen(buf));
543 	(void) close(fd);
544 }
545 
546 /*
547  * Exit lpc
548  */
549 void
550 quit(argc, argv)
551 	int argc;
552 	char *argv[];
553 {
554 	exit(0);
555 }
556 
557 /*
558  * Kill and restart the daemon.
559  */
560 void
561 restart(pp)
562 	struct printer *pp;
563 {
564 	abortpr(pp, 0);
565 	startpr(pp, 0);
566 }
567 
568 /*
569  * Enable printing on the specified printer and startup the daemon.
570  */
571 void
572 startcmd(pp)
573 	struct printer *pp;
574 {
575 	startpr(pp, 1);
576 }
577 
578 static void
579 startpr(pp, enable)
580 	struct printer *pp;
581 	int enable;
582 {
583 	struct stat stbuf;
584 	char lf[MAXPATHLEN];
585 
586 	lock_file_name(pp, lf, sizeof lf);
587 	printf("%s:\n", pp->printer);
588 
589 	/*
590 	 * For enable==1 ('start'), turn off the LFM_PRINT_DIS bit of the
591 	 * lock file to re-enable printing.  For enable==2 ('up'), also
592 	 * turn off the LFM_QUEUE_DIS bit to re-enable queueing.
593 	 */
594 	seteuid(euid);
595 	if (enable && stat(lf, &stbuf) >= 0) {
596 		mode_t bits = (enable == 2 ? 0 : LFM_QUEUE_DIS);
597 		if (chmod(lf, stbuf.st_mode & (LOCK_FILE_MODE | bits)) < 0)
598 			printf("\tcannot enable printing\n");
599 		else
600 			printf("\tprinting enabled\n");
601 	}
602 	if (!startdaemon(pp))
603 		printf("\tcouldn't start daemon\n");
604 	else
605 		printf("\tdaemon started\n");
606 	seteuid(uid);
607 }
608 
609 /*
610  * Print the status of the printer queue.
611  */
612 void
613 status(pp)
614 	struct printer *pp;
615 {
616 	struct stat stbuf;
617 	register int fd, i;
618 	register struct dirent *dp;
619 	DIR *dirp;
620 	char file[MAXPATHLEN];
621 
622 	printf("%s:\n", pp->printer);
623 	lock_file_name(pp, file, sizeof file);
624 	if (stat(file, &stbuf) >= 0) {
625 		printf("\tqueuing is %s\n",
626 		       ((stbuf.st_mode & LFM_QUEUE_DIS) ? "disabled"
627 			: "enabled"));
628 		printf("\tprinting is %s\n",
629 		       ((stbuf.st_mode & LFM_PRINT_DIS) ? "disabled"
630 			: "enabled"));
631 	} else {
632 		printf("\tqueuing is enabled\n");
633 		printf("\tprinting is enabled\n");
634 	}
635 	if ((dirp = opendir(pp->spool_dir)) == NULL) {
636 		printf("\tcannot examine spool directory\n");
637 		return;
638 	}
639 	i = 0;
640 	while ((dp = readdir(dirp)) != NULL) {
641 		if (*dp->d_name == 'c' && dp->d_name[1] == 'f')
642 			i++;
643 	}
644 	closedir(dirp);
645 	if (i == 0)
646 		printf("\tno entries in spool area\n");
647 	else if (i == 1)
648 		printf("\t1 entry in spool area\n");
649 	else
650 		printf("\t%d entries in spool area\n", i);
651 	fd = open(file, O_RDONLY);
652 	if (fd < 0 || flock(fd, LOCK_SH|LOCK_NB) == 0) {
653 		(void) close(fd);	/* unlocks as well */
654 		printf("\tprinter idle\n");
655 		return;
656 	}
657 	(void) close(fd);
658 	/* print out the contents of the status file, if it exists */
659 	status_file_name(pp, file, sizeof file);
660 	fd = open(file, O_RDONLY|O_SHLOCK);
661 	if (fd >= 0) {
662 		(void) fstat(fd, &stbuf);
663 		if (stbuf.st_size > 0) {
664 			putchar('\t');
665 			while ((i = read(fd, line, sizeof(line))) > 0)
666 				(void) fwrite(line, 1, i, stdout);
667 		}
668 		(void) close(fd);	/* unlocks as well */
669 	}
670 }
671 
672 /*
673  * Stop the specified daemon after completing the current job and disable
674  * printing.
675  */
676 void
677 stop(pp)
678 	struct printer *pp;
679 {
680 	register int fd;
681 	struct stat stbuf;
682 	char lf[MAXPATHLEN];
683 
684 	lock_file_name(pp, lf, sizeof lf);
685 	printf("%s:\n", pp->printer);
686 
687 	/*
688 	 * Turn on the owner execute bit of the lock file to disable printing.
689 	 */
690 	seteuid(euid);
691 	if (stat(lf, &stbuf) >= 0) {
692 		if (chmod(lf, stbuf.st_mode | LFM_PRINT_DIS) < 0)
693 			printf("\tcannot disable printing: %s\n",
694 			       strerror(errno));
695 		else {
696 			upstat(pp, "printing disabled\n");
697 			printf("\tprinting disabled\n");
698 		}
699 	} else if (errno == ENOENT) {
700 		if ((fd = open(lf, O_WRONLY|O_CREAT,
701 			       LOCK_FILE_MODE | LFM_PRINT_DIS)) < 0)
702 			printf("\tcannot create lock file: %s\n",
703 			       strerror(errno));
704 		else {
705 			(void) close(fd);
706 			upstat(pp, "printing disabled\n");
707 			printf("\tprinting disabled\n");
708 		}
709 	} else
710 		printf("\tcannot stat lock file\n");
711 	seteuid(uid);
712 }
713 
714 struct	queue **queue;
715 int	nitems;
716 time_t	mtime;
717 
718 /*
719  * Put the specified jobs at the top of printer queue.
720  */
721 void
722 topq(argc, argv)
723 	int argc;
724 	char *argv[];
725 {
726 	register int i;
727 	struct stat stbuf;
728 	int status, changed;
729 	struct printer myprinter, *pp = &myprinter;
730 
731 	if (argc < 3) {
732 		printf("Usage: topq printer [jobnum ...] [user ...]\n");
733 		return;
734 	}
735 
736 	--argc;
737 	++argv;
738 	init_printer(pp);
739 	status = getprintcap(*argv, pp);
740 	switch(status) {
741 	default:
742 		fatal(pp, pcaperr(status));
743 	case PCAPERR_NOTFOUND:
744 		printf("unknown printer %s\n", *argv);
745 		return;
746 	case PCAPERR_TCOPEN:
747 		printf("warning: %s: unresolved tc= reference(s)", *argv);
748 		break;
749 	case PCAPERR_SUCCESS:
750 		break;
751 	}
752 	printf("%s:\n", pp->printer);
753 
754 	seteuid(euid);
755 	if (chdir(pp->spool_dir) < 0) {
756 		printf("\tcannot chdir to %s\n", pp->spool_dir);
757 		goto out;
758 	}
759 	seteuid(uid);
760 	nitems = getq(pp, &queue);
761 	if (nitems == 0)
762 		return;
763 	changed = 0;
764 	mtime = queue[0]->q_time;
765 	for (i = argc; --i; ) {
766 		if (doarg(argv[i]) == 0) {
767 			printf("\tjob %s is not in the queue\n", argv[i]);
768 			continue;
769 		} else
770 			changed++;
771 	}
772 	for (i = 0; i < nitems; i++)
773 		free(queue[i]);
774 	free(queue);
775 	if (!changed) {
776 		printf("\tqueue order unchanged\n");
777 		return;
778 	}
779 	/*
780 	 * Turn on the public execute bit of the lock file to
781 	 * get lpd to rebuild the queue after the current job.
782 	 */
783 	seteuid(euid);
784 	if (changed && stat(pp->lock_file, &stbuf) >= 0)
785 		(void) chmod(pp->lock_file, stbuf.st_mode | LFM_RESET_QUE);
786 
787 out:
788 	seteuid(uid);
789 }
790 
791 /*
792  * Reposition the job by changing the modification time of
793  * the control file.
794  */
795 static int
796 touch(q)
797 	struct queue *q;
798 {
799 	struct timeval tvp[2];
800 	int ret;
801 
802 	tvp[0].tv_sec = tvp[1].tv_sec = --mtime;
803 	tvp[0].tv_usec = tvp[1].tv_usec = 0;
804 	seteuid(euid);
805 	ret = utimes(q->q_name, tvp);
806 	seteuid(uid);
807 	return (ret);
808 }
809 
810 /*
811  * Checks if specified job name is in the printer's queue.
812  * Returns:  negative (-1) if argument name is not in the queue.
813  */
814 static int
815 doarg(job)
816 	char *job;
817 {
818 	register struct queue **qq;
819 	register int jobnum, n;
820 	register char *cp, *machine;
821 	int cnt = 0;
822 	FILE *fp;
823 
824 	/*
825 	 * Look for a job item consisting of system name, colon, number
826 	 * (example: ucbarpa:114)
827 	 */
828 	if ((cp = strchr(job, ':')) != NULL) {
829 		machine = job;
830 		*cp++ = '\0';
831 		job = cp;
832 	} else
833 		machine = NULL;
834 
835 	/*
836 	 * Check for job specified by number (example: 112 or 235ucbarpa).
837 	 */
838 	if (isdigit(*job)) {
839 		jobnum = 0;
840 		do
841 			jobnum = jobnum * 10 + (*job++ - '0');
842 		while (isdigit(*job));
843 		for (qq = queue + nitems; --qq >= queue; ) {
844 			n = 0;
845 			for (cp = (*qq)->q_name+3; isdigit(*cp); )
846 				n = n * 10 + (*cp++ - '0');
847 			if (jobnum != n)
848 				continue;
849 			if (*job && strcmp(job, cp) != 0)
850 				continue;
851 			if (machine != NULL && strcmp(machine, cp) != 0)
852 				continue;
853 			if (touch(*qq) == 0) {
854 				printf("\tmoved %s\n", (*qq)->q_name);
855 				cnt++;
856 			}
857 		}
858 		return(cnt);
859 	}
860 	/*
861 	 * Process item consisting of owner's name (example: henry).
862 	 */
863 	for (qq = queue + nitems; --qq >= queue; ) {
864 		seteuid(euid);
865 		fp = fopen((*qq)->q_name, "r");
866 		seteuid(uid);
867 		if (fp == NULL)
868 			continue;
869 		while (getline(fp) > 0)
870 			if (line[0] == 'P')
871 				break;
872 		(void) fclose(fp);
873 		if (line[0] != 'P' || strcmp(job, line+1) != 0)
874 			continue;
875 		if (touch(*qq) == 0) {
876 			printf("\tmoved %s\n", (*qq)->q_name);
877 			cnt++;
878 		}
879 	}
880 	return(cnt);
881 }
882 
883 /*
884  * Enable everything and start printer (undo `down').
885  */
886 void
887 up(pp)
888 	struct printer *pp;
889 {
890 	startpr(pp, 2);
891 }
892