cmds.c revision 39084
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
36static 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/*
43static char sccsid[] = "@(#)cmds.c	8.2 (Berkeley) 4/28/95";
44*/
45static const char rcsid[] =
46	"$Id: cmds.c,v 1.11 1997/12/02 20:45:37 wollman Exp $";
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
73static void	abortpr __P((struct printer *, int));
74static int	doarg __P((char *));
75static int	doselect __P((struct dirent *));
76static void	putmsg __P((struct printer *, int, char **));
77static int	sortq __P((const void *, const void *));
78static void	startpr __P((struct printer *, int));
79static int	touch __P((struct queue *));
80static void	unlinkf __P((char *));
81static 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 */
87void
88generic(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);
108looperr:
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 */
147void
148doabort(pp)
149	struct printer *pp;
150{
151	abortpr(pp, 1);
152}
153
154static void
155abortpr(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);
217out:
218	seteuid(uid);
219}
220
221/*
222 * Write a message into the status file.
223 */
224static void
225upstat(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
247static int
248doselect(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 */
262static int
263sortq(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 */
289void
290clean(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
347static void
348unlinkf(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 */
362void
363enable(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 */
388void
389disable(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 */
426void
427down(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);
446looperr:
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
478static void
479putmsg(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 */
549void
550quit(argc, argv)
551	int argc;
552	char *argv[];
553{
554	exit(0);
555}
556
557/*
558 * Kill and restart the daemon.
559 */
560void
561restart(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 */
571void
572startcmd(pp)
573	struct printer *pp;
574{
575	startpr(pp, 1);
576}
577
578static void
579startpr(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	 * Turn off the owner execute bit of the lock file to enable printing.
591	 */
592	seteuid(euid);
593	if (enable && stat(lf, &stbuf) >= 0) {
594		mode_t bits = (enable == 2 ? 0
595			       : (LFM_PRINT_DIS | LFM_QUEUE_DIS));
596		if (chmod(lf, stbuf.st_mode & (LOCK_FILE_MODE | bits)) < 0)
597			printf("\tcannot enable printing\n");
598		else
599			printf("\tprinting enabled\n");
600	}
601	if (!startdaemon(pp))
602		printf("\tcouldn't start daemon\n");
603	else
604		printf("\tdaemon started\n");
605	seteuid(uid);
606}
607
608/*
609 * Print the status of the printer queue.
610 */
611void
612status(pp)
613	struct printer *pp;
614{
615	struct stat stbuf;
616	register int fd, i;
617	register struct dirent *dp;
618	DIR *dirp;
619	char file[MAXPATHLEN];
620
621	printf("%s:\n", pp->printer);
622	lock_file_name(pp, file, sizeof file);
623	if (stat(file, &stbuf) >= 0) {
624		printf("\tqueuing is %s\n",
625		       ((stbuf.st_mode & LFM_QUEUE_DIS) ? "disabled"
626			: "enabled"));
627		printf("\tprinting is %s\n",
628		       ((stbuf.st_mode & LFM_PRINT_DIS) ? "disabled"
629			: "enabled"));
630	} else {
631		printf("\tqueuing is enabled\n");
632		printf("\tprinting is enabled\n");
633	}
634	if ((dirp = opendir(pp->spool_dir)) == NULL) {
635		printf("\tcannot examine spool directory\n");
636		return;
637	}
638	i = 0;
639	while ((dp = readdir(dirp)) != NULL) {
640		if (*dp->d_name == 'c' && dp->d_name[1] == 'f')
641			i++;
642	}
643	closedir(dirp);
644	if (i == 0)
645		printf("\tno entries in spool area\n");
646	else if (i == 1)
647		printf("\t1 entry in spool area\n");
648	else
649		printf("\t%d entries in spool area\n", i);
650	fd = open(file, O_RDONLY);
651	if (fd < 0 || flock(fd, LOCK_SH|LOCK_NB) == 0) {
652		(void) close(fd);	/* unlocks as well */
653		printf("\tprinter idle\n");
654		return;
655	}
656	(void) close(fd);
657	/* print out the contents of the status file, if it exists */
658	status_file_name(pp, file, sizeof file);
659	fd = open(file, O_RDONLY|O_SHLOCK);
660	if (fd >= 0) {
661		(void) fstat(fd, &stbuf);
662		if (stbuf.st_size > 0) {
663			putchar('\t');
664			while ((i = read(fd, line, sizeof(line))) > 0)
665				(void) fwrite(line, 1, i, stdout);
666		}
667		(void) close(fd);	/* unlocks as well */
668	}
669}
670
671/*
672 * Stop the specified daemon after completing the current job and disable
673 * printing.
674 */
675void
676stop(pp)
677	struct printer *pp;
678{
679	register int fd;
680	struct stat stbuf;
681	char lf[MAXPATHLEN];
682
683	lock_file_name(pp, lf, sizeof lf);
684	printf("%s:\n", pp->printer);
685
686	/*
687	 * Turn on the owner execute bit of the lock file to disable printing.
688	 */
689	seteuid(euid);
690	if (stat(lf, &stbuf) >= 0) {
691		if (chmod(lf, stbuf.st_mode | LFM_PRINT_DIS) < 0)
692			printf("\tcannot disable printing: %s\n",
693			       strerror(errno));
694		else {
695			upstat(pp, "printing disabled\n");
696			printf("\tprinting disabled\n");
697		}
698	} else if (errno == ENOENT) {
699		if ((fd = open(lf, O_WRONLY|O_CREAT,
700			       LOCK_FILE_MODE | LFM_PRINT_DIS)) < 0)
701			printf("\tcannot create lock file: %s\n",
702			       strerror(errno));
703		else {
704			(void) close(fd);
705			upstat(pp, "printing disabled\n");
706			printf("\tprinting disabled\n");
707		}
708	} else
709		printf("\tcannot stat lock file\n");
710	seteuid(uid);
711}
712
713struct	queue **queue;
714int	nitems;
715time_t	mtime;
716
717/*
718 * Put the specified jobs at the top of printer queue.
719 */
720void
721topq(argc, argv)
722	int argc;
723	char *argv[];
724{
725	register int i;
726	struct stat stbuf;
727	int status, changed;
728	struct printer myprinter, *pp = &myprinter;
729
730	if (argc < 3) {
731		printf("Usage: topq printer [jobnum ...] [user ...]\n");
732		return;
733	}
734
735	--argc;
736	++argv;
737	init_printer(pp);
738	status = getprintcap(*argv, pp);
739	switch(status) {
740	default:
741		fatal(pp, pcaperr(status));
742	case PCAPERR_NOTFOUND:
743		printf("unknown printer %s\n", *argv);
744		return;
745	case PCAPERR_TCOPEN:
746		printf("warning: %s: unresolved tc= reference(s)", *argv);
747		break;
748	case PCAPERR_SUCCESS:
749		break;
750	}
751	printf("%s:\n", pp->printer);
752
753	seteuid(euid);
754	if (chdir(pp->spool_dir) < 0) {
755		printf("\tcannot chdir to %s\n", pp->spool_dir);
756		goto out;
757	}
758	seteuid(uid);
759	nitems = getq(pp, &queue);
760	if (nitems == 0)
761		return;
762	changed = 0;
763	mtime = queue[0]->q_time;
764	for (i = argc; --i; ) {
765		if (doarg(argv[i]) == 0) {
766			printf("\tjob %s is not in the queue\n", argv[i]);
767			continue;
768		} else
769			changed++;
770	}
771	for (i = 0; i < nitems; i++)
772		free(queue[i]);
773	free(queue);
774	if (!changed) {
775		printf("\tqueue order unchanged\n");
776		return;
777	}
778	/*
779	 * Turn on the public execute bit of the lock file to
780	 * get lpd to rebuild the queue after the current job.
781	 */
782	seteuid(euid);
783	if (changed && stat(pp->lock_file, &stbuf) >= 0)
784		(void) chmod(pp->lock_file, stbuf.st_mode | LFM_RESET_QUE);
785
786out:
787	seteuid(uid);
788}
789
790/*
791 * Reposition the job by changing the modification time of
792 * the control file.
793 */
794static int
795touch(q)
796	struct queue *q;
797{
798	struct timeval tvp[2];
799	int ret;
800
801	tvp[0].tv_sec = tvp[1].tv_sec = --mtime;
802	tvp[0].tv_usec = tvp[1].tv_usec = 0;
803	seteuid(euid);
804	ret = utimes(q->q_name, tvp);
805	seteuid(uid);
806	return (ret);
807}
808
809/*
810 * Checks if specified job name is in the printer's queue.
811 * Returns:  negative (-1) if argument name is not in the queue.
812 */
813static int
814doarg(job)
815	char *job;
816{
817	register struct queue **qq;
818	register int jobnum, n;
819	register char *cp, *machine;
820	int cnt = 0;
821	FILE *fp;
822
823	/*
824	 * Look for a job item consisting of system name, colon, number
825	 * (example: ucbarpa:114)
826	 */
827	if ((cp = strchr(job, ':')) != NULL) {
828		machine = job;
829		*cp++ = '\0';
830		job = cp;
831	} else
832		machine = NULL;
833
834	/*
835	 * Check for job specified by number (example: 112 or 235ucbarpa).
836	 */
837	if (isdigit(*job)) {
838		jobnum = 0;
839		do
840			jobnum = jobnum * 10 + (*job++ - '0');
841		while (isdigit(*job));
842		for (qq = queue + nitems; --qq >= queue; ) {
843			n = 0;
844			for (cp = (*qq)->q_name+3; isdigit(*cp); )
845				n = n * 10 + (*cp++ - '0');
846			if (jobnum != n)
847				continue;
848			if (*job && strcmp(job, cp) != 0)
849				continue;
850			if (machine != NULL && strcmp(machine, cp) != 0)
851				continue;
852			if (touch(*qq) == 0) {
853				printf("\tmoved %s\n", (*qq)->q_name);
854				cnt++;
855			}
856		}
857		return(cnt);
858	}
859	/*
860	 * Process item consisting of owner's name (example: henry).
861	 */
862	for (qq = queue + nitems; --qq >= queue; ) {
863		seteuid(euid);
864		fp = fopen((*qq)->q_name, "r");
865		seteuid(uid);
866		if (fp == NULL)
867			continue;
868		while (getline(fp) > 0)
869			if (line[0] == 'P')
870				break;
871		(void) fclose(fp);
872		if (line[0] != 'P' || strcmp(job, line+1) != 0)
873			continue;
874		if (touch(*qq) == 0) {
875			printf("\tmoved %s\n", (*qq)->q_name);
876			cnt++;
877		}
878	}
879	return(cnt);
880}
881
882/*
883 * Enable everything and start printer (undo `down').
884 */
885void
886up(pp)
887	struct printer *pp;
888{
889	startpr(pp, 2);
890}
891