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