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