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