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