xref: /original-bsd/usr.sbin/lpr/lpd/recvjob.c (revision 27393bdf)
1 /*
2  * Copyright (c) 1983, 1993
3  *	The Regents of the University of California.  All rights reserved.
4  *
5  *
6  * %sccs.include.redist.c%
7  */
8 
9 #ifndef lint
10 static char copyright[] =
11 "@(#) Copyright (c) 1983, 1993\n\
12 	The Regents of the University of California.  All rights reserved.\n";
13 #endif /* not lint */
14 
15 #ifndef lint
16 static char sccsid[] = "@(#)recvjob.c	8.2 (Berkeley) 04/27/95";
17 #endif /* not lint */
18 
19 /*
20  * Receive printer jobs from the network, queue them and
21  * start the printer daemon.
22  */
23 #include <sys/param.h>
24 #include <sys/mount.h>
25 #include <sys/stat.h>
26 
27 #include <unistd.h>
28 #include <signal.h>
29 #include <fcntl.h>
30 #include <dirent.h>
31 #include <syslog.h>
32 #include <stdio.h>
33 #include <stdlib.h>
34 #include <string.h>
35 #include "lp.h"
36 #include "lp.local.h"
37 #include "extern.h"
38 #include "pathnames.h"
39 
40 #define ack()	(void) write(1, sp, 1);
41 
42 static char	 dfname[40];	/* data files */
43 static int	 minfree;       /* keep at least minfree blocks available */
44 static char	*sp = "";
45 static char	 tfname[40];	/* tmp copy of cf before linking */
46 
47 static int        chksize __P((int));
48 static void       frecverr __P((const char *, ...));
49 static int        noresponse __P((void));
50 static void       rcleanup __P((int));
51 static int        read_number __P((char *));
52 static int        readfile __P((char *, int));
53 static int        readjob __P((void));
54 
55 
56 void
57 recvjob()
58 {
59 	struct stat stb;
60 	int status;
61 
62 	/*
63 	 * Perform lookup for printer name or abbreviation
64 	 */
65 	if ((status = cgetent(&bp, printcapdb, printer)) == -2)
66 		frecverr("cannot open printer description file");
67 	else if (status == -1)
68 		frecverr("unknown printer %s", printer);
69 	else if (status == -3)
70 		fatal("potential reference loop detected in printcap file");
71 
72 	if (cgetstr(bp, "lf", &LF) == -1)
73 		LF = _PATH_CONSOLE;
74 	if (cgetstr(bp, "sd", &SD) == -1)
75 		SD = _PATH_DEFSPOOL;
76 	if (cgetstr(bp, "lo", &LO) == -1)
77 		LO = DEFLOCK;
78 
79 	(void) close(2);			/* set up log file */
80 	if (open(LF, O_WRONLY|O_APPEND, 0664) < 0) {
81 		syslog(LOG_ERR, "%s: %m", LF);
82 		(void) open(_PATH_DEVNULL, O_WRONLY);
83 	}
84 
85 	if (chdir(SD) < 0)
86 		frecverr("%s: %s: %m", printer, SD);
87 	if (stat(LO, &stb) == 0) {
88 		if (stb.st_mode & 010) {
89 			/* queue is disabled */
90 			putchar('\1');		/* return error code */
91 			exit(1);
92 		}
93 	} else if (stat(SD, &stb) < 0)
94 		frecverr("%s: %s: %m", printer, SD);
95 	minfree = 2 * read_number("minfree");	/* scale KB to 512 blocks */
96 	signal(SIGTERM, rcleanup);
97 	signal(SIGPIPE, rcleanup);
98 
99 	if (readjob())
100 		printjob();
101 }
102 
103 /*
104  * Read printer jobs sent by lpd and copy them to the spooling directory.
105  * Return the number of jobs successfully transfered.
106  */
107 static int
108 readjob()
109 {
110 	register int size, nfiles;
111 	register char *cp;
112 
113 	ack();
114 	nfiles = 0;
115 	for (;;) {
116 		/*
117 		 * Read a command to tell us what to do
118 		 */
119 		cp = line;
120 		do {
121 			if ((size = read(1, cp, 1)) != 1) {
122 				if (size < 0)
123 					frecverr("%s: Lost connection",printer);
124 				return(nfiles);
125 			}
126 		} while (*cp++ != '\n');
127 		*--cp = '\0';
128 		cp = line;
129 		switch (*cp++) {
130 		case '\1':	/* cleanup because data sent was bad */
131 			rcleanup(0);
132 			continue;
133 
134 		case '\2':	/* read cf file */
135 			size = 0;
136 			while (*cp >= '0' && *cp <= '9')
137 				size = size * 10 + (*cp++ - '0');
138 			if (*cp++ != ' ')
139 				break;
140 			/*
141 			 * host name has been authenticated, we use our
142 			 * view of the host name since we may be passed
143 			 * something different than what gethostbyaddr()
144 			 * returns
145 			 */
146 			strcpy(cp + 6, from);
147 			strcpy(tfname, cp);
148 			tfname[0] = 't';
149 			if (!chksize(size)) {
150 				(void) write(1, "\2", 1);
151 				continue;
152 			}
153 			if (!readfile(tfname, size)) {
154 				rcleanup(0);
155 				continue;
156 			}
157 			if (link(tfname, cp) < 0)
158 				frecverr("%s: %m", tfname);
159 			(void) unlink(tfname);
160 			tfname[0] = '\0';
161 			nfiles++;
162 			continue;
163 
164 		case '\3':	/* read df file */
165 			size = 0;
166 			while (*cp >= '0' && *cp <= '9')
167 				size = size * 10 + (*cp++ - '0');
168 			if (*cp++ != ' ')
169 				break;
170 			if (!chksize(size)) {
171 				(void) write(1, "\2", 1);
172 				continue;
173 			}
174 			(void) strcpy(dfname, cp);
175 			if (index(dfname, '/'))
176 				frecverr("readjob: %s: illegal path name",
177 					dfname);
178 			(void) readfile(dfname, size);
179 			continue;
180 		}
181 		frecverr("protocol screwup: %s", line);
182 	}
183 }
184 
185 /*
186  * Read files send by lpd and copy them to the spooling directory.
187  */
188 static int
189 readfile(file, size)
190 	char *file;
191 	int size;
192 {
193 	register char *cp;
194 	char buf[BUFSIZ];
195 	register int i, j, amt;
196 	int fd, err;
197 
198 	fd = open(file, O_CREAT|O_EXCL|O_WRONLY, FILMOD);
199 	if (fd < 0)
200 		frecverr("readfile: %s: illegal path name: %m", file);
201 	ack();
202 	err = 0;
203 	for (i = 0; i < size; i += BUFSIZ) {
204 		amt = BUFSIZ;
205 		cp = buf;
206 		if (i + amt > size)
207 			amt = size - i;
208 		do {
209 			j = read(1, cp, amt);
210 			if (j <= 0)
211 				frecverr("Lost connection");
212 			amt -= j;
213 			cp += j;
214 		} while (amt > 0);
215 		amt = BUFSIZ;
216 		if (i + amt > size)
217 			amt = size - i;
218 		if (write(fd, buf, amt) != amt) {
219 			err++;
220 			break;
221 		}
222 	}
223 	(void) close(fd);
224 	if (err)
225 		frecverr("%s: write error", file);
226 	if (noresponse()) {		/* file sent had bad data in it */
227 		(void) unlink(file);
228 		return(0);
229 	}
230 	ack();
231 	return(1);
232 }
233 
234 static int
235 noresponse()
236 {
237 	char resp;
238 
239 	if (read(1, &resp, 1) != 1)
240 		frecverr("Lost connection");
241 	if (resp == '\0')
242 		return(0);
243 	return(1);
244 }
245 
246 /*
247  * Check to see if there is enough space on the disk for size bytes.
248  * 1 == OK, 0 == Not OK.
249  */
250 static int
251 chksize(size)
252 	int size;
253 {
254 	int spacefree;
255 	struct statfs sfb;
256 
257 	if (statfs(".", &sfb) < 0) {
258 		syslog(LOG_ERR, "%s: %m", "statfs(\".\")");
259 		return (1);
260 	}
261 	spacefree = sfb.f_bavail * (sfb.f_bsize / 512);
262 	size = (size + 511) / 512;
263 	if (minfree + size > spacefree)
264 		return(0);
265 	return(1);
266 }
267 
268 static int
269 read_number(fn)
270 	char *fn;
271 {
272 	char lin[80];
273 	register FILE *fp;
274 
275 	if ((fp = fopen(fn, "r")) == NULL)
276 		return (0);
277 	if (fgets(lin, 80, fp) == NULL) {
278 		fclose(fp);
279 		return (0);
280 	}
281 	fclose(fp);
282 	return (atoi(lin));
283 }
284 
285 /*
286  * Remove all the files associated with the current job being transfered.
287  */
288 static void
289 rcleanup(signo)
290 	int signo;
291 {
292 	if (tfname[0])
293 		(void) unlink(tfname);
294 	if (dfname[0])
295 		do {
296 			do
297 				(void) unlink(dfname);
298 			while (dfname[2]-- != 'A');
299 			dfname[2] = 'z';
300 		} while (dfname[0]-- != 'd');
301 	dfname[0] = '\0';
302 }
303 
304 #if __STDC__
305 #include <stdarg.h>
306 #else
307 #include <varargs.h>
308 #endif
309 
310 static void
311 #if __STDC__
312 frecverr(const char *msg, ...)
313 #else
314 frecverr(msg, va_alist)
315 	char *msg;
316         va_dcl
317 #endif
318 {
319 	extern char fromb[];
320 	va_list ap;
321 #if __STDC__
322 	va_start(ap, msg);
323 #else
324 	va_start(ap);
325 #endif
326 	rcleanup(0);
327 	syslog(LOG_ERR, "%s", fromb);
328 	vsyslog(LOG_ERR, msg, ap);
329 	va_end(ap);
330 	putchar('\1');		/* return error code */
331 	exit(1);
332 }
333