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