xref: /openbsd-src/usr.sbin/lpr/lpc/cmds.c (revision f414793931f0f39a413874f9e342e33d9fd35eac)
1*f4147939Sguenther /*	$OpenBSD: cmds.c,v 1.28 2018/04/26 12:42:51 guenther Exp $	*/
2a7643117Smillert /*	$NetBSD: cmds.c,v 1.12 1997/10/05 15:12:06 mrg Exp $	*/
3ca5d3c4eSmillert 
4df930be7Sderaadt /*
5df930be7Sderaadt  * Copyright (c) 1983, 1993
6df930be7Sderaadt  *	The Regents of the University of California.  All rights reserved.
7df930be7Sderaadt  *
8df930be7Sderaadt  *
9df930be7Sderaadt  * Redistribution and use in source and binary forms, with or without
10df930be7Sderaadt  * modification, are permitted provided that the following conditions
11df930be7Sderaadt  * are met:
12df930be7Sderaadt  * 1. Redistributions of source code must retain the above copyright
13df930be7Sderaadt  *    notice, this list of conditions and the following disclaimer.
14df930be7Sderaadt  * 2. Redistributions in binary form must reproduce the above copyright
15df930be7Sderaadt  *    notice, this list of conditions and the following disclaimer in the
16df930be7Sderaadt  *    documentation and/or other materials provided with the distribution.
1729295d1cSmillert  * 3. Neither the name of the University nor the names of its contributors
18df930be7Sderaadt  *    may be used to endorse or promote products derived from this software
19df930be7Sderaadt  *    without specific prior written permission.
20df930be7Sderaadt  *
21df930be7Sderaadt  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22df930be7Sderaadt  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23df930be7Sderaadt  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24df930be7Sderaadt  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25df930be7Sderaadt  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26df930be7Sderaadt  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27df930be7Sderaadt  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28df930be7Sderaadt  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29df930be7Sderaadt  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30df930be7Sderaadt  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31df930be7Sderaadt  * SUCH DAMAGE.
32df930be7Sderaadt  */
33df930be7Sderaadt 
34df930be7Sderaadt /*
35df930be7Sderaadt  * lpc -- line printer control program -- commands:
36df930be7Sderaadt  */
37df930be7Sderaadt 
38df930be7Sderaadt #include <sys/time.h>
39df930be7Sderaadt #include <sys/stat.h>
40df930be7Sderaadt 
41df930be7Sderaadt #include <signal.h>
42df930be7Sderaadt #include <fcntl.h>
43df930be7Sderaadt #include <errno.h>
44df930be7Sderaadt #include <dirent.h>
45df930be7Sderaadt #include <unistd.h>
46b9fc9a72Sderaadt #include <limits.h>
47df930be7Sderaadt #include <stdlib.h>
48df930be7Sderaadt #include <stdio.h>
49df930be7Sderaadt #include <ctype.h>
50df930be7Sderaadt #include <string.h>
51df930be7Sderaadt #include "lp.h"
52df930be7Sderaadt #include "lp.local.h"
53df930be7Sderaadt #include "lpc.h"
54df930be7Sderaadt #include "extern.h"
55df930be7Sderaadt #include "pathnames.h"
56df930be7Sderaadt 
57a7643117Smillert static void	abortpr(int);
58a7643117Smillert static void	cleanpr(void);
59a7643117Smillert static void	disablepr(void);
60a7643117Smillert static int	doarg(char *);
61a737da78Sguenther static int	doselect(const struct dirent *);
62a7643117Smillert static void	enablepr(void);
63a7643117Smillert static void	prstat(void);
64a7643117Smillert static void	putmsg(int, char **);
659142ec07Sguenther static int	sortq(const struct dirent **, const struct dirent **);
66a7643117Smillert static void	startpr(int);
67a7643117Smillert static void	stoppr(void);
68a7643117Smillert static int	touch(struct queue *);
69a7643117Smillert static void	unlinkf(char *);
70a7643117Smillert static void	upstat(char *);
71df930be7Sderaadt 
72df930be7Sderaadt /*
73df930be7Sderaadt  * kill an existing daemon and disable printing.
74df930be7Sderaadt  */
75df930be7Sderaadt void
doabort(int argc,char ** argv)76a7643117Smillert doabort(int argc, char **argv)
77df930be7Sderaadt {
78c1624b2fSmillert 	int c, status;
79c1624b2fSmillert 	char *cp1, *cp2;
80df930be7Sderaadt 	char prbuf[100];
81df930be7Sderaadt 
82df930be7Sderaadt 	if (argc == 1) {
831d8c2aacSsobrado 		printf("usage: abort {all | printer ...}\n");
84df930be7Sderaadt 		return;
85df930be7Sderaadt 	}
86a7643117Smillert 	if (argc == 2 && strcmp(argv[1], "all") == 0) {
87df930be7Sderaadt 		printer = prbuf;
88df930be7Sderaadt 		while (cgetnext(&bp, printcapdb) > 0) {
89df930be7Sderaadt 			cp1 = prbuf;
90df930be7Sderaadt 			cp2 = bp;
917416c11cSmillert 			while ((c = *cp2++) && c != '|' && c != ':' &&
92c9e7d913Spjanzen 			    (cp1 - prbuf) < sizeof(prbuf) - 1)
93df930be7Sderaadt 				*cp1++ = c;
94df930be7Sderaadt 			*cp1 = '\0';
95df930be7Sderaadt 			abortpr(1);
96df930be7Sderaadt 		}
97df930be7Sderaadt 		return;
98df930be7Sderaadt 	}
99df930be7Sderaadt 	while (--argc) {
100df930be7Sderaadt 		printer = *++argv;
101df930be7Sderaadt 		if ((status = cgetent(&bp, printcapdb, printer)) == -2) {
102df930be7Sderaadt 			printf("cannot open printer description file\n");
103df930be7Sderaadt 			continue;
104df930be7Sderaadt 		} else if (status == -1) {
105df930be7Sderaadt 			printf("unknown printer %s\n", printer);
106df930be7Sderaadt 			continue;
107df930be7Sderaadt 		} else if (status == -3)
108df930be7Sderaadt 			fatal("potential reference loop detected in printcap file");
109df930be7Sderaadt 		abortpr(1);
110df930be7Sderaadt 	}
111df930be7Sderaadt }
112df930be7Sderaadt 
113a7643117Smillert static void
abortpr(int dis)114a7643117Smillert abortpr(int dis)
115df930be7Sderaadt {
116c1624b2fSmillert 	FILE *fp;
117df930be7Sderaadt 	struct stat stbuf;
118c9e7a8b4Sderaadt 	int pid, fd;
119df930be7Sderaadt 
120df930be7Sderaadt 	if (cgetstr(bp, "sd", &SD) == -1)
121df930be7Sderaadt 		SD = _PATH_DEFSPOOL;
122df930be7Sderaadt 	if (cgetstr(bp, "lo", &LO) == -1)
123df930be7Sderaadt 		LO = DEFLOCK;
1247416c11cSmillert 	(void)snprintf(line, sizeof(line), "%s/%s", SD, LO);
125df930be7Sderaadt 	printf("%s:\n", printer);
126df930be7Sderaadt 
1276468ba68Smillert 	PRIV_START;
128df930be7Sderaadt 	/*
129df930be7Sderaadt 	 * Turn on the owner execute bit of the lock file to disable printing.
130df930be7Sderaadt 	 */
131df930be7Sderaadt 	if (dis) {
132df930be7Sderaadt 		if (stat(line, &stbuf) >= 0) {
1336468ba68Smillert 			stbuf.st_mode |= S_IXUSR;
1346468ba68Smillert 			if (chmod(line, stbuf.st_mode & 0777) < 0)
135df930be7Sderaadt 				printf("\tcannot disable printing\n");
136df930be7Sderaadt 			else {
137df930be7Sderaadt 				upstat("printing disabled\n");
138df930be7Sderaadt 				printf("\tprinting disabled\n");
139df930be7Sderaadt 			}
140df930be7Sderaadt 		} else if (errno == ENOENT) {
1416468ba68Smillert 			if ((fd = safe_open(line, O_WRONLY|O_CREAT|O_NOFOLLOW,
1426468ba68Smillert 			    0760)) < 0)
143df930be7Sderaadt 				printf("\tcannot create lock file\n");
144df930be7Sderaadt 			else {
1456468ba68Smillert 				(void)fchown(fd, DEFUID, -1);
146df930be7Sderaadt 				(void)close(fd);
147df930be7Sderaadt 				upstat("printing disabled\n");
148df930be7Sderaadt 				printf("\tprinting disabled\n");
149df930be7Sderaadt 				printf("\tno daemon to abort\n");
150df930be7Sderaadt 			}
151df930be7Sderaadt 			goto out;
152df930be7Sderaadt 		} else {
153df930be7Sderaadt 			printf("\tcannot stat lock file\n");
154df930be7Sderaadt 			goto out;
155df930be7Sderaadt 		}
156df930be7Sderaadt 	}
157df930be7Sderaadt 	/*
158df930be7Sderaadt 	 * Kill the current daemon to stop printing now.
159df930be7Sderaadt 	 */
1606468ba68Smillert 	fd = safe_open(line, O_RDONLY|O_NOFOLLOW, 0);
1616468ba68Smillert 	if (fd < 0 || (fp = fdopen(fd, "r")) == NULL) {
1626468ba68Smillert 		if (fd >= 0)
1636468ba68Smillert 			close(fd);
164df930be7Sderaadt 		printf("\tcannot open lock file\n");
165df930be7Sderaadt 		goto out;
166df930be7Sderaadt 	}
167f9bbbf45Sfgsch 	if (!get_line(fp) || flock(fileno(fp), LOCK_SH|LOCK_NB) == 0) {
168df930be7Sderaadt 		(void)fclose(fp);	/* unlocks as well */
169df930be7Sderaadt 		printf("\tno daemon to abort\n");
170df930be7Sderaadt 		goto out;
171df930be7Sderaadt 	}
172df930be7Sderaadt 	(void)fclose(fp);
17320a848d0Smillert 	if (kill(pid = atoi(line), SIGTERM) < 0) {
17420a848d0Smillert 		if (errno == ESRCH)
17520a848d0Smillert 			printf("\tno daemon to abort\n");
176df930be7Sderaadt 		else
17720a848d0Smillert 			printf("\tWarning: daemon (pid %d) not killed\n", pid);
17820a848d0Smillert 	} else
179df930be7Sderaadt 		printf("\tdaemon (pid %d) killed\n", pid);
180df930be7Sderaadt out:
1816468ba68Smillert 	PRIV_END;
182df930be7Sderaadt }
183df930be7Sderaadt 
184df930be7Sderaadt /*
1856468ba68Smillert  * Write a message into the status file (assumes PRIV_START already called)
186df930be7Sderaadt  */
187a7643117Smillert static void
upstat(char * msg)188a7643117Smillert upstat(char *msg)
189df930be7Sderaadt {
190c1624b2fSmillert 	int fd;
191b9fc9a72Sderaadt 	char statfile[PATH_MAX];
192df930be7Sderaadt 
193df930be7Sderaadt 	if (cgetstr(bp, "st", &ST) == -1)
194df930be7Sderaadt 		ST = DEFSTAT;
1957416c11cSmillert 	(void)snprintf(statfile, sizeof(statfile), "%s/%s", SD, ST);
1966468ba68Smillert 	fd = safe_open(statfile, O_WRONLY|O_CREAT|O_NOFOLLOW, 0660);
197df930be7Sderaadt 	if (fd < 0 || flock(fd, LOCK_EX) < 0) {
198df930be7Sderaadt 		printf("\tcannot create status file\n");
19995cb4a2fSkrw 		if (fd >= 0)
20095cb4a2fSkrw 			(void)close(fd);	/* unlocks as well */
201df930be7Sderaadt 		return;
202df930be7Sderaadt 	}
2036468ba68Smillert 	(void)fchown(fd, DEFUID, -1);
204df930be7Sderaadt 	(void)ftruncate(fd, 0);
205df930be7Sderaadt 	if (msg == (char *)NULL)
206df930be7Sderaadt 		(void)write(fd, "\n", 1);
207df930be7Sderaadt 	else
208df930be7Sderaadt 		(void)write(fd, msg, strlen(msg));
209df930be7Sderaadt 	(void)close(fd);
210df930be7Sderaadt }
211df930be7Sderaadt 
212df930be7Sderaadt /*
213df930be7Sderaadt  * Remove all spool files and temporaries from the spooling area.
214df930be7Sderaadt  */
215df930be7Sderaadt void
clean(int argc,char ** argv)216a7643117Smillert clean(int argc, char **argv)
217df930be7Sderaadt {
218c1624b2fSmillert 	int c, status;
219c1624b2fSmillert 	char *cp1, *cp2;
220df930be7Sderaadt 	char prbuf[100];
221df930be7Sderaadt 
222df930be7Sderaadt 	if (argc == 1) {
2231d8c2aacSsobrado 		printf("usage: clean {all | printer ...}\n");
224df930be7Sderaadt 		return;
225df930be7Sderaadt 	}
226a7643117Smillert 	if (argc == 2 && strcmp(argv[1], "all") == 0) {
227df930be7Sderaadt 		printer = prbuf;
228df930be7Sderaadt 		while (cgetnext(&bp, printcapdb) > 0) {
229df930be7Sderaadt 			cp1 = prbuf;
230df930be7Sderaadt 			cp2 = bp;
2317416c11cSmillert 			while ((c = *cp2++) && c != '|' && c != ':' &&
232c9e7d913Spjanzen 			    (cp1 - prbuf) < sizeof(prbuf) - 1)
233df930be7Sderaadt 				*cp1++ = c;
234df930be7Sderaadt 			*cp1 = '\0';
235df930be7Sderaadt 			cleanpr();
236df930be7Sderaadt 		}
237df930be7Sderaadt 		return;
238df930be7Sderaadt 	}
239df930be7Sderaadt 	while (--argc) {
240df930be7Sderaadt 		printer = *++argv;
241df930be7Sderaadt 		if ((status = cgetent(&bp, printcapdb, printer)) == -2) {
242df930be7Sderaadt 			printf("cannot open printer description file\n");
243df930be7Sderaadt 			continue;
244df930be7Sderaadt 		} else if (status == -1) {
245df930be7Sderaadt 			printf("unknown printer %s\n", printer);
246df930be7Sderaadt 			continue;
247df930be7Sderaadt 		} else if (status == -3)
248df930be7Sderaadt 			fatal("potential reference loop detected in printcap file");
249df930be7Sderaadt 
250df930be7Sderaadt 		cleanpr();
251df930be7Sderaadt 	}
252df930be7Sderaadt }
253df930be7Sderaadt 
254a7643117Smillert static int
doselect(const struct dirent * d)255a737da78Sguenther doselect(const struct dirent *d)
256df930be7Sderaadt {
257df930be7Sderaadt 	int c = d->d_name[0];
258df930be7Sderaadt 
259df930be7Sderaadt 	if ((c == 't' || c == 'c' || c == 'd') && d->d_name[1] == 'f')
260df930be7Sderaadt 		return(1);
261df930be7Sderaadt 	return(0);
262df930be7Sderaadt }
263df930be7Sderaadt 
264df930be7Sderaadt /*
265df930be7Sderaadt  * Comparison routine for scandir. Sort by job number and machine, then
266df930be7Sderaadt  * by `cf', `tf', or `df', then by the sequence letter A-Z, a-z.
267df930be7Sderaadt  */
268a7643117Smillert static int
sortq(const struct dirent ** d1,const struct dirent ** d2)2699142ec07Sguenther sortq(const struct dirent **d1, const struct dirent **d2)
270df930be7Sderaadt {
271df930be7Sderaadt 	int c1, c2;
272df930be7Sderaadt 
273a7643117Smillert 	if ((c1 = strcmp((*d1)->d_name + 3, (*d2)->d_name + 3)) != 0)
274df930be7Sderaadt 		return(c1);
275df930be7Sderaadt 	c1 = (*d1)->d_name[0];
276df930be7Sderaadt 	c2 = (*d2)->d_name[0];
277df930be7Sderaadt 	if (c1 == c2)
278df930be7Sderaadt 		return((*d1)->d_name[2] - (*d2)->d_name[2]);
279df930be7Sderaadt 	if (c1 == 'c')
280df930be7Sderaadt 		return(-1);
281df930be7Sderaadt 	if (c1 == 'd' || c2 == 'c')
282df930be7Sderaadt 		return(1);
283df930be7Sderaadt 	return(-1);
284df930be7Sderaadt }
285df930be7Sderaadt 
286df930be7Sderaadt /*
287df930be7Sderaadt  * Remove incomplete jobs from spooling area.
288df930be7Sderaadt  */
289a7643117Smillert static void
cleanpr(void)290a7643117Smillert cleanpr(void)
291df930be7Sderaadt {
292c1624b2fSmillert 	int i, n;
293c1624b2fSmillert 	char *cp, *cp1, *lp;
294df930be7Sderaadt 	struct dirent **queue;
295df930be7Sderaadt 	int nitems;
296df930be7Sderaadt 
297df930be7Sderaadt 	if (cgetstr(bp, "sd", &SD) == -1)
298df930be7Sderaadt 		SD = _PATH_DEFSPOOL;
299df930be7Sderaadt 	printf("%s:\n", printer);
300df930be7Sderaadt 
301a7643117Smillert 	/* XXX depends on SD being non-NUL */
302a7643117Smillert 	for (lp = line, cp = SD; (lp - line) < sizeof(line) &&
303a7643117Smillert 	    (*lp++ = *cp++) != '\0'; )
304df930be7Sderaadt 		;
305df930be7Sderaadt 	lp[-1] = '/';
30673a94c6dSpjanzen 	if (lp - line >= sizeof(line)) {
30773a94c6dSpjanzen 		printf("\tspool directory name too long\n");
30873a94c6dSpjanzen 		return;
30973a94c6dSpjanzen 	}
310df930be7Sderaadt 
3116468ba68Smillert 	PRIV_START;
312df930be7Sderaadt 	nitems = scandir(SD, &queue, doselect, sortq);
3136468ba68Smillert 	PRIV_END;
314df930be7Sderaadt 	if (nitems < 0) {
315df930be7Sderaadt 		printf("\tcannot examine spool directory\n");
316df930be7Sderaadt 		return;
317df930be7Sderaadt 	}
318df930be7Sderaadt 	if (nitems == 0)
319df930be7Sderaadt 		return;
320df930be7Sderaadt 	i = 0;
321df930be7Sderaadt 	do {
322df930be7Sderaadt 		cp = queue[i]->d_name;
323df930be7Sderaadt 		if (*cp == 'c') {
324df930be7Sderaadt 			n = 0;
325df930be7Sderaadt 			while (i + 1 < nitems) {
326df930be7Sderaadt 				cp1 = queue[i + 1]->d_name;
327df930be7Sderaadt 				if (*cp1 != 'd' || strcmp(cp + 3, cp1 + 3))
328df930be7Sderaadt 					break;
329df930be7Sderaadt 				i++;
330df930be7Sderaadt 				n++;
331df930be7Sderaadt 			}
332df930be7Sderaadt 			if (n == 0) {
333a7643117Smillert 				if (strlcpy(lp, cp, sizeof(line) - (lp - line))
334a7643117Smillert 				    >= sizeof(line) - (lp - line))
33573a94c6dSpjanzen 					printf("\tpath too long, %s/%s", SD, cp);
33673a94c6dSpjanzen 				else
337df930be7Sderaadt 					unlinkf(line);
338df930be7Sderaadt 			}
339df930be7Sderaadt 		} else {
340df930be7Sderaadt 			/*
341df930be7Sderaadt 			 * Must be a df with no cf (otherwise, it would have
342df930be7Sderaadt 			 * been skipped above) or a tf file (which can always
343df930be7Sderaadt 			 * be removed).
344df930be7Sderaadt 			 */
34573a94c6dSpjanzen 			if (strlcpy(lp, cp, sizeof(line) - (lp - line)) >=
34673a94c6dSpjanzen 			    sizeof(line) - (lp - line))
34773a94c6dSpjanzen 				printf("\tpath too long, %s/%s", SD, cp);
34873a94c6dSpjanzen 			else
349df930be7Sderaadt 				unlinkf(line);
350df930be7Sderaadt 		}
351df930be7Sderaadt      	} while (++i < nitems);
352df930be7Sderaadt }
353df930be7Sderaadt 
354a7643117Smillert static void
unlinkf(char * name)355a7643117Smillert unlinkf(char *name)
356df930be7Sderaadt {
3576468ba68Smillert 	PRIV_START;
358df930be7Sderaadt 	if (unlink(name) < 0)
359df930be7Sderaadt 		printf("\tcannot remove %s\n", name);
360df930be7Sderaadt 	else
361df930be7Sderaadt 		printf("\tremoved %s\n", name);
3626468ba68Smillert 	PRIV_END;
363df930be7Sderaadt }
364df930be7Sderaadt 
365df930be7Sderaadt /*
366df930be7Sderaadt  * Enable queuing to the printer (allow lpr's).
367df930be7Sderaadt  */
368df930be7Sderaadt void
enable(int argc,char ** argv)369a7643117Smillert enable(int argc, char **argv)
370df930be7Sderaadt {
371c1624b2fSmillert 	int c, status;
372c1624b2fSmillert 	char *cp1, *cp2;
373df930be7Sderaadt 	char prbuf[100];
374df930be7Sderaadt 
375df930be7Sderaadt 	if (argc == 1) {
3761d8c2aacSsobrado 		printf("usage: enable {all | printer ...}\n");
377df930be7Sderaadt 		return;
378df930be7Sderaadt 	}
379a7643117Smillert 	if (argc == 2 && strcmp(argv[1], "all") == 0) {
380df930be7Sderaadt 		printer = prbuf;
381df930be7Sderaadt 		while (cgetnext(&bp, printcapdb) > 0) {
382df930be7Sderaadt 			cp1 = prbuf;
383df930be7Sderaadt 			cp2 = bp;
3847416c11cSmillert 			while ((c = *cp2++) && c != '|' && c != ':' &&
385c9e7d913Spjanzen 			    (cp1 - prbuf) < sizeof(prbuf) - 1)
386df930be7Sderaadt 				*cp1++ = c;
387df930be7Sderaadt 			*cp1 = '\0';
388df930be7Sderaadt 			enablepr();
389df930be7Sderaadt 		}
390df930be7Sderaadt 		return;
391df930be7Sderaadt 	}
392df930be7Sderaadt 	while (--argc) {
393df930be7Sderaadt 		printer = *++argv;
394df930be7Sderaadt 		if ((status = cgetent(&bp, printcapdb, printer)) == -2) {
395df930be7Sderaadt 			printf("cannot open printer description file\n");
396df930be7Sderaadt 			continue;
397df930be7Sderaadt 		} else if (status == -1) {
398df930be7Sderaadt 			printf("unknown printer %s\n", printer);
399df930be7Sderaadt 			continue;
400df930be7Sderaadt 		} else if (status == -3)
401df930be7Sderaadt 			fatal("potential reference loop detected in printcap file");
402df930be7Sderaadt 
403df930be7Sderaadt 		enablepr();
404df930be7Sderaadt 	}
405df930be7Sderaadt }
406df930be7Sderaadt 
407a7643117Smillert static void
enablepr(void)408a7643117Smillert enablepr(void)
409df930be7Sderaadt {
410df930be7Sderaadt 	struct stat stbuf;
411df930be7Sderaadt 
412df930be7Sderaadt 	if (cgetstr(bp, "sd", &SD) == -1)
413df930be7Sderaadt 		SD = _PATH_DEFSPOOL;
414df930be7Sderaadt 	if (cgetstr(bp, "lo", &LO) == -1)
415df930be7Sderaadt 		LO = DEFLOCK;
4167416c11cSmillert 	(void)snprintf(line, sizeof(line), "%s/%s", SD, LO);
417df930be7Sderaadt 	printf("%s:\n", printer);
418df930be7Sderaadt 
419df930be7Sderaadt 	/*
420df930be7Sderaadt 	 * Turn off the group execute bit of the lock file to enable queuing.
421df930be7Sderaadt 	 */
4226468ba68Smillert 	PRIV_START;
423df930be7Sderaadt 	if (stat(line, &stbuf) >= 0) {
4246468ba68Smillert 		stbuf.st_mode &= ~S_IXGRP;
4256468ba68Smillert 		if (chmod(line, stbuf.st_mode & 0777) < 0)
426df930be7Sderaadt 			printf("\tcannot enable queuing\n");
427df930be7Sderaadt 		else
428df930be7Sderaadt 			printf("\tqueuing enabled\n");
429df930be7Sderaadt 	}
4306468ba68Smillert 	PRIV_END;
431df930be7Sderaadt }
432df930be7Sderaadt 
433df930be7Sderaadt /*
434df930be7Sderaadt  * Disable queuing.
435df930be7Sderaadt  */
436df930be7Sderaadt void
disable(int argc,char ** argv)437a7643117Smillert disable(int argc, char **argv)
438df930be7Sderaadt {
439c1624b2fSmillert 	int c, status;
440c1624b2fSmillert 	char *cp1, *cp2;
441df930be7Sderaadt 	char prbuf[100];
442df930be7Sderaadt 
443df930be7Sderaadt 	if (argc == 1) {
4441d8c2aacSsobrado 		printf("usage: disable {all | printer ...}\n");
445df930be7Sderaadt 		return;
446df930be7Sderaadt 	}
447a7643117Smillert 	if (argc == 2 && strcmp(argv[1], "all") == 0) {
448df930be7Sderaadt 		printer = prbuf;
449df930be7Sderaadt 		while (cgetnext(&bp, printcapdb) > 0) {
450df930be7Sderaadt 			cp1 = prbuf;
451df930be7Sderaadt 			cp2 = bp;
4527416c11cSmillert 			while ((c = *cp2++) && c != '|' && c != ':' &&
453c9e7d913Spjanzen 			    (cp1 - prbuf) < sizeof(prbuf) - 1)
454df930be7Sderaadt 				*cp1++ = c;
455df930be7Sderaadt 			*cp1 = '\0';
456df930be7Sderaadt 			disablepr();
457df930be7Sderaadt 		}
458df930be7Sderaadt 		return;
459df930be7Sderaadt 	}
460df930be7Sderaadt 	while (--argc) {
461df930be7Sderaadt 		printer = *++argv;
462df930be7Sderaadt 		if ((status = cgetent(&bp, printcapdb, printer)) == -2) {
463df930be7Sderaadt 			printf("cannot open printer description file\n");
464df930be7Sderaadt 			continue;
465df930be7Sderaadt 		} else if (status == -1) {
466df930be7Sderaadt 			printf("unknown printer %s\n", printer);
467df930be7Sderaadt 			continue;
468df930be7Sderaadt 		} else if (status == -3)
469df930be7Sderaadt 			fatal("potential reference loop detected in printcap file");
470df930be7Sderaadt 
471df930be7Sderaadt 		disablepr();
472df930be7Sderaadt 	}
473df930be7Sderaadt }
474df930be7Sderaadt 
475a7643117Smillert static void
disablepr(void)476a7643117Smillert disablepr(void)
477df930be7Sderaadt {
478c1624b2fSmillert 	int fd;
479df930be7Sderaadt 	struct stat stbuf;
480df930be7Sderaadt 
481df930be7Sderaadt 	if (cgetstr(bp, "sd", &SD) == -1)
482df930be7Sderaadt 		SD = _PATH_DEFSPOOL;
483df930be7Sderaadt 	if (cgetstr(bp, "lo", &LO) == -1)
484df930be7Sderaadt 		LO = DEFLOCK;
4857416c11cSmillert 	(void)snprintf(line, sizeof(line), "%s/%s", SD, LO);
486df930be7Sderaadt 	printf("%s:\n", printer);
487df930be7Sderaadt 	/*
488df930be7Sderaadt 	 * Turn on the group execute bit of the lock file to disable queuing.
489df930be7Sderaadt 	 */
4906468ba68Smillert 	PRIV_START;
491df930be7Sderaadt 	if (stat(line, &stbuf) >= 0) {
4926468ba68Smillert 		stbuf.st_mode |= S_IXGRP;
4936468ba68Smillert 		if (chmod(line, stbuf.st_mode & 0777) < 0)
494df930be7Sderaadt 			printf("\tcannot disable queuing\n");
495df930be7Sderaadt 		else
496df930be7Sderaadt 			printf("\tqueuing disabled\n");
497df930be7Sderaadt 	} else if (errno == ENOENT) {
4986468ba68Smillert 		if ((fd = safe_open(line, O_WRONLY|O_CREAT|O_NOFOLLOW, 0670)) < 0)
499df930be7Sderaadt 			printf("\tcannot create lock file\n");
500df930be7Sderaadt 		else {
5016468ba68Smillert 			(void)fchown(fd, DEFUID, -1);
502df930be7Sderaadt 			(void)close(fd);
503df930be7Sderaadt 			printf("\tqueuing disabled\n");
504df930be7Sderaadt 		}
505df930be7Sderaadt 	} else
506df930be7Sderaadt 		printf("\tcannot stat lock file\n");
5076468ba68Smillert 	PRIV_END;
508df930be7Sderaadt }
509df930be7Sderaadt 
510df930be7Sderaadt /*
511df930be7Sderaadt  * Disable queuing and printing and put a message into the status file
512df930be7Sderaadt  * (reason for being down).
513df930be7Sderaadt  */
514df930be7Sderaadt void
down(int argc,char ** argv)515a7643117Smillert down(int argc, char **argv)
516df930be7Sderaadt {
517c1624b2fSmillert 	int c, status;
518c1624b2fSmillert 	char *cp1, *cp2;
519df930be7Sderaadt 	char prbuf[100];
520df930be7Sderaadt 
521df930be7Sderaadt 	if (argc == 1) {
5221d8c2aacSsobrado 		printf("usage: down {all | printer} [message ...]\n");
523df930be7Sderaadt 		return;
524df930be7Sderaadt 	}
525a7643117Smillert 	if (strcmp(argv[1], "all") == 0) {
526df930be7Sderaadt 		printer = prbuf;
527df930be7Sderaadt 		while (cgetnext(&bp, printcapdb) > 0) {
528df930be7Sderaadt 			cp1 = prbuf;
529df930be7Sderaadt 			cp2 = bp;
5307416c11cSmillert 			while ((c = *cp2++) && c != '|' && c != ':' &&
531c9e7d913Spjanzen 			    (cp1 - prbuf) < sizeof(prbuf) - 1)
532df930be7Sderaadt 				*cp1++ = c;
533df930be7Sderaadt 			*cp1 = '\0';
534df930be7Sderaadt 			putmsg(argc - 2, argv + 2);
535df930be7Sderaadt 		}
536df930be7Sderaadt 		return;
537df930be7Sderaadt 	}
538df930be7Sderaadt 	printer = argv[1];
539df930be7Sderaadt 	if ((status = cgetent(&bp, printcapdb, printer)) == -2) {
540df930be7Sderaadt 		printf("cannot open printer description file\n");
541df930be7Sderaadt 		return;
542df930be7Sderaadt 	} else if (status == -1) {
543df930be7Sderaadt 		printf("unknown printer %s\n", printer);
544df930be7Sderaadt 		return;
545df930be7Sderaadt 	} else if (status == -3)
546df930be7Sderaadt 		fatal("potential reference loop detected in printcap file");
547df930be7Sderaadt 
548df930be7Sderaadt 	putmsg(argc - 2, argv + 2);
549df930be7Sderaadt }
550df930be7Sderaadt 
551a7643117Smillert static void
putmsg(int argc,char ** argv)552a7643117Smillert putmsg(int argc, char **argv)
553df930be7Sderaadt {
554c1624b2fSmillert 	int fd;
555c1624b2fSmillert 	char *cp1, *cp2;
556df930be7Sderaadt 	char buf[1024];
557df930be7Sderaadt 	struct stat stbuf;
558df930be7Sderaadt 
559df930be7Sderaadt 	if (cgetstr(bp, "sd", &SD) == -1)
560df930be7Sderaadt 		SD = _PATH_DEFSPOOL;
561df930be7Sderaadt 	if (cgetstr(bp, "lo", &LO) == -1)
562df930be7Sderaadt 		LO = DEFLOCK;
563df930be7Sderaadt 	if (cgetstr(bp, "st", &ST) == -1)
564df930be7Sderaadt 		ST = DEFSTAT;
565df930be7Sderaadt 	printf("%s:\n", printer);
566df930be7Sderaadt 	/*
567df930be7Sderaadt 	 * Turn on the group execute bit of the lock file to disable queuing and
568df930be7Sderaadt 	 * turn on the owner execute bit of the lock file to disable printing.
569df930be7Sderaadt 	 */
5707416c11cSmillert 	(void)snprintf(line, sizeof(line), "%s/%s", SD, LO);
5716468ba68Smillert 	PRIV_START;
572df930be7Sderaadt 	if (stat(line, &stbuf) >= 0) {
5736468ba68Smillert 		stbuf.st_mode |= (S_IXGRP|S_IXUSR);
5746468ba68Smillert 		if (chmod(line, stbuf.st_mode & 0777) < 0)
575df930be7Sderaadt 			printf("\tcannot disable queuing\n");
576df930be7Sderaadt 		else
577df930be7Sderaadt 			printf("\tprinter and queuing disabled\n");
578df930be7Sderaadt 	} else if (errno == ENOENT) {
5796468ba68Smillert 		if ((fd = safe_open(line, O_WRONLY|O_CREAT|O_NOFOLLOW, 0770)) < 0)
580df930be7Sderaadt 			printf("\tcannot create lock file\n");
581df930be7Sderaadt 		else {
5826468ba68Smillert 			(void)fchown(fd, DEFUID, -1);
583df930be7Sderaadt 			(void)close(fd);
584df930be7Sderaadt 			printf("\tprinter and queuing disabled\n");
585df930be7Sderaadt 		}
5866468ba68Smillert 		PRIV_END;
587df930be7Sderaadt 		return;
588df930be7Sderaadt 	} else
589df930be7Sderaadt 		printf("\tcannot stat lock file\n");
590df930be7Sderaadt 	/*
591df930be7Sderaadt 	 * Write the message into the status file.
592df930be7Sderaadt 	 */
5937416c11cSmillert 	(void)snprintf(line, sizeof(line), "%s/%s", SD, ST);
5946468ba68Smillert 	fd = safe_open(line, O_WRONLY|O_CREAT|O_NOFOLLOW, 0660);
595df930be7Sderaadt 	if (fd < 0 || flock(fd, LOCK_EX) < 0) {
596df930be7Sderaadt 		printf("\tcannot create status file\n");
59795cb4a2fSkrw 		if (fd >= 0)
59895cb4a2fSkrw 			(void)close(fd);	/* unlocks as well */
5996468ba68Smillert 		PRIV_END;
600df930be7Sderaadt 		return;
601df930be7Sderaadt 	}
6026468ba68Smillert 	PRIV_END;
6036468ba68Smillert 	(void)fchown(fd, DEFUID, -1);
604df930be7Sderaadt 	(void)ftruncate(fd, 0);
605df930be7Sderaadt 	if (argc <= 0) {
606df930be7Sderaadt 		(void)write(fd, "\n", 1);
607df930be7Sderaadt 		(void)close(fd);
608df930be7Sderaadt 		return;
609df930be7Sderaadt 	}
610df930be7Sderaadt 	cp1 = buf;
611df930be7Sderaadt 	while (--argc >= 0) {
612df930be7Sderaadt 		cp2 = *argv++;
613c9e7d913Spjanzen 		while ((cp1 - buf) < sizeof(buf) - 1 && (*cp1++ = *cp2++))
614df930be7Sderaadt 			;
615df930be7Sderaadt 		cp1[-1] = ' ';
616df930be7Sderaadt 	}
617df930be7Sderaadt 	cp1[-1] = '\n';
618df930be7Sderaadt 	*cp1 = '\0';
619df930be7Sderaadt 	(void)write(fd, buf, strlen(buf));
620df930be7Sderaadt 	(void)close(fd);
621df930be7Sderaadt }
622df930be7Sderaadt 
623df930be7Sderaadt /*
624df930be7Sderaadt  * Exit lpc
625df930be7Sderaadt  */
626df930be7Sderaadt void
quit(int argc,char ** argv)627a7643117Smillert quit(int argc, char **argv)
628df930be7Sderaadt {
629df930be7Sderaadt 	exit(0);
630df930be7Sderaadt }
631df930be7Sderaadt 
632df930be7Sderaadt /*
633df930be7Sderaadt  * Kill and restart the daemon.
634df930be7Sderaadt  */
635df930be7Sderaadt void
restart(int argc,char ** argv)636a7643117Smillert restart(int argc, char **argv)
637df930be7Sderaadt {
638c1624b2fSmillert 	int c, status;
639c1624b2fSmillert 	char *cp1, *cp2;
640df930be7Sderaadt 	char prbuf[100];
641df930be7Sderaadt 
642df930be7Sderaadt 	if (argc == 1) {
6431d8c2aacSsobrado 		printf("usage: restart {all | printer ...}\n");
644df930be7Sderaadt 		return;
645df930be7Sderaadt 	}
646a7643117Smillert 	if (argc == 2 && strcmp(argv[1], "all") == 0) {
647df930be7Sderaadt 		printer = prbuf;
648df930be7Sderaadt 		while (cgetnext(&bp, printcapdb) > 0) {
649df930be7Sderaadt 			cp1 = prbuf;
650df930be7Sderaadt 			cp2 = bp;
6517416c11cSmillert 			while ((c = *cp2++) && c != '|' && c != ':' &&
652c9e7d913Spjanzen 			    (cp1 - prbuf) < sizeof(prbuf) - 1)
653df930be7Sderaadt 				*cp1++ = c;
654df930be7Sderaadt 			*cp1 = '\0';
655df930be7Sderaadt 			abortpr(0);
656df930be7Sderaadt 			startpr(0);
657df930be7Sderaadt 		}
658df930be7Sderaadt 		return;
659df930be7Sderaadt 	}
660df930be7Sderaadt 	while (--argc) {
661df930be7Sderaadt 		printer = *++argv;
662df930be7Sderaadt 		if ((status = cgetent(&bp, printcapdb, printer)) == -2) {
663df930be7Sderaadt 			printf("cannot open printer description file\n");
664df930be7Sderaadt 			continue;
665df930be7Sderaadt 		} else if (status == -1) {
666df930be7Sderaadt 			printf("unknown printer %s\n", printer);
667df930be7Sderaadt 			continue;
668df930be7Sderaadt 		} else if (status == -3)
669df930be7Sderaadt 			fatal("potential reference loop detected in printcap file");
670df930be7Sderaadt 
671df930be7Sderaadt 		abortpr(0);
672df930be7Sderaadt 		startpr(0);
673df930be7Sderaadt 	}
674df930be7Sderaadt }
675df930be7Sderaadt 
676df930be7Sderaadt /*
677df930be7Sderaadt  * Enable printing on the specified printer and startup the daemon.
678df930be7Sderaadt  */
679df930be7Sderaadt void
startcmd(int argc,char ** argv)680a7643117Smillert startcmd(int argc, char **argv)
681df930be7Sderaadt {
682c1624b2fSmillert 	int c, status;
683c1624b2fSmillert 	char *cp1, *cp2;
684df930be7Sderaadt 	char prbuf[100];
685df930be7Sderaadt 
686df930be7Sderaadt 	if (argc == 1) {
6871d8c2aacSsobrado 		printf("usage: start {all | printer ...}\n");
688df930be7Sderaadt 		return;
689df930be7Sderaadt 	}
690a7643117Smillert 	if (argc == 2 && strcmp(argv[1], "all") == 0) {
691df930be7Sderaadt 		printer = prbuf;
692df930be7Sderaadt 		while (cgetnext(&bp, printcapdb) > 0) {
693df930be7Sderaadt 			cp1 = prbuf;
694df930be7Sderaadt 			cp2 = bp;
6957416c11cSmillert 			while ((c = *cp2++) && c != '|' && c != ':' &&
696c9e7d913Spjanzen 			    (cp1 - prbuf) < sizeof(prbuf) - 1)
697df930be7Sderaadt 				*cp1++ = c;
698df930be7Sderaadt 			*cp1 = '\0';
699df930be7Sderaadt 			startpr(1);
700df930be7Sderaadt 		}
701df930be7Sderaadt 		return;
702df930be7Sderaadt 	}
703df930be7Sderaadt 	while (--argc) {
704df930be7Sderaadt 		printer = *++argv;
705df930be7Sderaadt 		if ((status = cgetent(&bp, printcapdb, printer)) == -2) {
706df930be7Sderaadt 			printf("cannot open printer description file\n");
707df930be7Sderaadt 			continue;
708df930be7Sderaadt 		} else if (status == -1) {
709df930be7Sderaadt 			printf("unknown printer %s\n", printer);
710df930be7Sderaadt 			continue;
711df930be7Sderaadt 		} else if (status == -3)
712df930be7Sderaadt 			fatal("potential reference loop detected in printcap file");
713df930be7Sderaadt 
714df930be7Sderaadt 		startpr(1);
715df930be7Sderaadt 	}
716df930be7Sderaadt }
717df930be7Sderaadt 
718a7643117Smillert static void
startpr(int enable)719a7643117Smillert startpr(int enable)
720df930be7Sderaadt {
721df930be7Sderaadt 	struct stat stbuf;
722df930be7Sderaadt 
723df930be7Sderaadt 	if (cgetstr(bp, "sd", &SD) == -1)
724df930be7Sderaadt 		SD = _PATH_DEFSPOOL;
725df930be7Sderaadt 	if (cgetstr(bp, "lo", &LO) == -1)
726df930be7Sderaadt 		LO = DEFLOCK;
7277416c11cSmillert 	(void)snprintf(line, sizeof(line), "%s/%s", SD, LO);
728df930be7Sderaadt 	printf("%s:\n", printer);
729df930be7Sderaadt 
730df930be7Sderaadt 	/*
731df930be7Sderaadt 	 * Turn off the owner execute bit of the lock file to enable printing.
7326468ba68Smillert 	 * If we are marking the printer "up" also turn off group execute bit.
733df930be7Sderaadt 	 */
7346468ba68Smillert 	PRIV_START;
735df930be7Sderaadt 	if (enable && stat(line, &stbuf) >= 0) {
7366468ba68Smillert 		if (enable == 2)
7376468ba68Smillert 			stbuf.st_mode &= ~(S_IXUSR|S_IXGRP);
7386468ba68Smillert 		else
7396468ba68Smillert 			stbuf.st_mode &= ~S_IXUSR;
7406468ba68Smillert 		if (chmod(line, stbuf.st_mode & 0777) < 0)
741df930be7Sderaadt 			printf("\tcannot enable printing\n");
742df930be7Sderaadt 		else
743df930be7Sderaadt 			printf("\tprinting enabled\n");
744df930be7Sderaadt 	}
7456468ba68Smillert 	PRIV_END;
746df930be7Sderaadt 	if (!startdaemon(printer))
747df930be7Sderaadt 		printf("\tcouldn't start daemon\n");
748df930be7Sderaadt 	else
749df930be7Sderaadt 		printf("\tdaemon started\n");
750df930be7Sderaadt }
751df930be7Sderaadt 
752df930be7Sderaadt /*
753df930be7Sderaadt  * Print the status of each queue listed or all the queues.
754df930be7Sderaadt  */
755df930be7Sderaadt void
status(int argc,char ** argv)756a7643117Smillert status(int argc, char **argv)
757df930be7Sderaadt {
758c1624b2fSmillert 	int c, status;
759c1624b2fSmillert 	char *cp1, *cp2;
760df930be7Sderaadt 	char prbuf[100];
761df930be7Sderaadt 
762a7643117Smillert 	if (argc == 1 || (argc == 2 && strcmp(argv[1], "all") == 0)) {
763df930be7Sderaadt 		printer = prbuf;
764df930be7Sderaadt 		while (cgetnext(&bp, printcapdb) > 0) {
765df930be7Sderaadt 			cp1 = prbuf;
766df930be7Sderaadt 			cp2 = bp;
7677416c11cSmillert 			while ((c = *cp2++) && c != '|' && c != ':' &&
768c9e7d913Spjanzen 			    (cp1 - prbuf) < sizeof(prbuf) - 1)
769df930be7Sderaadt 				*cp1++ = c;
770df930be7Sderaadt 			*cp1 = '\0';
771df930be7Sderaadt 			prstat();
772df930be7Sderaadt 		}
773df930be7Sderaadt 		return;
774df930be7Sderaadt 	}
775df930be7Sderaadt 	while (--argc) {
776df930be7Sderaadt 		printer = *++argv;
777df930be7Sderaadt 		if ((status = cgetent(&bp, printcapdb, printer)) == -2) {
778df930be7Sderaadt 			printf("cannot open printer description file\n");
779df930be7Sderaadt 			continue;
780df930be7Sderaadt 		} else if (status == -1) {
781df930be7Sderaadt 			printf("unknown printer %s\n", printer);
782df930be7Sderaadt 			continue;
783df930be7Sderaadt 		} else if (status == -3)
784df930be7Sderaadt 			fatal("potential reference loop detected in printcap file");
785df930be7Sderaadt 
786df930be7Sderaadt 		prstat();
787df930be7Sderaadt 	}
788df930be7Sderaadt }
789df930be7Sderaadt 
790df930be7Sderaadt /*
791df930be7Sderaadt  * Print the status of the printer queue.
792df930be7Sderaadt  */
793a7643117Smillert static void
prstat(void)794a7643117Smillert prstat(void)
795df930be7Sderaadt {
796df930be7Sderaadt 	struct stat stbuf;
797c1624b2fSmillert 	int fd, i;
798c1624b2fSmillert 	struct dirent *dp;
799df930be7Sderaadt 	DIR *dirp;
800df930be7Sderaadt 
801df930be7Sderaadt 	if (cgetstr(bp, "sd", &SD) == -1)
802df930be7Sderaadt 		SD = _PATH_DEFSPOOL;
803df930be7Sderaadt 	if (cgetstr(bp, "lo", &LO) == -1)
804df930be7Sderaadt 		LO = DEFLOCK;
805df930be7Sderaadt 	if (cgetstr(bp, "st", &ST) == -1)
806df930be7Sderaadt 		ST = DEFSTAT;
807df930be7Sderaadt 	printf("%s:\n", printer);
8087416c11cSmillert 	(void)snprintf(line, sizeof(line), "%s/%s", SD, LO);
8096468ba68Smillert 	PRIV_START;
8106468ba68Smillert 	i = stat(line, &stbuf);
8116468ba68Smillert 	PRIV_END;
8126468ba68Smillert 	if (i >= 0) {
813df930be7Sderaadt 		printf("\tqueuing is %s\n",
814df930be7Sderaadt 			(stbuf.st_mode & 010) ? "disabled" : "enabled");
815df930be7Sderaadt 		printf("\tprinting is %s\n",
816df930be7Sderaadt 			(stbuf.st_mode & 0100) ? "disabled" : "enabled");
817df930be7Sderaadt 	} else {
818df930be7Sderaadt 		printf("\tqueuing is enabled\n");
819df930be7Sderaadt 		printf("\tprinting is enabled\n");
820df930be7Sderaadt 	}
8216468ba68Smillert 	PRIV_START;
8226468ba68Smillert 	dirp = opendir(SD);
8236468ba68Smillert 	PRIV_END;
8246468ba68Smillert 	if (dirp == NULL) {
825df930be7Sderaadt 		printf("\tcannot examine spool directory\n");
826df930be7Sderaadt 		return;
827df930be7Sderaadt 	}
828df930be7Sderaadt 	i = 0;
829df930be7Sderaadt 	while ((dp = readdir(dirp)) != NULL) {
830df930be7Sderaadt 		if (*dp->d_name == 'c' && dp->d_name[1] == 'f')
831df930be7Sderaadt 			i++;
832df930be7Sderaadt 	}
833df930be7Sderaadt 	closedir(dirp);
834df930be7Sderaadt 	if (i == 0)
835df930be7Sderaadt 		printf("\tno entries\n");
836df930be7Sderaadt 	else if (i == 1)
837df930be7Sderaadt 		printf("\t1 entry in spool area\n");
838df930be7Sderaadt 	else
839df930be7Sderaadt 		printf("\t%d entries in spool area\n", i);
8406468ba68Smillert 	PRIV_START;
8416468ba68Smillert 	fd = safe_open(line, O_RDONLY|O_NOFOLLOW, 0);
8426468ba68Smillert 	PRIV_END;
843df930be7Sderaadt 	if (fd < 0 || flock(fd, LOCK_SH|LOCK_NB) == 0) {
8448d476b29Sderaadt 		printf("\tprinter idle\n");
84595cb4a2fSkrw 		if (fd >= 0)
84695cb4a2fSkrw 			(void)close(fd);	/* unlocks as well */
847df930be7Sderaadt 		return;
848df930be7Sderaadt 	}
849df930be7Sderaadt 	(void)close(fd);
8507416c11cSmillert 	(void)snprintf(line, sizeof(line), "%s/%s", SD, ST);
8516468ba68Smillert 	PRIV_START;
8526468ba68Smillert 	fd = safe_open(line, O_RDONLY|O_NOFOLLOW, 0);
8536468ba68Smillert 	PRIV_END;
854df930be7Sderaadt 	if (fd >= 0) {
855df930be7Sderaadt 		(void)flock(fd, LOCK_SH);
856a7643117Smillert 		if (fstat(fd, &stbuf) == 0 && stbuf.st_size > 0) {
857a7643117Smillert 			putchar('\t');
858df930be7Sderaadt 			while ((i = read(fd, line, sizeof(line))) > 0)
859df930be7Sderaadt 				(void)fwrite(line, 1, i, stdout);
860a7643117Smillert 		}
861df930be7Sderaadt 		(void)close(fd);	/* unlocks as well */
862df930be7Sderaadt 	}
863df930be7Sderaadt }
864df930be7Sderaadt 
865df930be7Sderaadt /*
866df930be7Sderaadt  * Stop the specified daemon after completing the current job and disable
867df930be7Sderaadt  * printing.
868df930be7Sderaadt  */
869df930be7Sderaadt void
stop(int argc,char ** argv)870a7643117Smillert stop(int argc, char **argv)
871df930be7Sderaadt {
872c1624b2fSmillert 	int c, status;
873c1624b2fSmillert 	char *cp1, *cp2;
874df930be7Sderaadt 	char prbuf[100];
875df930be7Sderaadt 
876df930be7Sderaadt 	if (argc == 1) {
8771d8c2aacSsobrado 		printf("usage: stop {all | printer ...}\n");
878df930be7Sderaadt 		return;
879df930be7Sderaadt 	}
880a7643117Smillert 	if (argc == 2 && strcmp(argv[1], "all") == 0) {
881df930be7Sderaadt 		printer = prbuf;
882df930be7Sderaadt 		while (cgetnext(&bp, printcapdb) > 0) {
883df930be7Sderaadt 			cp1 = prbuf;
884df930be7Sderaadt 			cp2 = bp;
8857416c11cSmillert 			while ((c = *cp2++) && c != '|' && c != ':' &&
886c9e7d913Spjanzen 			    (cp1 - prbuf) < sizeof(prbuf) - 1)
887df930be7Sderaadt 				*cp1++ = c;
888df930be7Sderaadt 			*cp1 = '\0';
889df930be7Sderaadt 			stoppr();
890df930be7Sderaadt 		}
891df930be7Sderaadt 		return;
892df930be7Sderaadt 	}
893df930be7Sderaadt 	while (--argc) {
894df930be7Sderaadt 		printer = *++argv;
895df930be7Sderaadt 		if ((status = cgetent(&bp, printcapdb, printer)) == -2) {
896df930be7Sderaadt 			printf("cannot open printer description file\n");
897df930be7Sderaadt 			continue;
898df930be7Sderaadt 		} else if (status == -1) {
899df930be7Sderaadt 			printf("unknown printer %s\n", printer);
900df930be7Sderaadt 			continue;
901df930be7Sderaadt 		} else if (status == -3)
902df930be7Sderaadt 			fatal("potential reference loop detected in printcap file");
903df930be7Sderaadt 
904df930be7Sderaadt 		stoppr();
905df930be7Sderaadt 	}
906df930be7Sderaadt }
907df930be7Sderaadt 
908a7643117Smillert static void
stoppr(void)909a7643117Smillert stoppr(void)
910df930be7Sderaadt {
911c1624b2fSmillert 	int fd;
912df930be7Sderaadt 	struct stat stbuf;
913df930be7Sderaadt 
914df930be7Sderaadt 	if (cgetstr(bp, "sd", &SD) == -1)
915df930be7Sderaadt 		SD = _PATH_DEFSPOOL;
916df930be7Sderaadt 	if (cgetstr(bp, "lo", &LO) == -1)
917df930be7Sderaadt 		LO = DEFLOCK;
9187416c11cSmillert 	(void)snprintf(line, sizeof(line), "%s/%s", SD, LO);
919df930be7Sderaadt 	printf("%s:\n", printer);
920df930be7Sderaadt 
921df930be7Sderaadt 	/*
922df930be7Sderaadt 	 * Turn on the owner execute bit of the lock file to disable printing.
923df930be7Sderaadt 	 */
9246468ba68Smillert 	PRIV_START;
925df930be7Sderaadt 	if (stat(line, &stbuf) >= 0) {
9266468ba68Smillert 		stbuf.st_mode |= S_IXUSR;
9276468ba68Smillert 		if (chmod(line, stbuf.st_mode & 0777) < 0)
928df930be7Sderaadt 			printf("\tcannot disable printing\n");
929df930be7Sderaadt 		else {
930df930be7Sderaadt 			upstat("printing disabled\n");
931df930be7Sderaadt 			printf("\tprinting disabled\n");
932df930be7Sderaadt 		}
933df930be7Sderaadt 	} else if (errno == ENOENT) {
9346468ba68Smillert 		if ((fd = safe_open(line, O_WRONLY|O_CREAT|O_NOFOLLOW, 0760)) < 0)
935df930be7Sderaadt 			printf("\tcannot create lock file\n");
936df930be7Sderaadt 		else {
9376468ba68Smillert 			(void)fchown(fd, DEFUID, -1);
938df930be7Sderaadt 			(void)close(fd);
939df930be7Sderaadt 			upstat("printing disabled\n");
940df930be7Sderaadt 			printf("\tprinting disabled\n");
941df930be7Sderaadt 		}
942df930be7Sderaadt 	} else
943df930be7Sderaadt 		printf("\tcannot stat lock file\n");
9446468ba68Smillert 	PRIV_END;
945df930be7Sderaadt }
946df930be7Sderaadt 
947df930be7Sderaadt struct	queue **queue;
948df930be7Sderaadt int	nitems;
949df930be7Sderaadt time_t	mtime;
950df930be7Sderaadt 
951df930be7Sderaadt /*
952df930be7Sderaadt  * Put the specified jobs at the top of printer queue.
953df930be7Sderaadt  */
954df930be7Sderaadt void
topq(int argc,char ** argv)955a7643117Smillert topq(int argc, char **argv)
956df930be7Sderaadt {
957c1624b2fSmillert 	int i;
958df930be7Sderaadt 	struct stat stbuf;
959df930be7Sderaadt 	int status, changed;
960df930be7Sderaadt 
961df930be7Sderaadt 	if (argc < 3) {
9621d8c2aacSsobrado 		printf("usage: topq printer [jobnum ...] [user ...]\n");
963df930be7Sderaadt 		return;
964df930be7Sderaadt 	}
965df930be7Sderaadt 
966df930be7Sderaadt 	--argc;
967df930be7Sderaadt 	printer = *++argv;
968df930be7Sderaadt 	status = cgetent(&bp, printcapdb, printer);
969df930be7Sderaadt 	if (status == -2) {
970df930be7Sderaadt 		printf("cannot open printer description file\n");
971df930be7Sderaadt 		return;
972df930be7Sderaadt 	} else if (status == -1) {
973df930be7Sderaadt 		printf("%s: unknown printer\n", printer);
974df930be7Sderaadt 		return;
975df930be7Sderaadt 	} else if (status == -3)
976df930be7Sderaadt 		fatal("potential reference loop detected in printcap file");
977df930be7Sderaadt 
978df930be7Sderaadt 	if (cgetstr(bp, "sd", &SD) == -1)
979df930be7Sderaadt 		SD = _PATH_DEFSPOOL;
980df930be7Sderaadt 	if (cgetstr(bp, "lo", &LO) == -1)
981df930be7Sderaadt 		LO = DEFLOCK;
982df930be7Sderaadt 	printf("%s:\n", printer);
983df930be7Sderaadt 
9846468ba68Smillert 	PRIV_START;
985df930be7Sderaadt 	if (chdir(SD) < 0) {
986df930be7Sderaadt 		printf("\tcannot chdir to %s\n", SD);
987df930be7Sderaadt 		goto out;
988df930be7Sderaadt 	}
9896468ba68Smillert 	PRIV_END;
990df930be7Sderaadt 	nitems = getq(&queue);
991df930be7Sderaadt 	if (nitems == 0)
992df930be7Sderaadt 		return;
993df930be7Sderaadt 	changed = 0;
994df930be7Sderaadt 	mtime = queue[0]->q_time;
995df930be7Sderaadt 	for (i = argc; --i; ) {
996df930be7Sderaadt 		if (doarg(argv[i]) == 0) {
997df930be7Sderaadt 			printf("\tjob %s is not in the queue\n", argv[i]);
998df930be7Sderaadt 			continue;
999df930be7Sderaadt 		} else
1000df930be7Sderaadt 			changed++;
1001df930be7Sderaadt 	}
1002df930be7Sderaadt 	for (i = 0; i < nitems; i++)
1003df930be7Sderaadt 		free(queue[i]);
1004df930be7Sderaadt 	free(queue);
1005df930be7Sderaadt 	if (!changed) {
1006df930be7Sderaadt 		printf("\tqueue order unchanged\n");
1007df930be7Sderaadt 		return;
1008df930be7Sderaadt 	}
1009df930be7Sderaadt 	/*
1010df930be7Sderaadt 	 * Turn on the public execute bit of the lock file to
1011df930be7Sderaadt 	 * get lpd to rebuild the queue after the current job.
1012df930be7Sderaadt 	 */
10136468ba68Smillert 	PRIV_START;
10146468ba68Smillert 	if (changed && stat(LO, &stbuf) >= 0) {
10156468ba68Smillert 		stbuf.st_mode |= S_IXOTH;
10166468ba68Smillert 		(void)chmod(LO, stbuf.st_mode & 0777);
10176468ba68Smillert 	}
1018df930be7Sderaadt 
1019df930be7Sderaadt out:
10206468ba68Smillert 	PRIV_END;
1021df930be7Sderaadt }
1022df930be7Sderaadt 
1023df930be7Sderaadt /*
1024df930be7Sderaadt  * Reposition the job by changing the modification time of
1025df930be7Sderaadt  * the control file.
1026df930be7Sderaadt  */
1027a7643117Smillert static int
touch(struct queue * q)1028a7643117Smillert touch(struct queue *q)
1029df930be7Sderaadt {
1030df930be7Sderaadt 	struct timeval tvp[2];
1031df930be7Sderaadt 	int ret;
1032df930be7Sderaadt 
1033df930be7Sderaadt 	tvp[0].tv_sec = tvp[1].tv_sec = --mtime;
1034df930be7Sderaadt 	tvp[0].tv_usec = tvp[1].tv_usec = 0;
10356468ba68Smillert 	PRIV_START;
1036df930be7Sderaadt 	ret = utimes(q->q_name, tvp);
10376468ba68Smillert 	PRIV_END;
1038df930be7Sderaadt 	return (ret);
1039df930be7Sderaadt }
1040df930be7Sderaadt 
1041df930be7Sderaadt /*
1042df930be7Sderaadt  * Checks if specified job name is in the printer's queue.
1043df930be7Sderaadt  * Returns:  negative (-1) if argument name is not in the queue.
1044df930be7Sderaadt  */
10450321e45eSderaadt int
doarg(char * job)1046a7643117Smillert doarg(char *job)
1047df930be7Sderaadt {
1048c1624b2fSmillert 	struct queue **qq;
10496468ba68Smillert 	int jobnum, fd, n;
1050c1624b2fSmillert 	char *cp, *machine;
1051df930be7Sderaadt 	int cnt = 0;
1052df930be7Sderaadt 	FILE *fp;
1053df930be7Sderaadt 
1054df930be7Sderaadt 	/*
1055df930be7Sderaadt 	 * Look for a job item consisting of system name, colon, number
1056df930be7Sderaadt 	 * (example: ucbarpa:114)
1057df930be7Sderaadt 	 */
105820a848d0Smillert 	if ((cp = strchr(job, ':')) != NULL) {
1059df930be7Sderaadt 		machine = job;
1060df930be7Sderaadt 		*cp++ = '\0';
1061df930be7Sderaadt 		job = cp;
1062df930be7Sderaadt 	} else
1063df930be7Sderaadt 		machine = NULL;
1064df930be7Sderaadt 
1065df930be7Sderaadt 	/*
1066df930be7Sderaadt 	 * Check for job specified by number (example: 112 or 235ucbarpa).
1067df930be7Sderaadt 	 */
10680c4db8c1Sderaadt 	if (isdigit((unsigned char)*job)) {
1069df930be7Sderaadt 		jobnum = 0;
1070df930be7Sderaadt 		do
1071df930be7Sderaadt 			jobnum = jobnum * 10 + (*job++ - '0');
10720c4db8c1Sderaadt 		while (isdigit((unsigned char)*job));
1073df930be7Sderaadt 		for (qq = queue + nitems; --qq >= queue; ) {
1074df930be7Sderaadt 			n = 0;
10750c4db8c1Sderaadt 			for (cp = (*qq)->q_name+3; isdigit((unsigned char)*cp); )
1076df930be7Sderaadt 				n = n * 10 + (*cp++ - '0');
1077df930be7Sderaadt 			if (jobnum != n)
1078df930be7Sderaadt 				continue;
1079df930be7Sderaadt 			if (*job && strcmp(job, cp) != 0)
1080df930be7Sderaadt 				continue;
1081df930be7Sderaadt 			if (machine != NULL && strcmp(machine, cp) != 0)
1082df930be7Sderaadt 				continue;
1083df930be7Sderaadt 			if (touch(*qq) == 0) {
1084df930be7Sderaadt 				printf("\tmoved %s\n", (*qq)->q_name);
1085df930be7Sderaadt 				cnt++;
1086df930be7Sderaadt 			}
1087df930be7Sderaadt 		}
1088df930be7Sderaadt 		return(cnt);
1089df930be7Sderaadt 	}
1090df930be7Sderaadt 	/*
1091df930be7Sderaadt 	 * Process item consisting of owner's name (example: henry).
1092df930be7Sderaadt 	 */
1093df930be7Sderaadt 	for (qq = queue + nitems; --qq >= queue; ) {
10946468ba68Smillert 		PRIV_START;
10956468ba68Smillert 		fd = safe_open((*qq)->q_name, O_RDONLY|O_NOFOLLOW, 0);
10966468ba68Smillert 		PRIV_END;
10976468ba68Smillert 		if (fd < 0 || (fp = fdopen(fd, "r")) == NULL) {
10986468ba68Smillert 			if (fd >= 0)
10996468ba68Smillert 				close(fd);
1100df930be7Sderaadt 			continue;
11016468ba68Smillert 		}
1102f9bbbf45Sfgsch 		while (get_line(fp) > 0)
1103df930be7Sderaadt 			if (line[0] == 'P')
1104df930be7Sderaadt 				break;
1105df930be7Sderaadt 		(void)fclose(fp);
1106df930be7Sderaadt 		if (line[0] != 'P' || strcmp(job, line+1) != 0)
1107df930be7Sderaadt 			continue;
1108df930be7Sderaadt 		if (touch(*qq) == 0) {
1109df930be7Sderaadt 			printf("\tmoved %s\n", (*qq)->q_name);
1110df930be7Sderaadt 			cnt++;
1111df930be7Sderaadt 		}
1112df930be7Sderaadt 	}
1113df930be7Sderaadt 	return(cnt);
1114df930be7Sderaadt }
1115df930be7Sderaadt 
1116df930be7Sderaadt /*
1117df930be7Sderaadt  * Enable everything and start printer (undo `down').
1118df930be7Sderaadt  */
1119df930be7Sderaadt void
up(int argc,char ** argv)1120a7643117Smillert up(int argc, char **argv)
1121df930be7Sderaadt {
1122c1624b2fSmillert 	int c, status;
1123c1624b2fSmillert 	char *cp1, *cp2;
1124df930be7Sderaadt 	char prbuf[100];
1125df930be7Sderaadt 
1126df930be7Sderaadt 	if (argc == 1) {
11271d8c2aacSsobrado 		printf("usage: up {all | printer ...}\n");
1128df930be7Sderaadt 		return;
1129df930be7Sderaadt 	}
1130a7643117Smillert 	if (argc == 2 && strcmp(argv[1], "all") == 0) {
1131df930be7Sderaadt 		printer = prbuf;
1132df930be7Sderaadt 		while (cgetnext(&bp, printcapdb) > 0) {
1133df930be7Sderaadt 			cp1 = prbuf;
1134df930be7Sderaadt 			cp2 = bp;
11357416c11cSmillert 			while ((c = *cp2++) && c != '|' && c != ':' &&
1136c9e7d913Spjanzen 			    (cp1 - prbuf) < sizeof(prbuf) - 1)
1137df930be7Sderaadt 				*cp1++ = c;
1138df930be7Sderaadt 			*cp1 = '\0';
1139df930be7Sderaadt 			startpr(2);
1140df930be7Sderaadt 		}
1141df930be7Sderaadt 		return;
1142df930be7Sderaadt 	}
1143df930be7Sderaadt 	while (--argc) {
1144df930be7Sderaadt 		printer = *++argv;
1145df930be7Sderaadt 		if ((status = cgetent(&bp, printcapdb, printer)) == -2) {
1146df930be7Sderaadt 			printf("cannot open printer description file\n");
1147df930be7Sderaadt 			continue;
1148df930be7Sderaadt 		} else if (status == -1) {
1149df930be7Sderaadt 			printf("unknown printer %s\n", printer);
1150df930be7Sderaadt 			continue;
1151df930be7Sderaadt 		} else if (status == -3)
1152df930be7Sderaadt 			fatal("potential reference loop detected in printcap file");
1153df930be7Sderaadt 
1154df930be7Sderaadt 		startpr(2);
1155df930be7Sderaadt 	}
1156df930be7Sderaadt }
1157