xref: /original-bsd/usr.sbin/lpr/lpd/recvjob.c (revision 01d1337d)
1 /*
2  * Copyright (c) 1983 Regents of the University of California.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms are permitted
6  * provided that the above copyright notice and this paragraph are
7  * duplicated in all such forms and that any documentation,
8  * advertising materials, and other materials related to such
9  * distribution and use acknowledge that the software was developed
10  * by the University of California, Berkeley.  The name of the
11  * University may not be used to endorse or promote products derived
12  * from this software without specific prior written permission.
13  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
14  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
15  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
16  */
17 
18 #ifndef lint
19 static char sccsid[] = "@(#)recvjob.c	5.8 (Berkeley) 05/11/89";
20 #endif /* not lint */
21 
22 /*
23  * Receive printer jobs from the network, queue them and
24  * start the printer daemon.
25  */
26 
27 #include "lp.h"
28 #include <sys/fs.h>
29 #include "pathnames.h"
30 
31 char	*sp = "";
32 #define ack()	(void) write(1, sp, 1);
33 
34 char    tfname[40];		/* tmp copy of cf before linking */
35 char    dfname[40];		/* data files */
36 int	minfree;		/* keep at least minfree blocks available */
37 char	*ddev;			/* disk device (for checking free space) */
38 int	dfd;			/* file system device descriptor */
39 
40 char	*find_dev();
41 
42 recvjob()
43 {
44 	struct stat stb;
45 	char *bp = pbuf;
46 	int status, rcleanup();
47 
48 	/*
49 	 * Perform lookup for printer name or abbreviation
50 	 */
51 	if ((status = pgetent(line, printer)) < 0)
52 		frecverr("cannot open printer description file");
53 	else if (status == 0)
54 		frecverr("unknown printer %s", printer);
55 	if ((LF = pgetstr("lf", &bp)) == NULL)
56 		LF = _PATH_CONSOLE;
57 	if ((SD = pgetstr("sd", &bp)) == NULL)
58 		SD = _PATH_DEFSPOOL;
59 	if ((LO = pgetstr("lo", &bp)) == NULL)
60 		LO = DEFLOCK;
61 
62 	(void) close(2);			/* set up log file */
63 	if (open(LF, O_WRONLY|O_APPEND, 0664) < 0) {
64 		syslog(LOG_ERR, "%s: %m", LF);
65 		(void) open(_PATH_DEVNULL, O_WRONLY);
66 	}
67 
68 	if (chdir(SD) < 0)
69 		frecverr("%s: %s: %m", printer, SD);
70 	if (stat(LO, &stb) == 0) {
71 		if (stb.st_mode & 010) {
72 			/* queue is disabled */
73 			putchar('\1');		/* return error code */
74 			exit(1);
75 		}
76 	} else if (stat(SD, &stb) < 0)
77 		frecverr("%s: %s: %m", printer, SD);
78 	minfree = read_number("minfree");
79 	ddev = find_dev(stb.st_dev, S_IFBLK);
80 	if ((dfd = open(ddev, O_RDONLY)) < 0)
81 		syslog(LOG_WARNING, "%s: %s: %m", printer, ddev);
82 	signal(SIGTERM, rcleanup);
83 	signal(SIGPIPE, rcleanup);
84 
85 	if (readjob())
86 		printjob();
87 }
88 
89 char *
90 find_dev(dev, type)
91 	register dev_t dev;
92 	register int type;
93 {
94 	register DIR *dfd = opendir(_PATH_DEV);
95 	struct direct *dir;
96 	struct stat stb;
97 	char devname[MAXNAMLEN+6];
98 	char *dp;
99 
100 	strcpy(devname, _PATH_DEV);
101 	while ((dir = readdir(dfd))) {
102 		strcpy(devname + 5, dir->d_name);
103 		if (stat(devname, &stb))
104 			continue;
105 		if ((stb.st_mode & S_IFMT) != type)
106 			continue;
107 		if (dev == stb.st_rdev) {
108 			closedir(dfd);
109 			dp = (char *)malloc(strlen(devname)+1);
110 			strcpy(dp, devname);
111 			return(dp);
112 		}
113 	}
114 	closedir(dfd);
115 	frecverr("cannot find device %d, %d", major(dev), minor(dev));
116 	/*NOTREACHED*/
117 }
118 
119 /*
120  * Read printer jobs sent by lpd and copy them to the spooling directory.
121  * Return the number of jobs successfully transfered.
122  */
123 readjob()
124 {
125 	register int size, nfiles;
126 	register char *cp;
127 
128 	ack();
129 	nfiles = 0;
130 	for (;;) {
131 		/*
132 		 * Read a command to tell us what to do
133 		 */
134 		cp = line;
135 		do {
136 			if ((size = read(1, cp, 1)) != 1) {
137 				if (size < 0)
138 					frecverr("%s: Lost connection",printer);
139 				return(nfiles);
140 			}
141 		} while (*cp++ != '\n');
142 		*--cp = '\0';
143 		cp = line;
144 		switch (*cp++) {
145 		case '\1':	/* cleanup because data sent was bad */
146 			rcleanup();
147 			continue;
148 
149 		case '\2':	/* read cf file */
150 			size = 0;
151 			while (*cp >= '0' && *cp <= '9')
152 				size = size * 10 + (*cp++ - '0');
153 			if (*cp++ != ' ')
154 				break;
155 			/*
156 			 * host name has been authenticated, we use our
157 			 * view of the host name since we may be passed
158 			 * something different than what gethostbyaddr()
159 			 * returns
160 			 */
161 			strcpy(cp + 6, from);
162 			strcpy(tfname, cp);
163 			tfname[0] = 't';
164 			if (!chksize(size)) {
165 				(void) write(1, "\2", 1);
166 				continue;
167 			}
168 			if (!readfile(tfname, size)) {
169 				rcleanup();
170 				continue;
171 			}
172 			if (link(tfname, cp) < 0)
173 				frecverr("%s: %m", tfname);
174 			(void) unlink(tfname);
175 			tfname[0] = '\0';
176 			nfiles++;
177 			continue;
178 
179 		case '\3':	/* read df file */
180 			size = 0;
181 			while (*cp >= '0' && *cp <= '9')
182 				size = size * 10 + (*cp++ - '0');
183 			if (*cp++ != ' ')
184 				break;
185 			if (!chksize(size)) {
186 				(void) write(1, "\2", 1);
187 				continue;
188 			}
189 			strcpy(dfname, cp);
190 			(void) readfile(dfname, size);
191 			continue;
192 		}
193 		frecverr("protocol screwup");
194 	}
195 }
196 
197 /*
198  * Read files send by lpd and copy them to the spooling directory.
199  */
200 readfile(file, size)
201 	char *file;
202 	int size;
203 {
204 	register char *cp;
205 	char buf[BUFSIZ];
206 	register int i, j, amt;
207 	int fd, err;
208 
209 	fd = open(file, O_WRONLY|O_CREAT, FILMOD);
210 	if (fd < 0)
211 		frecverr("%s: %m", file);
212 	ack();
213 	err = 0;
214 	for (i = 0; i < size; i += BUFSIZ) {
215 		amt = BUFSIZ;
216 		cp = buf;
217 		if (i + amt > size)
218 			amt = size - i;
219 		do {
220 			j = read(1, cp, amt);
221 			if (j <= 0)
222 				frecverr("Lost connection");
223 			amt -= j;
224 			cp += j;
225 		} while (amt > 0);
226 		amt = BUFSIZ;
227 		if (i + amt > size)
228 			amt = size - i;
229 		if (write(fd, buf, amt) != amt) {
230 			err++;
231 			break;
232 		}
233 	}
234 	(void) close(fd);
235 	if (err)
236 		frecverr("%s: write error", file);
237 	if (noresponse()) {		/* file sent had bad data in it */
238 		(void) unlink(file);
239 		return(0);
240 	}
241 	ack();
242 	return(1);
243 }
244 
245 noresponse()
246 {
247 	char resp;
248 
249 	if (read(1, &resp, 1) != 1)
250 		frecverr("Lost connection");
251 	if (resp == '\0')
252 		return(0);
253 	return(1);
254 }
255 
256 /*
257  * Check to see if there is enough space on the disk for size bytes.
258  * 1 == OK, 0 == Not OK.
259  */
260 chksize(size)
261 	int size;
262 {
263 	struct stat stb;
264 	register char *ddev;
265 	int spacefree;
266 	struct fs fs;
267 
268 	if (dfd < 0 || lseek(dfd, (long)(SBOFF), 0) < 0)
269 		return(1);
270 	if (read(dfd, (char *)&fs, sizeof fs) != sizeof fs)
271 		return(1);
272 	spacefree = freespace(&fs, fs.fs_minfree) * fs.fs_fsize / 1024;
273 	size = (size + 1023) / 1024;
274 	if (minfree + size > spacefree)
275 		return(0);
276 	return(1);
277 }
278 
279 read_number(fn)
280 	char *fn;
281 {
282 	char lin[80];
283 	register FILE *fp;
284 
285 	if ((fp = fopen(fn, "r")) == NULL)
286 		return (0);
287 	if (fgets(lin, 80, fp) == NULL) {
288 		fclose(fp);
289 		return (0);
290 	}
291 	fclose(fp);
292 	return (atoi(lin));
293 }
294 
295 /*
296  * Remove all the files associated with the current job being transfered.
297  */
298 rcleanup()
299 {
300 
301 	if (tfname[0])
302 		(void) unlink(tfname);
303 	if (dfname[0])
304 		do {
305 			do
306 				(void) unlink(dfname);
307 			while (dfname[2]-- != 'A');
308 			dfname[2] = 'z';
309 		} while (dfname[0]-- != 'd');
310 	dfname[0] = '\0';
311 }
312 
313 frecverr(msg, a1, a2)
314 	char *msg;
315 {
316 	rcleanup();
317 	syslog(LOG_ERR, msg, a1, a2);
318 	putchar('\1');		/* return error code */
319 	exit(1);
320 }
321