cmds.c revision 98267
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  "$FreeBSD: head/usr.sbin/lpr/lpc/cmds.c 98267 2002-06-15 22:51:58Z gad $";
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/*
74 * Return values from kill_qtask().
75 */
76#define KQT_LFERROR	-2
77#define KQT_KILLFAIL	-1
78#define KQT_NODAEMON	0
79#define KQT_KILLOK	1
80
81static void	 abortpr(struct printer *_pp, int _dis);
82static char	*args2line(int argc, char **argv);
83static int	 doarg(char *_job);
84static int	 doselect(struct dirent *_d);
85static int	 kill_qtask(const char *lf);
86static void	 putmsg(struct printer *_pp, int _argc, char **_argv);
87static int	 sortq(const void *_a, const void *_b);
88static void	 startpr(struct printer *_pp, int _chgenable);
89static int	 touch(struct jobqueue *_jq);
90static void	 unlinkf(char *_name);
91static void	 upstat(struct printer *_pp, const char *_msg, int _notify);
92static void	 wrapup_clean(int _laststatus);
93
94/*
95 * generic framework for commands which operate on all or a specified
96 * set of printers
97 */
98enum	qsel_val {			/* how a given ptr was selected */
99	QSEL_UNKNOWN = -1,		/* ... not selected yet */
100	QSEL_BYNAME = 0,		/* ... user specifed it by name */
101	QSEL_ALL = 1			/* ... user wants "all" printers */
102					/*     (with more to come)    */
103};
104
105static enum qsel_val generic_qselect;	/* indicates how ptr was selected */
106static int generic_initerr;		/* result of initrtn processing */
107static char *generic_msg;		/* if a -msg was specified */
108static char *generic_nullarg;
109static void (*generic_wrapup)(int _last_status);   /* perform rtn wrap-up */
110
111void
112generic(void (*specificrtn)(struct printer *_pp), int cmdopts,
113    void (*initrtn)(int _argc, char *_argv[]), int argc, char *argv[])
114{
115	int cmdstatus, more, targc;
116	struct printer myprinter, *pp;
117	char **targv;
118
119	if (argc == 1) {
120		printf("usage: %s  {all | printer ...}", argv[0]);
121		if (cmdopts & LPC_MSGOPT)
122			printf(" [-msg <text> ...]");
123		printf("\n");
124		return;
125	}
126
127	/*
128	 * The initialization routine for a command might set a generic
129	 * "wrapup" routine, which should be called after processing all
130	 * the printers in the command.  This might print summary info.
131	 *
132	 * Note that the initialization routine may also parse (and
133	 * nullify) some of the parameters given on the command, leaving
134	 * only the parameters which have to do with printer names.
135	 */
136	pp = &myprinter;
137	generic_wrapup = NULL;
138	generic_qselect = QSEL_UNKNOWN;
139	cmdstatus = 0;
140	/* this just needs to be a distinct value of type 'char *' */
141	if (generic_nullarg == NULL)
142		generic_nullarg = strdup("");
143
144	/*
145	 * Some commands accept a -msg argument, which indicates that
146	 * all remaining arguments should be combined into a string.
147	 */
148	generic_msg = NULL;
149	if (cmdopts & LPC_MSGOPT) {
150		targc = argc;
151		targv = argv;
152		while (--targc) {
153			++targv;
154			if (strcmp(*targv, "-msg") == 0) {
155				argc -= targc;
156				generic_msg = args2line(targc - 1, targv + 1);
157				break;
158			}
159		}
160	}
161
162	/* call initialization routine, if there is one for this cmd */
163	if (initrtn != NULL) {
164		generic_initerr = 0;
165		(*initrtn)(argc, argv);
166		if (generic_initerr)
167			return;
168		/* skip any initial arguments null-ified by initrtn */
169		targc = argc;
170		targv = argv;
171		while (--targc) {
172			if (targv[1] != generic_nullarg)
173				break;
174			++targv;
175		}
176		if (targv != argv) {
177			targv[0] = argv[0];	/* copy the command-name */
178			argv = targv;
179			argc = targc + 1;
180		}
181	}
182
183	if (argc == 2 && strcmp(argv[1], "all") == 0) {
184		generic_qselect = QSEL_ALL;
185		more = firstprinter(pp, &cmdstatus);
186		if (cmdstatus)
187			goto looperr;
188		while (more) {
189			(*specificrtn)(pp);
190			do {
191				more = nextprinter(pp, &cmdstatus);
192looperr:
193				switch (cmdstatus) {
194				case PCAPERR_TCOPEN:
195					printf("warning: %s: unresolved "
196					       "tc= reference(s) ",
197					       pp->printer);
198				case PCAPERR_SUCCESS:
199					break;
200				default:
201					fatal(pp, "%s", pcaperr(cmdstatus));
202				}
203			} while (more && cmdstatus);
204		}
205		goto wrapup;
206	}
207
208	generic_qselect = QSEL_BYNAME;		/* specifically-named ptrs */
209	while (--argc) {
210		++argv;
211		if (*argv == generic_nullarg)
212			continue;
213		init_printer(pp);
214		cmdstatus = getprintcap(*argv, pp);
215		switch (cmdstatus) {
216		default:
217			fatal(pp, "%s", pcaperr(cmdstatus));
218		case PCAPERR_NOTFOUND:
219			printf("unknown printer %s\n", *argv);
220			continue;
221		case PCAPERR_TCOPEN:
222			printf("warning: %s: unresolved tc= reference(s)\n",
223			       *argv);
224			break;
225		case PCAPERR_SUCCESS:
226			break;
227		}
228		(*specificrtn)(pp);
229	}
230
231wrapup:
232	if (generic_wrapup) {
233		(*generic_wrapup)(cmdstatus);
234	}
235	if (generic_msg)
236		free(generic_msg);
237}
238
239/*
240 * Convert an argv-array of character strings into a single string.
241 */
242static char *
243args2line(int argc, char **argv)
244{
245	char *cp1, *cend;
246	const char *cp2;
247	char buf[1024];
248
249	if (argc <= 0)
250		return strdup("\n");
251
252	cp1 = buf;
253	cend = buf + sizeof(buf) - 1;		/* save room for '\0' */
254	while (--argc >= 0) {
255		cp2 = *argv++;
256		while ((cp1 < cend) && (*cp1++ = *cp2++))
257			;
258		cp1[-1] = ' ';
259	}
260	cp1[-1] = '\n';
261	*cp1 = '\0';
262	return strdup(buf);
263}
264
265/*
266 * kill an existing daemon and disable printing.
267 */
268void
269doabort(struct printer *pp)
270{
271	abortpr(pp, 1);
272}
273
274static void
275abortpr(struct printer *pp, int dis)
276{
277	register FILE *fp;
278	struct stat stbuf;
279	int pid, fd;
280	char lf[MAXPATHLEN];
281
282	lock_file_name(pp, lf, sizeof lf);
283	printf("%s:\n", pp->printer);
284
285	/*
286	 * Turn on the owner execute bit of the lock file to disable printing.
287	 */
288	if (dis) {
289		seteuid(euid);
290		if (stat(lf, &stbuf) >= 0) {
291			if (chmod(lf, stbuf.st_mode | LFM_PRINT_DIS) < 0)
292				printf("\tcannot disable printing: %s\n",
293				       strerror(errno));
294			else {
295				/* ..call newer upstat() in obsolete code.. */
296				upstat(pp, "printing disabled\n", 0);
297				/* ..the new upstat() did a setuid(uid).. */
298				seteuid(euid);
299				printf("\tprinting disabled\n");
300			}
301		} else if (errno == ENOENT) {
302			if ((fd = open(lf, O_WRONLY|O_CREAT,
303				       LOCK_FILE_MODE | LFM_PRINT_DIS)) < 0)
304				printf("\tcannot create lock file: %s\n",
305				       strerror(errno));
306			else {
307				(void) close(fd);
308				/* ..call newer upstat() in obsolete code.. */
309				upstat(pp, "printing disabled\n", 0);
310				/* ..the new upstat() did a setuid(uid).. */
311				seteuid(euid);
312				printf("\tprinting disabled\n");
313				printf("\tno daemon to abort\n");
314			}
315			goto out;
316		} else {
317			printf("\tcannot stat lock file\n");
318			goto out;
319		}
320	}
321	/*
322	 * Kill the current daemon to stop printing now.
323	 */
324	if ((fp = fopen(lf, "r")) == NULL) {
325		printf("\tcannot open lock file\n");
326		goto out;
327	}
328	if (!getline(fp) || flock(fileno(fp), LOCK_SH|LOCK_NB) == 0) {
329		(void) fclose(fp);	/* unlocks as well */
330		printf("\tno daemon to abort\n");
331		goto out;
332	}
333	(void) fclose(fp);
334	if (kill(pid = atoi(line), SIGTERM) < 0) {
335		if (errno == ESRCH)
336			printf("\tno daemon to abort\n");
337		else
338			printf("\tWarning: daemon (pid %d) not killed\n", pid);
339	} else
340		printf("\tdaemon (pid %d) killed\n", pid);
341out:
342	seteuid(uid);
343}
344
345/*
346 * Kill the current daemon, to stop printing of the active job.
347 */
348static int
349kill_qtask(const char *lf)
350{
351	FILE *fp;
352	pid_t pid;
353	int errsav, killres, lockres, res;
354
355	seteuid(euid);
356	fp = fopen(lf, "r");
357	errsav = errno;
358	seteuid(uid);
359	res = KQT_NODAEMON;
360	if (fp == NULL) {
361		/*
362		 * If there is no lock file, then there is no daemon to
363		 * kill.  Any other error return means there is some
364		 * kind of problem with the lock file.
365		 */
366		if (errsav != ENOENT)
367			res = KQT_LFERROR;
368		goto killdone;
369	}
370
371	/* If the lock file is empty, then there is no daemon to kill */
372	if (getline(fp) == 0)
373		goto killdone;
374
375	/*
376	 * If the file can be locked without blocking, then there
377	 * no daemon to kill, or we should not try to kill it.
378	 *
379	 * XXX - not sure I understand the reasoning behind this...
380	 */
381	lockres = flock(fileno(fp), LOCK_SH|LOCK_NB);
382	(void) fclose(fp);
383	if (lockres == 0)
384		goto killdone;
385
386	pid = atoi(line);
387	if (pid < 0) {
388		/*
389		 * If we got a negative pid, then the contents of the
390		 * lock file is not valid.
391		 */
392		res = KQT_LFERROR;
393		goto killdone;
394	}
395
396	seteuid(uid);
397	killres = kill(pid, SIGTERM);
398	errsav = errno;
399	seteuid(uid);
400	if (killres == 0) {
401		res = KQT_KILLOK;
402		printf("\tdaemon (pid %d) killed\n", pid);
403	} else if (errno == ESRCH) {
404		res = KQT_NODAEMON;
405	} else {
406		res = KQT_KILLFAIL;
407		printf("\tWarning: daemon (pid %d) not killed:\n", pid);
408		printf("\t    %s\n", strerror(errsav));
409	}
410
411killdone:
412	switch (res) {
413	case KQT_LFERROR:
414		printf("\tcannot open lock file: %s\n",
415		    strerror(errsav));
416		break;
417	case KQT_NODAEMON:
418		printf("\tno daemon to abort\n");
419		break;
420	case KQT_KILLFAIL:
421	case KQT_KILLOK:
422		/* These two already printed messages to the user. */
423		break;
424	default:
425		printf("\t<internal error in kill_qtask>\n");
426		break;
427	}
428
429	return (res);
430}
431
432/*
433 * Write a message into the status file.
434 */
435static void
436upstat(struct printer *pp, const char *msg, int notifyuser)
437{
438	int fd;
439	char statfile[MAXPATHLEN];
440
441	status_file_name(pp, statfile, sizeof statfile);
442	umask(0);
443	seteuid(euid);
444	fd = open(statfile, O_WRONLY|O_CREAT|O_EXLOCK, STAT_FILE_MODE);
445	seteuid(uid);
446	if (fd < 0) {
447		printf("\tcannot create status file: %s\n", strerror(errno));
448		return;
449	}
450	(void) ftruncate(fd, 0);
451	if (msg == (char *)NULL)
452		(void) write(fd, "\n", 1);
453	else
454		(void) write(fd, msg, strlen(msg));
455	(void) close(fd);
456	if (notifyuser) {
457		if ((msg == (char *)NULL) || (strcmp(msg, "\n") == 0))
458			printf("\tstatus message is now set to nothing.\n");
459		else
460			printf("\tstatus message is now: %s", msg);
461	}
462}
463
464/*
465 * kill an existing daemon and disable printing.
466 */
467void
468abort_q(struct printer *pp)
469{
470	int killres, setres;
471	char lf[MAXPATHLEN];
472
473	lock_file_name(pp, lf, sizeof lf);
474	printf("%s:\n", pp->printer);
475
476	/*
477	 * Turn on the owner execute bit of the lock file to disable printing.
478	 */
479	setres = set_qstate(SQS_STOPP, lf);
480
481	/*
482	 * If set_qstate found that there already was a lock file, then
483	 * call a routine which will read that lock file and kill the
484	 * lpd-process which is listed in that lock file.  If the lock
485	 * file did not exist, then either there is no daemon running
486	 * for this queue, or there is one running but *it* could not
487	 * write a lock file (which means we can not determine the
488	 * process id of that lpd-process).
489	 */
490	switch (setres) {
491	case SQS_CHGOK:
492	case SQS_CHGFAIL:
493		/* Kill the process */
494		killres = kill_qtask(lf);
495		break;
496	case SQS_CREOK:
497	case SQS_CREFAIL:
498		printf("\tno daemon to abort\n");
499		break;
500	case SQS_STATFAIL:
501		printf("\tassuming no daemon to abort\n");
502		break;
503	default:
504		printf("\t<unexpected result (%d) from set_qstate>\n",
505		    setres);
506		break;
507	}
508
509	if (setres >= 0)
510		upstat(pp, "printing disabled\n", 0);
511}
512
513/*
514 * "global" variables for all the routines related to 'clean' and 'tclean'
515 */
516static time_t	 cln_now;		/* current time */
517static double	 cln_minage;		/* minimum age before file is removed */
518static long	 cln_sizecnt;		/* amount of space freed up */
519static int 	 cln_debug;		/* print extra debugging msgs */
520static int	 cln_filecnt;		/* number of files destroyed */
521static int	 cln_foundcore;		/* found a core file! */
522static int	 cln_queuecnt;		/* number of queues checked */
523static int 	 cln_testonly;		/* remove-files vs just-print-info */
524
525static int
526doselect(struct dirent *d)
527{
528	int c = d->d_name[0];
529
530	if ((c == 'c' || c == 'd' || c == 'r' || c == 't') &&
531	    d->d_name[1] == 'f')
532		return 1;
533	if (c == 'c') {
534		if (!strcmp(d->d_name, "core"))
535			cln_foundcore = 1;
536	}
537	if (c == 'e') {
538		if (!strncmp(d->d_name, "errs.", 5))
539			return 1;
540	}
541	return 0;
542}
543
544/*
545 * Comparison routine that clean_q() uses for scandir.
546 *
547 * The purpose of this sort is to have all `df' files end up immediately
548 * after the matching `cf' file.  For files matching `cf', `df', `rf', or
549 * `tf', it sorts by job number and machine, then by `cf', `df', `rf', or
550 * `tf', and then by the sequence letter (which is A-Z, or a-z).    This
551 * routine may also see filenames which do not start with `cf', `df', `rf',
552 * or `tf' (such as `errs.*'), and those are simply sorted by the full
553 * filename.
554 *
555 * XXX
556 *   This assumes that all control files start with `cfA*', and it turns
557 *   out there are a few implementations of lpr which will create `cfB*'
558 *   filenames (they will have datafile names which start with `dfB*').
559 */
560static int
561sortq(const void *a, const void *b)
562{
563	const int a_lt_b = -1, a_gt_b = 1, cat_other = 10;
564	const char *fname_a, *fname_b, *jnum_a, *jnum_b;
565	int cat_a, cat_b, ch, res, seq_a, seq_b;
566
567	fname_a = (*(const struct dirent * const *)a)->d_name;
568	fname_b = (*(const struct dirent * const *)b)->d_name;
569
570	/*
571	 * First separate filenames into cagatories.  Catagories are
572	 * legitimate `cf', `df', `rf' & `tf' filenames, and "other" - in
573	 * that order.  It is critical that the mapping be exactly the
574	 * same for 'a' vs 'b', so define a macro for the job.
575	 *
576	 * [aside: the standard `cf' file has the jobnumber start in
577	 * position 4, but some implementations have that as an extra
578	 * file-sequence letter, and start the job number in position 5.]
579	 */
580#define MAP_TO_CAT(fname_X,cat_X,jnum_X,seq_X) do { \
581	cat_X = cat_other;    \
582	ch = *(fname_X + 2);  \
583	jnum_X = fname_X + 3; \
584	seq_X = 0;            \
585	if ((*(fname_X + 1) == 'f') && (isalpha(ch))) { \
586		seq_X = ch; \
587		if (*fname_X == 'c') \
588			cat_X = 1; \
589		else if (*fname_X == 'd') \
590			cat_X = 2; \
591		else if (*fname_X == 'r') \
592			cat_X = 3; \
593		else if (*fname_X == 't') \
594			cat_X = 4; \
595		if (cat_X != cat_other) { \
596			ch = *jnum_X; \
597			if (!isdigit(ch)) { \
598				if (isalpha(ch)) { \
599					jnum_X++; \
600					ch = *jnum_X; \
601					seq_X = (seq_X << 8) + ch; \
602				} \
603				if (!isdigit(ch)) \
604					cat_X = cat_other; \
605			} \
606		} \
607	} \
608} while (0)
609
610	MAP_TO_CAT(fname_a, cat_a, jnum_a, seq_a);
611	MAP_TO_CAT(fname_b, cat_b, jnum_b, seq_b);
612
613#undef MAP_TO_CAT
614
615	/* First handle all cases which have "other" files */
616	if ((cat_a >= cat_other) || (cat_b >= cat_other)) {
617		/* for two "other" files, just compare the full name */
618		if (cat_a == cat_b)
619			res = strcmp(fname_a, fname_b);
620		else if (cat_a < cat_b)
621			res = a_lt_b;
622		else
623			res = a_gt_b;
624		goto have_res;
625	}
626
627	/*
628	 * At this point, we know both files are legitimate `cf', `df', `rf',
629	 * or `tf' files.  Compare them by job-number and machine name.
630	 */
631	res = strcmp(jnum_a, jnum_b);
632	if (res != 0)
633		goto have_res;
634
635	/*
636	 * We have two files which belong to the same job.  Sort based
637	 * on the catagory of file (`c' before `d', etc).
638	 */
639	if (cat_a < cat_b) {
640		res = a_lt_b;
641		goto have_res;
642	} else if (cat_a > cat_b) {
643		res = a_gt_b;
644		goto have_res;
645	}
646
647	/*
648	 * Two files in the same catagory for a single job.  Sort based
649	 * on the sequence letter(s).  (usually `A' thru `Z', etc).
650	 */
651	if (seq_a < seq_b) {
652		res = a_lt_b;
653		goto have_res;
654	} else if (seq_a > seq_b) {
655		res = a_gt_b;
656		goto have_res;
657	}
658
659	/*
660	 * Given that the filenames in a directory are unique, this SHOULD
661	 * never happen (unless there are logic errors in this routine).
662	 * But if it does happen, we must return "is equal" or the caller
663	 * might see inconsistent results in the sorting order, and that
664	 * can trigger other problems.
665	 */
666	printf("\t*** Error in sortq: %s == %s !\n", fname_a, fname_b);
667	printf("\t***       cat %d == %d ; seq = %d %d\n", cat_a, cat_b,
668	    seq_a, seq_b);
669	res = 0;
670
671have_res:
672	return res;
673}
674
675/*
676 * Remove all spool files and temporaries from the spooling area.
677 * Or, perhaps:
678 * Remove incomplete jobs from spooling area.
679 */
680
681void
682init_clean(int argc, char *argv[])
683{
684
685	/* init some fields before 'clean' is called for each queue */
686	cln_queuecnt = 0;
687	cln_now = time(NULL);
688	cln_minage = 3600.0;		/* only delete files >1h old */
689	cln_filecnt = 0;
690	cln_sizecnt = 0;
691	cln_debug = 0;
692	cln_testonly = 0;
693	generic_wrapup = &wrapup_clean;
694
695	/* see if there are any options specified before the ptr list */
696	while (--argc) {
697		++argv;
698		if (**argv != '-')
699			break;
700		if (strcmp(*argv, "-d") == 0) {
701			/* just an example of an option... */
702			cln_debug++;
703			*argv = generic_nullarg;	/* "erase" it */
704		} else {
705			printf("Invalid option '%s'\n", *argv);
706			generic_initerr = 1;
707		}
708	}
709
710	return;
711}
712
713void
714init_tclean(int argc, char *argv[])
715{
716
717	/* only difference between 'clean' and 'tclean' is one value */
718	/* (...and the fact that 'clean' is priv and 'tclean' is not) */
719	init_clean(argc, argv);
720	cln_testonly = 1;
721
722	return;
723}
724
725void
726clean_q(struct printer *pp)
727{
728	char *cp, *cp1, *lp;
729	struct dirent **queue;
730	size_t linerem;
731	int didhead, i, n, nitems, rmcp;
732
733	cln_queuecnt++;
734
735	didhead = 0;
736	if (generic_qselect == QSEL_BYNAME) {
737		printf("%s:\n", pp->printer);
738		didhead = 1;
739	}
740
741	lp = line;
742	cp = pp->spool_dir;
743	while (lp < &line[sizeof(line) - 1]) {
744		if ((*lp++ = *cp++) == 0)
745			break;
746	}
747	lp[-1] = '/';
748	linerem = sizeof(line) - (lp - line);
749
750	cln_foundcore = 0;
751	seteuid(euid);
752	nitems = scandir(pp->spool_dir, &queue, doselect, sortq);
753	seteuid(uid);
754	if (nitems < 0) {
755		if (!didhead) {
756			printf("%s:\n", pp->printer);
757			didhead = 1;
758		}
759		printf("\tcannot examine spool directory\n");
760		return;
761	}
762	if (cln_foundcore) {
763		if (!didhead) {
764			printf("%s:\n", pp->printer);
765			didhead = 1;
766		}
767		printf("\t** found a core file in %s !\n", pp->spool_dir);
768	}
769	if (nitems == 0)
770		return;
771	if (!didhead)
772		printf("%s:\n", pp->printer);
773	if (cln_debug) {
774		printf("\t** ----- Sorted list of files being checked:\n");
775		i = 0;
776		do {
777			cp = queue[i]->d_name;
778			printf("\t** [%3d] = %s\n", i, cp);
779		} while (++i < nitems);
780		printf("\t** ----- end of sorted list\n");
781	}
782	i = 0;
783	do {
784		cp = queue[i]->d_name;
785		rmcp = 0;
786		if (*cp == 'c') {
787			/*
788			 * A control file.  Look for matching data-files.
789			 */
790			/* XXX
791			 *  Note the logic here assumes that the hostname
792			 *  part of cf-filenames match the hostname part
793			 *  in df-filenames, and that is not necessarily
794			 *  true (eg: for multi-homed hosts).  This needs
795			 *  some further thought...
796			 */
797			n = 0;
798			while (i + 1 < nitems) {
799				cp1 = queue[i + 1]->d_name;
800				if (*cp1 != 'd' || strcmp(cp + 3, cp1 + 3))
801					break;
802				i++;
803				n++;
804			}
805			if (n == 0) {
806				rmcp = 1;
807			}
808		} else if (*cp == 'e') {
809			/*
810			 * Must be an errrs or email temp file.
811			 */
812			rmcp = 1;
813		} else {
814			/*
815			 * Must be a df with no cf (otherwise, it would have
816			 * been skipped above) or an rf or tf file (which can
817			 * always be removed if it is old enough).
818			 */
819			rmcp = 1;
820		}
821		if (rmcp) {
822			if (strlen(cp) >= linerem) {
823				printf("\t** internal error: 'line' overflow!\n");
824				printf("\t**   spooldir = %s\n", pp->spool_dir);
825				printf("\t**   cp = %s\n", cp);
826				return;
827			}
828			strlcpy(lp, cp, linerem);
829			unlinkf(line);
830		}
831     	} while (++i < nitems);
832}
833
834static void
835wrapup_clean(int laststatus __unused)
836{
837
838	printf("Checked %d queues, and ", cln_queuecnt);
839	if (cln_filecnt < 1) {
840		printf("no cruft was found\n");
841		return;
842	}
843	if (cln_testonly) {
844		printf("would have ");
845	}
846	printf("removed %d files (%ld bytes).\n", cln_filecnt, cln_sizecnt);
847}
848
849static void
850unlinkf(char *name)
851{
852	struct stat stbuf;
853	double agemod, agestat;
854	int res;
855	char linkbuf[BUFSIZ];
856
857	/*
858	 * We have to use lstat() instead of stat(), in case this is a df*
859	 * "file" which is really a symlink due to 'lpr -s' processing.  In
860	 * that case, we need to check the last-mod time of the symlink, and
861	 * not the file that the symlink is pointed at.
862	 */
863	seteuid(euid);
864	res = lstat(name, &stbuf);
865	seteuid(uid);
866	if (res < 0) {
867		printf("\terror return from stat(%s):\n", name);
868		printf("\t      %s\n", strerror(errno));
869		return;
870	}
871
872	agemod = difftime(cln_now, stbuf.st_mtime);
873	agestat = difftime(cln_now,  stbuf.st_ctime);
874	if (cln_debug > 1) {
875		/* this debugging-aid probably is not needed any more... */
876		printf("\t\t  modify age=%g secs, stat age=%g secs\n",
877		    agemod, agestat);
878	}
879	if ((agemod <= cln_minage) && (agestat <= cln_minage))
880		return;
881
882	/*
883	 * if this file is a symlink, then find out the target of the
884	 * symlink before unlink-ing the file itself
885	 */
886	if (S_ISLNK(stbuf.st_mode)) {
887		seteuid(euid);
888		res = readlink(name, linkbuf, sizeof(linkbuf));
889		seteuid(uid);
890		if (res < 0) {
891			printf("\terror return from readlink(%s):\n", name);
892			printf("\t      %s\n", strerror(errno));
893			return;
894		}
895		if (res == sizeof(linkbuf))
896			res--;
897		linkbuf[res] = '\0';
898	}
899
900	cln_filecnt++;
901	cln_sizecnt += stbuf.st_size;
902
903	if (cln_testonly) {
904		printf("\twould remove %s\n", name);
905		if (S_ISLNK(stbuf.st_mode)) {
906			printf("\t    (which is a symlink to %s)\n", linkbuf);
907		}
908	} else {
909		seteuid(euid);
910		res = unlink(name);
911		seteuid(uid);
912		if (res < 0)
913			printf("\tcannot remove %s (!)\n", name);
914		else
915			printf("\tremoved %s\n", name);
916		/* XXX
917		 *  Note that for a df* file, this code should also check to see
918		 *  if it is a symlink to some other file, and if the original
919		 *  lpr command included '-r' ("remove file").  Of course, this
920		 *  code would not be removing the df* file unless there was no
921		 *  matching cf* file, and without the cf* file it is currently
922		 *  impossible to determine if '-r' had been specified...
923		 *
924		 *  As a result of this quandry, we may be leaving behind a
925		 *  user's file that was supposed to have been removed after
926		 *  being printed.  This may effect services such as CAP or
927		 *  samba, if they were configured to use 'lpr -r', and if
928		 *  datafiles are not being properly removed.
929		*/
930		if (S_ISLNK(stbuf.st_mode)) {
931			printf("\t    (which was a symlink to %s)\n", linkbuf);
932		}
933	}
934}
935
936/*
937 * Enable queuing to the printer (allow lpr's).
938 */
939void
940enable(struct printer *pp)
941{
942	struct stat stbuf;
943	char lf[MAXPATHLEN];
944
945	lock_file_name(pp, lf, sizeof lf);
946	printf("%s:\n", pp->printer);
947
948	/*
949	 * Turn off the group execute bit of the lock file to enable queuing.
950	 */
951	seteuid(euid);
952	if (stat(lf, &stbuf) >= 0) {
953		if (chmod(lf, stbuf.st_mode & ~LFM_QUEUE_DIS) < 0)
954			printf("\tcannot enable queuing\n");
955		else
956			printf("\tqueuing enabled\n");
957	}
958	seteuid(uid);
959}
960
961/*
962 * Enable queuing to the printer (allow lpr to add new jobs to the queue).
963 */
964void
965enable_q(struct printer *pp)
966{
967	int setres;
968	char lf[MAXPATHLEN];
969
970	lock_file_name(pp, lf, sizeof lf);
971	printf("%s:\n", pp->printer);
972
973	setres = set_qstate(SQS_ENABLEQ, lf);
974}
975
976/*
977 * Disable queuing.
978 */
979void
980disable(struct printer *pp)
981{
982	register int fd;
983	struct stat stbuf;
984	char lf[MAXPATHLEN];
985
986	lock_file_name(pp, lf, sizeof lf);
987	printf("%s:\n", pp->printer);
988	/*
989	 * Turn on the group execute bit of the lock file to disable queuing.
990	 */
991	seteuid(euid);
992	if (stat(lf, &stbuf) >= 0) {
993		if (chmod(lf, stbuf.st_mode | LFM_QUEUE_DIS) < 0)
994			printf("\tcannot disable queuing: %s\n",
995			       strerror(errno));
996		else
997			printf("\tqueuing disabled\n");
998	} else if (errno == ENOENT) {
999		if ((fd = open(lf, O_WRONLY|O_CREAT,
1000			       LOCK_FILE_MODE | LFM_QUEUE_DIS)) < 0)
1001			printf("\tcannot create lock file: %s\n",
1002			       strerror(errno));
1003		else {
1004			(void) close(fd);
1005			printf("\tqueuing disabled\n");
1006		}
1007	} else
1008		printf("\tcannot stat lock file\n");
1009	seteuid(uid);
1010}
1011
1012/*
1013 * Disable queuing.
1014 */
1015void
1016disable_q(struct printer *pp)
1017{
1018	int setres;
1019	char lf[MAXPATHLEN];
1020
1021	lock_file_name(pp, lf, sizeof lf);
1022	printf("%s:\n", pp->printer);
1023
1024	setres = set_qstate(SQS_DISABLEQ, lf);
1025}
1026
1027/*
1028 * Disable queuing and printing and put a message into the status file
1029 * (reason for being down).
1030 */
1031void
1032down(int argc, char *argv[])
1033{
1034        int cmdstatus, more;
1035	struct printer myprinter, *pp = &myprinter;
1036
1037	if (argc == 1) {
1038		printf("usage: down {all | printer} [message ...]\n");
1039		return;
1040	}
1041	if (!strcmp(argv[1], "all")) {
1042		more = firstprinter(pp, &cmdstatus);
1043		if (cmdstatus)
1044			goto looperr;
1045		while (more) {
1046			putmsg(pp, argc - 2, argv + 2);
1047			do {
1048				more = nextprinter(pp, &cmdstatus);
1049looperr:
1050				switch (cmdstatus) {
1051				case PCAPERR_TCOPEN:
1052					printf("warning: %s: unresolved "
1053					       "tc= reference(s) ",
1054					       pp->printer);
1055				case PCAPERR_SUCCESS:
1056					break;
1057				default:
1058					fatal(pp, "%s", pcaperr(cmdstatus));
1059				}
1060			} while (more && cmdstatus);
1061		}
1062		return;
1063	}
1064	init_printer(pp);
1065	cmdstatus = getprintcap(argv[1], pp);
1066	switch (cmdstatus) {
1067	default:
1068		fatal(pp, "%s", pcaperr(cmdstatus));
1069	case PCAPERR_NOTFOUND:
1070		printf("unknown printer %s\n", argv[1]);
1071		return;
1072	case PCAPERR_TCOPEN:
1073		printf("warning: %s: unresolved tc= reference(s)", argv[1]);
1074		break;
1075	case PCAPERR_SUCCESS:
1076		break;
1077	}
1078	putmsg(pp, argc - 2, argv + 2);
1079}
1080
1081static void
1082putmsg(struct printer *pp, int argc, char **argv)
1083{
1084	register int fd;
1085	register char *cp1, *cp2;
1086	char buf[1024];
1087	char file[MAXPATHLEN];
1088	struct stat stbuf;
1089
1090	printf("%s:\n", pp->printer);
1091	/*
1092	 * Turn on the group execute bit of the lock file to disable queuing;
1093	 * turn on the owner execute bit of the lock file to disable printing.
1094	 */
1095	lock_file_name(pp, file, sizeof file);
1096	seteuid(euid);
1097	if (stat(file, &stbuf) >= 0) {
1098		if (chmod(file, stbuf.st_mode|LFM_PRINT_DIS|LFM_QUEUE_DIS) < 0)
1099			printf("\tcannot disable queuing: %s\n",
1100			       strerror(errno));
1101		else
1102			printf("\tprinter and queuing disabled\n");
1103	} else if (errno == ENOENT) {
1104		if ((fd = open(file, O_WRONLY|O_CREAT,
1105			       LOCK_FILE_MODE|LFM_PRINT_DIS|LFM_QUEUE_DIS)) < 0)
1106			printf("\tcannot create lock file: %s\n",
1107			       strerror(errno));
1108		else {
1109			(void) close(fd);
1110			printf("\tprinter and queuing disabled\n");
1111		}
1112		seteuid(uid);
1113		return;
1114	} else
1115		printf("\tcannot stat lock file\n");
1116	/*
1117	 * Write the message into the status file.
1118	 */
1119	status_file_name(pp, file, sizeof file);
1120	fd = open(file, O_WRONLY|O_CREAT|O_EXLOCK, STAT_FILE_MODE);
1121	if (fd < 0) {
1122		printf("\tcannot create status file: %s\n", strerror(errno));
1123		seteuid(uid);
1124		return;
1125	}
1126	seteuid(uid);
1127	(void) ftruncate(fd, 0);
1128	if (argc <= 0) {
1129		(void) write(fd, "\n", 1);
1130		(void) close(fd);
1131		return;
1132	}
1133	cp1 = buf;
1134	while (--argc >= 0) {
1135		cp2 = *argv++;
1136		while ((size_t)(cp1 - buf) < sizeof(buf) && (*cp1++ = *cp2++))
1137			;
1138		cp1[-1] = ' ';
1139	}
1140	cp1[-1] = '\n';
1141	*cp1 = '\0';
1142	(void) write(fd, buf, strlen(buf));
1143	(void) close(fd);
1144}
1145
1146/*
1147 * Exit lpc
1148 */
1149void
1150quit(int argc __unused, char *argv[] __unused)
1151{
1152	exit(0);
1153}
1154
1155/*
1156 * Kill and restart the daemon.
1157 */
1158void
1159restart(struct printer *pp)
1160{
1161	abortpr(pp, 0);
1162	startpr(pp, 0);
1163}
1164
1165/*
1166 * Kill and restart the daemon.
1167 */
1168void
1169restart_q(struct printer *pp)
1170{
1171	int killres, setres, startok;
1172	char lf[MAXPATHLEN];
1173
1174	lock_file_name(pp, lf, sizeof lf);
1175	printf("%s:\n", pp->printer);
1176
1177	killres = kill_qtask(lf);
1178
1179	/*
1180	 * XXX - if the kill worked, we should probably sleep for
1181	 *      a second or so before trying to restart the queue.
1182	 */
1183
1184	/* make sure the queue is set to print jobs */
1185	setres = set_qstate(SQS_STARTP, lf);
1186
1187	seteuid(euid);
1188	startok = startdaemon(pp);
1189	seteuid(uid);
1190	if (!startok)
1191		printf("\tcouldn't restart daemon\n");
1192	else
1193		printf("\tdaemon restarted\n");
1194}
1195
1196/*
1197 * Set the status message of each queue listed.  Requires a "-msg"
1198 * parameter to indicate the end of the queue list and start of msg text.
1199 */
1200void
1201setstatus_gi(int argc __unused, char *argv[] __unused)
1202{
1203
1204	if (generic_msg == NULL) {
1205		printf("You must specify '-msg' before the text of the new status message.\n");
1206		generic_initerr = 1;
1207	}
1208}
1209
1210void
1211setstatus_q(struct printer *pp)
1212{
1213	char lf[MAXPATHLEN];
1214
1215	lock_file_name(pp, lf, sizeof lf);
1216	printf("%s:\n", pp->printer);
1217
1218	upstat(pp, generic_msg, 1);
1219}
1220
1221/*
1222 * Enable printing on the specified printer and startup the daemon.
1223 */
1224void
1225startcmd(struct printer *pp)
1226{
1227	startpr(pp, 1);
1228}
1229
1230static void
1231startpr(struct printer *pp, int chgenable)
1232{
1233	struct stat stbuf;
1234	char lf[MAXPATHLEN];
1235
1236	lock_file_name(pp, lf, sizeof lf);
1237	printf("%s:\n", pp->printer);
1238
1239	/*
1240	 * For chgenable==1 ('start'), turn off the LFM_PRINT_DIS bit of the
1241	 * lock file to re-enable printing.  For chgenable==2 ('up'), also
1242	 * turn off the LFM_QUEUE_DIS bit to re-enable queueing.
1243	 */
1244	seteuid(euid);
1245	if (chgenable && stat(lf, &stbuf) >= 0) {
1246		mode_t bits = (chgenable == 2 ? 0 : LFM_QUEUE_DIS);
1247		if (chmod(lf, stbuf.st_mode & (LOCK_FILE_MODE | bits)) < 0)
1248			printf("\tcannot enable printing\n");
1249		else
1250			printf("\tprinting enabled\n");
1251	}
1252	if (!startdaemon(pp))
1253		printf("\tcouldn't start daemon\n");
1254	else
1255		printf("\tdaemon started\n");
1256	seteuid(uid);
1257}
1258
1259/*
1260 * Enable printing on the specified printer and startup the daemon.
1261 */
1262void
1263start_q(struct printer *pp)
1264{
1265	int setres, startok;
1266	char lf[MAXPATHLEN];
1267
1268	lock_file_name(pp, lf, sizeof lf);
1269	printf("%s:\n", pp->printer);
1270
1271	setres = set_qstate(SQS_STARTP, lf);
1272
1273	seteuid(euid);
1274	startok = startdaemon(pp);
1275	seteuid(uid);
1276	if (!startok)
1277		printf("\tcouldn't start daemon\n");
1278	else
1279		printf("\tdaemon started\n");
1280	seteuid(uid);
1281}
1282
1283/*
1284 * Print the status of the printer queue.
1285 */
1286void
1287status(struct printer *pp)
1288{
1289	struct stat stbuf;
1290	register int fd, i;
1291	register struct dirent *dp;
1292	DIR *dirp;
1293	char file[MAXPATHLEN];
1294
1295	printf("%s:\n", pp->printer);
1296	lock_file_name(pp, file, sizeof file);
1297	if (stat(file, &stbuf) >= 0) {
1298		printf("\tqueuing is %s\n",
1299		       ((stbuf.st_mode & LFM_QUEUE_DIS) ? "disabled"
1300			: "enabled"));
1301		printf("\tprinting is %s\n",
1302		       ((stbuf.st_mode & LFM_PRINT_DIS) ? "disabled"
1303			: "enabled"));
1304	} else {
1305		printf("\tqueuing is enabled\n");
1306		printf("\tprinting is enabled\n");
1307	}
1308	if ((dirp = opendir(pp->spool_dir)) == NULL) {
1309		printf("\tcannot examine spool directory\n");
1310		return;
1311	}
1312	i = 0;
1313	while ((dp = readdir(dirp)) != NULL) {
1314		if (*dp->d_name == 'c' && dp->d_name[1] == 'f')
1315			i++;
1316	}
1317	closedir(dirp);
1318	if (i == 0)
1319		printf("\tno entries in spool area\n");
1320	else if (i == 1)
1321		printf("\t1 entry in spool area\n");
1322	else
1323		printf("\t%d entries in spool area\n", i);
1324	fd = open(file, O_RDONLY);
1325	if (fd < 0 || flock(fd, LOCK_SH|LOCK_NB) == 0) {
1326		(void) close(fd);	/* unlocks as well */
1327		printf("\tprinter idle\n");
1328		return;
1329	}
1330	(void) close(fd);
1331	/* print out the contents of the status file, if it exists */
1332	status_file_name(pp, file, sizeof file);
1333	fd = open(file, O_RDONLY|O_SHLOCK);
1334	if (fd >= 0) {
1335		(void) fstat(fd, &stbuf);
1336		if (stbuf.st_size > 0) {
1337			putchar('\t');
1338			while ((i = read(fd, line, sizeof(line))) > 0)
1339				(void) fwrite(line, 1, i, stdout);
1340		}
1341		(void) close(fd);	/* unlocks as well */
1342	}
1343}
1344
1345/*
1346 * Stop the specified daemon after completing the current job and disable
1347 * printing.
1348 */
1349void
1350stop(struct printer *pp)
1351{
1352	register int fd;
1353	struct stat stbuf;
1354	char lf[MAXPATHLEN];
1355
1356	lock_file_name(pp, lf, sizeof lf);
1357	printf("%s:\n", pp->printer);
1358
1359	/*
1360	 * Turn on the owner execute bit of the lock file to disable printing.
1361	 */
1362	seteuid(euid);
1363	if (stat(lf, &stbuf) >= 0) {
1364		if (chmod(lf, stbuf.st_mode | LFM_PRINT_DIS) < 0)
1365			printf("\tcannot disable printing: %s\n",
1366			       strerror(errno));
1367		else {
1368			upstat(pp, "printing disabled\n", 0);
1369			printf("\tprinting disabled\n");
1370		}
1371	} else if (errno == ENOENT) {
1372		if ((fd = open(lf, O_WRONLY|O_CREAT,
1373			       LOCK_FILE_MODE | LFM_PRINT_DIS)) < 0)
1374			printf("\tcannot create lock file: %s\n",
1375			       strerror(errno));
1376		else {
1377			(void) close(fd);
1378			upstat(pp, "printing disabled\n", 0);
1379			printf("\tprinting disabled\n");
1380		}
1381	} else
1382		printf("\tcannot stat lock file\n");
1383	seteuid(uid);
1384}
1385
1386/*
1387 * Stop the specified daemon after completing the current job and disable
1388 * printing.
1389 */
1390void
1391stop_q(struct printer *pp)
1392{
1393	int setres;
1394	char lf[MAXPATHLEN];
1395
1396	lock_file_name(pp, lf, sizeof lf);
1397	printf("%s:\n", pp->printer);
1398
1399	setres = set_qstate(SQS_STOPP, lf);
1400
1401	if (setres >= 0)
1402		upstat(pp, "printing disabled\n", 0);
1403}
1404
1405struct	jobqueue **queue;
1406int	nitems;
1407time_t	mtime;
1408
1409/*
1410 * Put the specified jobs at the top of printer queue.
1411 */
1412void
1413topq(int argc, char *argv[])
1414{
1415	register int i;
1416	struct stat stbuf;
1417	int cmdstatus, changed;
1418	struct printer myprinter, *pp = &myprinter;
1419
1420	if (argc < 3) {
1421		printf("usage: topq printer [jobnum ...] [user ...]\n");
1422		return;
1423	}
1424
1425	--argc;
1426	++argv;
1427	init_printer(pp);
1428	cmdstatus = getprintcap(*argv, pp);
1429	switch(cmdstatus) {
1430	default:
1431		fatal(pp, "%s", pcaperr(cmdstatus));
1432	case PCAPERR_NOTFOUND:
1433		printf("unknown printer %s\n", *argv);
1434		return;
1435	case PCAPERR_TCOPEN:
1436		printf("warning: %s: unresolved tc= reference(s)", *argv);
1437		break;
1438	case PCAPERR_SUCCESS:
1439		break;
1440	}
1441	printf("%s:\n", pp->printer);
1442
1443	seteuid(euid);
1444	if (chdir(pp->spool_dir) < 0) {
1445		printf("\tcannot chdir to %s\n", pp->spool_dir);
1446		goto out;
1447	}
1448	seteuid(uid);
1449	nitems = getq(pp, &queue);
1450	if (nitems == 0)
1451		return;
1452	changed = 0;
1453	mtime = queue[0]->job_time;
1454	for (i = argc; --i; ) {
1455		if (doarg(argv[i]) == 0) {
1456			printf("\tjob %s is not in the queue\n", argv[i]);
1457			continue;
1458		} else
1459			changed++;
1460	}
1461	for (i = 0; i < nitems; i++)
1462		free(queue[i]);
1463	free(queue);
1464	if (!changed) {
1465		printf("\tqueue order unchanged\n");
1466		return;
1467	}
1468	/*
1469	 * Turn on the public execute bit of the lock file to
1470	 * get lpd to rebuild the queue after the current job.
1471	 */
1472	seteuid(euid);
1473	if (changed && stat(pp->lock_file, &stbuf) >= 0)
1474		(void) chmod(pp->lock_file, stbuf.st_mode | LFM_RESET_QUE);
1475
1476out:
1477	seteuid(uid);
1478}
1479
1480/*
1481 * Reposition the job by changing the modification time of
1482 * the control file.
1483 */
1484static int
1485touch(struct jobqueue *jq)
1486{
1487	struct timeval tvp[2];
1488	int ret;
1489
1490	tvp[0].tv_sec = tvp[1].tv_sec = --mtime;
1491	tvp[0].tv_usec = tvp[1].tv_usec = 0;
1492	seteuid(euid);
1493	ret = utimes(jq->job_cfname, tvp);
1494	seteuid(uid);
1495	return (ret);
1496}
1497
1498/*
1499 * Checks if specified job name is in the printer's queue.
1500 * Returns:  negative (-1) if argument name is not in the queue.
1501 */
1502static int
1503doarg(char *job)
1504{
1505	register struct jobqueue **qq;
1506	register int jobnum, n;
1507	register char *cp, *machine;
1508	int cnt = 0;
1509	FILE *fp;
1510
1511	/*
1512	 * Look for a job item consisting of system name, colon, number
1513	 * (example: ucbarpa:114)
1514	 */
1515	if ((cp = strchr(job, ':')) != NULL) {
1516		machine = job;
1517		*cp++ = '\0';
1518		job = cp;
1519	} else
1520		machine = NULL;
1521
1522	/*
1523	 * Check for job specified by number (example: 112 or 235ucbarpa).
1524	 */
1525	if (isdigit(*job)) {
1526		jobnum = 0;
1527		do
1528			jobnum = jobnum * 10 + (*job++ - '0');
1529		while (isdigit(*job));
1530		for (qq = queue + nitems; --qq >= queue; ) {
1531			n = 0;
1532			for (cp = (*qq)->job_cfname+3; isdigit(*cp); )
1533				n = n * 10 + (*cp++ - '0');
1534			if (jobnum != n)
1535				continue;
1536			if (*job && strcmp(job, cp) != 0)
1537				continue;
1538			if (machine != NULL && strcmp(machine, cp) != 0)
1539				continue;
1540			if (touch(*qq) == 0) {
1541				printf("\tmoved %s\n", (*qq)->job_cfname);
1542				cnt++;
1543			}
1544		}
1545		return(cnt);
1546	}
1547	/*
1548	 * Process item consisting of owner's name (example: henry).
1549	 */
1550	for (qq = queue + nitems; --qq >= queue; ) {
1551		seteuid(euid);
1552		fp = fopen((*qq)->job_cfname, "r");
1553		seteuid(uid);
1554		if (fp == NULL)
1555			continue;
1556		while (getline(fp) > 0)
1557			if (line[0] == 'P')
1558				break;
1559		(void) fclose(fp);
1560		if (line[0] != 'P' || strcmp(job, line+1) != 0)
1561			continue;
1562		if (touch(*qq) == 0) {
1563			printf("\tmoved %s\n", (*qq)->job_cfname);
1564			cnt++;
1565		}
1566	}
1567	return(cnt);
1568}
1569
1570/*
1571 * Enable everything and start printer (undo `down').
1572 */
1573void
1574up(struct printer *pp)
1575{
1576	startpr(pp, 2);
1577}
1578
1579/*
1580 * Enable both queuing & printing, and start printer (undo `down').
1581 */
1582void
1583up_q(struct printer *pp)
1584{
1585	int setres, startok;
1586	char lf[MAXPATHLEN];
1587
1588	lock_file_name(pp, lf, sizeof lf);
1589	printf("%s:\n", pp->printer);
1590
1591	setres = set_qstate(SQS_ENABLEQ+SQS_STARTP, lf);
1592
1593	seteuid(euid);
1594	startok = startdaemon(pp);
1595	seteuid(uid);
1596	if (!startok)
1597		printf("\tcouldn't start daemon\n");
1598	else
1599		printf("\tdaemon started\n");
1600}
1601