xref: /freebsd/usr.sbin/lpr/common_source/common.c (revision 04c9749ff0148ec8f73b150cec8bc2c094a5d31a)
1 /*
2  * Copyright (c) 1983, 1993
3  *	The Regents of the University of California.  All rights reserved.
4  * (c) UNIX System Laboratories, Inc.
5  * All or some portions of this file are derived from material licensed
6  * to the University of California by American Telephone and Telegraph
7  * Co. or Unix System Laboratories, Inc. and are reproduced herein with
8  * the permission of UNIX System Laboratories, Inc.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  * 3. All advertising materials mentioning features or use of this software
19  *    must display the following acknowledgement:
20  *	This product includes software developed by the University of
21  *	California, Berkeley and its contributors.
22  * 4. Neither the name of the University nor the names of its contributors
23  *    may be used to endorse or promote products derived from this software
24  *    without specific prior written permission.
25  *
26  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
27  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
28  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
29  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
30  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
31  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
32  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
33  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
34  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
35  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
36  * SUCH DAMAGE.
37  */
38 
39 #ifndef lint
40 /*
41 static char sccsid[] = "@(#)common.c	8.5 (Berkeley) 4/28/95";
42 */
43 static const char rcsid[] =
44   "$FreeBSD$";
45 #endif /* not lint */
46 
47 #include <sys/param.h>
48 #include <sys/stat.h>
49 #include <sys/time.h>
50 
51 #include <dirent.h>
52 #include <stdio.h>
53 #include <stdlib.h>
54 #include <string.h>
55 #include <unistd.h>
56 
57 #include "lp.h"
58 #include "lp.local.h"
59 #include "pathnames.h"
60 
61 /*
62  * Routines and data common to all the line printer functions.
63  */
64 char	line[BUFSIZ];
65 char	*name;		/* program name */
66 
67 extern uid_t	uid, euid;
68 
69 static int compar __P((const void *, const void *));
70 
71 /*
72  * Getline reads a line from the control file cfp, removes tabs, converts
73  *  new-line to null and leaves it in line.
74  * Returns 0 at EOF or the number of characters read.
75  */
76 int
77 getline(cfp)
78 	FILE *cfp;
79 {
80 	register int linel = 0;
81 	register char *lp = line;
82 	register int c;
83 
84 	while ((c = getc(cfp)) != '\n' && linel+1 < sizeof(line)) {
85 		if (c == EOF)
86 			return(0);
87 		if (c == '\t') {
88 			do {
89 				*lp++ = ' ';
90 				linel++;
91 			} while ((linel & 07) != 0 && linel+1 < sizeof(line));
92 			continue;
93 		}
94 		*lp++ = c;
95 		linel++;
96 	}
97 	*lp++ = '\0';
98 	return(linel);
99 }
100 
101 /*
102  * Scan the current directory and make a list of daemon files sorted by
103  * creation time.
104  * Return the number of entries and a pointer to the list.
105  */
106 int
107 getq(pp, namelist)
108 	const struct printer *pp;
109 	struct queue *(*namelist[]);
110 {
111 	register struct dirent *d;
112 	register struct queue *q, **queue;
113 	register int nitems;
114 	struct stat stbuf;
115 	DIR *dirp;
116 	int arraysz;
117 
118 	seteuid(euid);
119 	if ((dirp = opendir(pp->spool_dir)) == NULL)
120 		return(-1);
121 	if (fstat(dirp->dd_fd, &stbuf) < 0)
122 		goto errdone;
123 	seteuid(uid);
124 
125 	/*
126 	 * Estimate the array size by taking the size of the directory file
127 	 * and dividing it by a multiple of the minimum size entry.
128 	 */
129 	arraysz = (stbuf.st_size / 24);
130 	queue = (struct queue **)malloc(arraysz * sizeof(struct queue *));
131 	if (queue == NULL)
132 		goto errdone;
133 
134 	nitems = 0;
135 	while ((d = readdir(dirp)) != NULL) {
136 		if (d->d_name[0] != 'c' || d->d_name[1] != 'f')
137 			continue;	/* daemon control files only */
138 		seteuid(euid);
139 		if (stat(d->d_name, &stbuf) < 0)
140 			continue;	/* Doesn't exist */
141 		seteuid(uid);
142 		q = (struct queue *)malloc(sizeof(time_t)+strlen(d->d_name)+1);
143 		if (q == NULL)
144 			goto errdone;
145 		q->q_time = stbuf.st_mtime;
146 		strcpy(q->q_name, d->d_name);
147 		/*
148 		 * Check to make sure the array has space left and
149 		 * realloc the maximum size.
150 		 */
151 		if (++nitems > arraysz) {
152 			arraysz *= 2;
153 			queue = (struct queue **)realloc((char *)queue,
154 				arraysz * sizeof(struct queue *));
155 			if (queue == NULL)
156 				goto errdone;
157 		}
158 		queue[nitems-1] = q;
159 	}
160 	closedir(dirp);
161 	if (nitems)
162 		qsort(queue, nitems, sizeof(struct queue *), compar);
163 	*namelist = queue;
164 	return(nitems);
165 
166 errdone:
167 	closedir(dirp);
168 	return(-1);
169 }
170 
171 /*
172  * Compare modification times.
173  */
174 static int
175 compar(p1, p2)
176 	const void *p1, *p2;
177 {
178 	const struct queue *qe1, *qe2;
179 	qe1 = *(const struct queue **)p1;
180 	qe2 = *(const struct queue **)p2;
181 
182 	if (qe1->q_time < qe2->q_time)
183 		return (-1);
184 	if (qe1->q_time > qe2->q_time)
185 		return (1);
186 	/*
187 	 * At this point, the two files have the same last-modification time.
188 	 * return a result based on filenames, so that 'cfA001some.host' will
189 	 * come before 'cfA002some.host'.  Since the jobid ('001') will wrap
190 	 * around when it gets to '999', we also assume that '9xx' jobs are
191 	 * older than '0xx' jobs.
192 	*/
193 	if ((qe1->q_name[3] == '9') && (qe2->q_name[3] == '0'))
194 		return (-1);
195 	if ((qe1->q_name[3] == '0') && (qe2->q_name[3] == '9'))
196 		return (1);
197 	return (strcmp(qe1->q_name,qe2->q_name));
198 }
199 
200 /* sleep n milliseconds */
201 void
202 delay(n)
203 	int n;
204 {
205 	struct timeval tdelay;
206 
207 	if (n <= 0 || n > 10000)
208 		fatal((struct printer *)0, /* fatal() knows how to deal */
209 		      "unreasonable delay period (%d)", n);
210 	tdelay.tv_sec = n / 1000;
211 	tdelay.tv_usec = n * 1000 % 1000000;
212 	(void) select(0, (fd_set *)0, (fd_set *)0, (fd_set *)0, &tdelay);
213 }
214 
215 char *
216 lock_file_name(pp, buf, len)
217 	const struct printer *pp;
218 	char *buf;
219 	size_t len;
220 {
221 	static char staticbuf[MAXPATHLEN];
222 
223 	if (buf == 0)
224 		buf = staticbuf;
225 	if (len == 0)
226 		len = MAXPATHLEN;
227 
228 	if (pp->lock_file[0] == '/') {
229 		buf[0] = '\0';
230 		strncpy(buf, pp->lock_file, len);
231 	} else {
232 		snprintf(buf, len, "%s/%s", pp->spool_dir, pp->lock_file);
233 	}
234 	return buf;
235 }
236 
237 char *
238 status_file_name(pp, buf, len)
239 	const struct printer *pp;
240 	char *buf;
241 	size_t len;
242 {
243 	static char staticbuf[MAXPATHLEN];
244 
245 	if (buf == 0)
246 		buf = staticbuf;
247 	if (len == 0)
248 		len = MAXPATHLEN;
249 
250 	if (pp->status_file[0] == '/') {
251 		buf[0] = '\0';
252 		strncpy(buf, pp->status_file, len);
253 	} else {
254 		snprintf(buf, len, "%s/%s", pp->spool_dir, pp->status_file);
255 	}
256 	return buf;
257 }
258 
259 #ifdef __STDC__
260 #include <stdarg.h>
261 #else
262 #include <varargs.h>
263 #endif
264 
265 void
266 #ifdef __STDC__
267 fatal(const struct printer *pp, const char *msg, ...)
268 #else
269 fatal(pp, msg, va_alist)
270 	const struct printer *pp;
271 	char *msg;
272         va_dcl
273 #endif
274 {
275 	va_list ap;
276 #ifdef __STDC__
277 	va_start(ap, msg);
278 #else
279 	va_start(ap);
280 #endif
281 	if (from != host)
282 		(void)printf("%s: ", host);
283 	(void)printf("%s: ", name);
284 	if (pp && pp->printer)
285 		(void)printf("%s: ", pp->printer);
286 	(void)vprintf(msg, ap);
287 	va_end(ap);
288 	(void)putchar('\n');
289 	exit(1);
290 }
291 
292 /*
293  * Close all file descriptors from START on up.
294  * This is a horrific kluge, since getdtablesize() might return
295  * ``infinity'', in which case we will be spending a long time
296  * closing ``files'' which were never open.  Perhaps it would
297  * be better to close the first N fds, for some small value of N.
298  */
299 void
300 closeallfds(start)
301 	int start;
302 {
303 	int stop = getdtablesize();
304 	for (; start < stop; start++)
305 		close(start);
306 }
307 
308