2 * Copyright (c) 1983, 1993
3 * The Regents of the University of California. All rights reserved.
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
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.
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
34 * @(#) Copyright (c) 1983, 1993 The Regents of the University of California. All rights reserved.
35 * @(#)recvjob.c 8.2 (Berkeley) 4/27/95
36 * $FreeBSD: src/usr.sbin/lpr/lpd/recvjob.c,v 1.14.2.13 2002/06/19 01:46:48 gad Exp $
37 * $DragonFly: src/usr.sbin/lpr/lpd/recvjob.c,v 1.4 2004/12/18 22:48:03 swildner Exp $
41 * Receive printer jobs from the network, queue them and
42 * start the printer daemon.
44 #include <sys/param.h>
45 #include <sys/mount.h>
61 #include "pathnames.h"
63 #define ack() write(STDOUT_FILENO, sp, (size_t)1);
65 static char dfname
[NAME_MAX
]; /* data files */
66 static int minfree
; /* keep at least minfree blocks available */
67 static const char *sp
= "";
68 static char tfname
[NAME_MAX
]; /* tmp copy of cf before linking */
70 static int chksize(int _size
);
71 static void frecverr(const char *_msg
, ...) __printf0like(1, 2);
72 static int noresponse(void);
73 static void rcleanup(int _signo
);
74 static int read_number(const char *_fn
);
75 static int readfile(struct printer
*_pp
, char *_file
, size_t _size
);
76 static int readjob(struct printer
*_pp
);
80 recvjob(const char *printer
)
84 struct printer myprinter
, *pp
= &myprinter
;
87 * Perform lookup for printer name or abbreviation
90 status
= getprintcap(printer
, pp
);
93 frecverr("cannot open printer description file");
95 case PCAPERR_NOTFOUND
:
96 frecverr("unknown printer %s", printer
);
99 fatal(pp
, "potential reference loop detected in printcap file");
104 close(2); /* set up log file */
105 if (open(pp
->log_file
, O_WRONLY
|O_APPEND
, 0664) < 0) {
106 syslog(LOG_ERR
, "%s: %m", pp
->log_file
);
107 open(_PATH_DEVNULL
, O_WRONLY
);
110 if (chdir(pp
->spool_dir
) < 0)
111 frecverr("%s: chdir(%s): %s", pp
->printer
, pp
->spool_dir
,
113 if (stat(pp
->lock_file
, &stb
) == 0) {
114 if (stb
.st_mode
& 010) {
115 /* queue is disabled */
116 putchar('\1'); /* return error code */
119 } else if (stat(pp
->spool_dir
, &stb
) < 0)
120 frecverr("%s: stat(%s): %s", pp
->printer
, pp
->spool_dir
,
122 minfree
= 2 * read_number("minfree"); /* scale KB to 512 blocks */
123 signal(SIGTERM
, rcleanup
);
124 signal(SIGPIPE
, rcleanup
);
131 * Read printer jobs sent by lpd and copy them to the spooling directory.
132 * Return the number of jobs successfully transfered.
135 readjob(struct printer
*pp
)
139 char *cp
, *clastp
, *errmsg
;
140 char givenid
[32], givenhost
[MAXHOSTNAMELEN
];
147 * Read a command to tell us what to do
150 clastp
= line
+ sizeof(line
) - 1;
152 size
= read(STDOUT_FILENO
, cp
, (size_t)1);
153 if (size
!= (ssize_t
)1) {
154 if (size
< (ssize_t
)0) {
155 frecverr("%s: lost connection",
161 } while ((*cp
++ != '\n') && (cp
<= clastp
));
163 frecverr("%s: readjob overflow", pp
->printer
);
169 case '\1': /* cleanup because data sent was bad */
173 case '\2': /* read cf file */
176 while (*cp
>= '0' && *cp
<= '9')
177 size
= size
* 10 + (*cp
++ - '0');
181 * host name has been authenticated, we use our
182 * view of the host name since we may be passed
183 * something different than what gethostbyaddr()
186 strlcpy(cp
+ 6, from_host
, sizeof(line
)
187 + (size_t)(line
- cp
- 6));
188 if (strchr(cp
, '/')) {
189 frecverr("readjob: %s: illegal path name", cp
);
192 strlcpy(tfname
, cp
, sizeof(tfname
));
193 tfname
[sizeof (tfname
) - 1] = '\0';
195 if (!chksize(size
)) {
196 write(STDOUT_FILENO
, "\2", (size_t)1);
199 if (!readfile(pp
, tfname
, (size_t)size
)) {
203 errmsg
= ctl_renametf(pp
->printer
, tfname
);
205 if (errmsg
!= NULL
) {
206 frecverr("%s: %s", pp
->printer
, errmsg
);
212 case '\3': /* read df file */
216 while (*cp
>= '0' && *cp
<= '9')
217 size
= size
* 10 + (*cp
++ - '0');
220 if (strchr(cp
, '/')) {
221 frecverr("readjob: %s: illegal path name", cp
);
224 if (!chksize(size
)) {
225 write(STDOUT_FILENO
, "\2", (size_t)1);
228 strlcpy(dfname
, cp
, sizeof(dfname
));
230 trstat_init(pp
, dfname
, dfcnt
);
231 readfile(pp
, dfname
, (size_t)size
);
232 trstat_write(pp
, TR_RECVING
, (size_t)size
, givenid
,
233 from_host
, givenhost
);
236 frecverr("protocol screwup: %s", line
);
242 * Read files send by lpd and copy them to the spooling directory.
245 readfile(struct printer
*pp
, char *file
, size_t size
)
252 fd
= open(file
, O_CREAT
|O_EXCL
|O_WRONLY
, FILMOD
);
254 frecverr("%s: readfile: error on open(%s): %s",
255 pp
->printer
, file
, strerror(errno
));
260 for (i
= 0; i
< size
; i
+= BUFSIZ
) {
266 j
= read(STDOUT_FILENO
, cp
, amt
);
268 frecverr("%s: lost connection", pp
->printer
);
277 if (write(fd
, buf
, amt
) != (ssize_t
)amt
) {
284 frecverr("%s: write error on close(%s)", pp
->printer
, file
);
287 if (noresponse()) { /* file sent had bad data in it */
288 if (strchr(file
, '/') == NULL
)
301 if (read(STDOUT_FILENO
, &resp
, (size_t)1) != 1) {
302 frecverr("lost connection in noresponse()");
311 * Check to see if there is enough space on the disk for size bytes.
312 * 1 == OK, 0 == Not OK.
320 if (statfs(".", &sfb
) < 0) {
321 syslog(LOG_ERR
, "%s: %m", "statfs(\".\")");
324 spacefree
= sfb
.f_bavail
* (sfb
.f_bsize
/ 512);
325 size
= (size
+ 511) / 512;
326 if (minfree
+ size
> spacefree
)
332 read_number(const char *fn
)
337 if ((fp
= fopen(fn
, "r")) == NULL
)
339 if (fgets(lin
, 80, fp
) == NULL
) {
348 * Remove all the files associated with the current job being transfered.
351 rcleanup(int signo __unused
)
353 if (tfname
[0] && strchr(tfname
, '/') == NULL
)
355 if (dfname
[0] && strchr(dfname
, '/') == NULL
) {
359 while (dfname
[2]-- != 'A');
361 } while (dfname
[0]-- != 'd');
369 frecverr(const char *msg
, ...)
373 syslog(LOG_ERR
, "Error receiving job from %s:", from_host
);
374 vsyslog(LOG_ERR
, msg
, ap
);
377 * rcleanup is not called until AFTER logging the error message,
378 * because rcleanup will zap some variables which may have been
379 * supplied as parameters for that msg...
383 * Add a minimal delay before returning the final error code to
384 * the sending host. This just in case that machine responds
385 * this error by INSTANTLY retrying (and instantly re-failing...).
386 * It would be stupid of the sending host to do that, but if there
387 * was a broken implementation which did it, the result might be
388 * obscure performance problems and a flood of syslog messages on
389 * the receiving host.
391 sleep(2); /* a paranoid throttling measure */
392 putchar('\1'); /* return error code */