recvjob.c revision 1.4 1 /*
2 * Copyright (c) 1983, 1993
3 * The Regents of the University of California. All rights reserved.
4 *
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * 3. All advertising materials mentioning features or use of this software
15 * must display the following acknowledgement:
16 * This product includes software developed by the University of
17 * California, Berkeley and its contributors.
18 * 4. Neither the name of the University nor the names of its contributors
19 * may be used to endorse or promote products derived from this software
20 * without specific prior written permission.
21 *
22 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 * SUCH DAMAGE.
33 */
34
35 #ifndef lint
36 static char copyright[] =
37 "@(#) Copyright (c) 1983, 1993\n\
38 The Regents of the University of California. All rights reserved.\n";
39 #endif /* not lint */
40
41 #ifndef lint
42 static char sccsid[] = "@(#)recvjob.c 8.1 (Berkeley) 6/6/93";
43 #endif /* not lint */
44
45 /*
46 * Receive printer jobs from the network, queue them and
47 * start the printer daemon.
48 */
49 #include <sys/param.h>
50 #include <sys/mount.h>
51 #include <sys/stat.h>
52
53 #include <unistd.h>
54 #include <signal.h>
55 #include <fcntl.h>
56 #include <dirent.h>
57 #include <syslog.h>
58 #include <stdio.h>
59 #include <stdlib.h>
60 #include <string.h>
61 #include "lp.h"
62 #include "lp.local.h"
63 #include "extern.h"
64 #include "pathnames.h"
65
66 #define ack() (void) write(1, sp, 1);
67
68 static char dfname[40]; /* data files */
69 static int minfree; /* keep at least minfree blocks available */
70 static char *sp = "";
71 static char tfname[40]; /* tmp copy of cf before linking */
72
73 static int chksize __P((int));
74 static void frecverr __P((const char *, ...));
75 static int noresponse __P((void));
76 static void rcleanup __P((int));
77 static int read_number __P((char *));
78 static int readfile __P((char *, int));
79 static int readjob __P((void));
80
81
82 void
83 recvjob()
84 {
85 struct stat stb;
86 int status;
87
88 /*
89 * Perform lookup for printer name or abbreviation
90 */
91 if ((status = cgetent(&bp, printcapdb, printer)) == -2)
92 frecverr("cannot open printer description file");
93 else if (status == -1)
94 frecverr("unknown printer %s", printer);
95 else if (status == -3)
96 fatal("potential reference loop detected in printcap file");
97
98 if (cgetstr(bp, "lf", &LF) == -1)
99 LF = _PATH_CONSOLE;
100 if (cgetstr(bp, "sd", &SD) == -1)
101 SD = _PATH_DEFSPOOL;
102 if (cgetstr(bp, "lo", &LO) == -1)
103 LO = DEFLOCK;
104
105 (void) close(2); /* set up log file */
106 if (open(LF, O_WRONLY|O_APPEND, 0664) < 0) {
107 syslog(LOG_ERR, "%s: %m", LF);
108 (void) open(_PATH_DEVNULL, O_WRONLY);
109 }
110
111 if (chdir(SD) < 0)
112 frecverr("%s: %s: %m", printer, SD);
113 if (stat(LO, &stb) == 0) {
114 if (stb.st_mode & 010) {
115 /* queue is disabled */
116 putchar('\1'); /* return error code */
117 exit(1);
118 }
119 } else if (stat(SD, &stb) < 0)
120 frecverr("%s: %s: %m", printer, SD);
121 minfree = 2 * read_number("minfree"); /* scale KB to 512 blocks */
122 signal(SIGTERM, rcleanup);
123 signal(SIGPIPE, rcleanup);
124
125 if (readjob())
126 printjob();
127 }
128
129 /*
130 * Read printer jobs sent by lpd and copy them to the spooling directory.
131 * Return the number of jobs successfully transfered.
132 */
133 static int
134 readjob()
135 {
136 register int size, nfiles;
137 register char *cp;
138
139 ack();
140 nfiles = 0;
141 for (;;) {
142 /*
143 * Read a command to tell us what to do
144 */
145 cp = line;
146 do {
147 if ((size = read(1, cp, 1)) != 1) {
148 if (size < 0)
149 frecverr("%s: Lost connection",printer);
150 return(nfiles);
151 }
152 } while (*cp++ != '\n');
153 *--cp = '\0';
154 cp = line;
155 switch (*cp++) {
156 case '\1': /* cleanup because data sent was bad */
157 rcleanup(0);
158 continue;
159
160 case '\2': /* read cf file */
161 size = 0;
162 while (*cp >= '0' && *cp <= '9')
163 size = size * 10 + (*cp++ - '0');
164 if (*cp++ != ' ')
165 break;
166 /*
167 * host name has been authenticated, we use our
168 * view of the host name since we may be passed
169 * something different than what gethostbyaddr()
170 * returns
171 */
172 strcpy(cp + 6, from);
173 strcpy(tfname, cp);
174 tfname[0] = 't';
175 if (!chksize(size)) {
176 (void) write(1, "\2", 1);
177 continue;
178 }
179 if (!readfile(tfname, size)) {
180 rcleanup(0);
181 continue;
182 }
183 if (link(tfname, cp) < 0)
184 frecverr("%s: %m", tfname);
185 (void) unlink(tfname);
186 tfname[0] = '\0';
187 nfiles++;
188 continue;
189
190 case '\3': /* read df file */
191 size = 0;
192 while (*cp >= '0' && *cp <= '9')
193 size = size * 10 + (*cp++ - '0');
194 if (*cp++ != ' ')
195 break;
196 if (!chksize(size)) {
197 (void) write(1, "\2", 1);
198 continue;
199 }
200 (void) strcpy(dfname, cp);
201 if (index(dfname, '/'))
202 frecverr("readjob: %s: illegal path name",
203 dfname);
204 (void) readfile(dfname, size);
205 continue;
206 }
207 frecverr("protocol screwup: %s", line);
208 }
209 }
210
211 /*
212 * Read files send by lpd and copy them to the spooling directory.
213 */
214 static int
215 readfile(file, size)
216 char *file;
217 int size;
218 {
219 register char *cp;
220 char buf[BUFSIZ];
221 register int i, j, amt;
222 int fd, err;
223
224 fd = open(file, O_CREAT|O_EXCL|O_WRONLY, FILMOD);
225 if (fd < 0)
226 frecverr("readfile: %s: illegal path name: %m", file);
227 ack();
228 err = 0;
229 for (i = 0; i < size; i += BUFSIZ) {
230 amt = BUFSIZ;
231 cp = buf;
232 if (i + amt > size)
233 amt = size - i;
234 do {
235 j = read(1, cp, amt);
236 if (j <= 0)
237 frecverr("Lost connection");
238 amt -= j;
239 cp += j;
240 } while (amt > 0);
241 amt = BUFSIZ;
242 if (i + amt > size)
243 amt = size - i;
244 if (write(fd, buf, amt) != amt) {
245 err++;
246 break;
247 }
248 }
249 (void) close(fd);
250 if (err)
251 frecverr("%s: write error", file);
252 if (noresponse()) { /* file sent had bad data in it */
253 (void) unlink(file);
254 return(0);
255 }
256 ack();
257 return(1);
258 }
259
260 static int
261 noresponse()
262 {
263 char resp;
264
265 if (read(1, &resp, 1) != 1)
266 frecverr("Lost connection");
267 if (resp == '\0')
268 return(0);
269 return(1);
270 }
271
272 /*
273 * Check to see if there is enough space on the disk for size bytes.
274 * 1 == OK, 0 == Not OK.
275 */
276 static int
277 chksize(size)
278 int size;
279 {
280 int spacefree;
281 struct statfs sfb;
282
283 if (statfs(".", &sfb) < 0) {
284 syslog(LOG_ERR, "%s: %m", "statfs(\".\")");
285 return (1);
286 }
287 spacefree = sfb.f_bavail * (sfb.f_bsize / 512);
288 size = (size + 511) / 512;
289 if (minfree + size > spacefree)
290 return(0);
291 return(1);
292 }
293
294 static int
295 read_number(fn)
296 char *fn;
297 {
298 char lin[80];
299 register FILE *fp;
300
301 if ((fp = fopen(fn, "r")) == NULL)
302 return (0);
303 if (fgets(lin, 80, fp) == NULL) {
304 fclose(fp);
305 return (0);
306 }
307 fclose(fp);
308 return (atoi(lin));
309 }
310
311 /*
312 * Remove all the files associated with the current job being transfered.
313 */
314 static void
315 rcleanup(signo)
316 int signo;
317 {
318 if (tfname[0])
319 (void) unlink(tfname);
320 if (dfname[0])
321 do {
322 do
323 (void) unlink(dfname);
324 while (dfname[2]-- != 'A');
325 dfname[2] = 'z';
326 } while (dfname[0]-- != 'd');
327 dfname[0] = '\0';
328 }
329
330 #if __STDC__
331 #include <stdarg.h>
332 #else
333 #include <varargs.h>
334 #endif
335
336 static void
337 #if __STDC__
338 frecverr(const char *msg, ...)
339 #else
340 frecverr(msg, va_alist)
341 char *msg;
342 va_dcl
343 #endif
344 {
345 extern char *fromb;
346 va_list ap;
347 #if __STDC__
348 va_start(ap, msg);
349 #else
350 va_start(ap);
351 #endif
352 rcleanup(0);
353 syslog(LOG_ERR, "%s", fromb);
354 vsyslog(LOG_ERR, msg, ap);
355 va_end(ap);
356 putchar('\1'); /* return error code */
357 exit(1);
358 }
359