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