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