]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - usr.sbin/lpr/lpd/recvjob.c
unfinished sblive driver, playback/mixer only for now - not enabled in
[FreeBSD/FreeBSD.git] / usr.sbin / lpr / lpd / recvjob.c
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 const 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 #if 0
43 static char sccsid[] = "@(#)recvjob.c   8.2 (Berkeley) 4/27/95";
44 #endif
45 static const char rcsid[] =
46   "$FreeBSD$";
47 #endif /* not lint */
48
49 /*
50  * Receive printer jobs from the network, queue them and
51  * start the printer daemon.
52  */
53 #include <sys/param.h>
54 #include <sys/mount.h>
55 #include <sys/stat.h>
56
57 #include <unistd.h>
58 #include <signal.h>
59 #include <fcntl.h>
60 #include <dirent.h>
61 #include <syslog.h>
62 #include <stdio.h>
63 #include <stdlib.h>
64 #include <string.h>
65 #include "lp.h"
66 #include "lp.local.h"
67 #include "extern.h"
68 #include "pathnames.h"
69
70 #define ack()   (void) write(1, sp, 1);
71
72 static char      dfname[NAME_MAX];      /* data files */
73 static int       minfree;       /* keep at least minfree blocks available */
74 static char     *sp = "";
75 static char      tfname[NAME_MAX];      /* tmp copy of cf before linking */
76
77 static int        chksize __P((int));
78 static void       frecverr __P((const char *, ...));
79 static int        noresponse __P((void));
80 static void       rcleanup __P((int));
81 static int        read_number __P((char *));
82 static int        readfile __P((char *, int));
83 static int        readjob __P((struct printer *pp));
84
85
86 void
87 recvjob(printer)
88         const char *printer;
89 {
90         struct stat stb;
91         int status;
92         struct printer myprinter, *pp = &myprinter;
93
94         /*
95          * Perform lookup for printer name or abbreviation
96          */
97         init_printer(pp);
98         status = getprintcap(printer, pp);
99         switch (status) {
100         case PCAPERR_OSERR:
101                 frecverr("cannot open printer description file");
102                 break;
103         case PCAPERR_NOTFOUND:
104                 frecverr("unknown printer %s", printer);
105                 break;
106         case PCAPERR_TCLOOP:
107                 fatal(pp, "potential reference loop detected in printcap file");
108         default:
109                 break;
110         }
111         
112         (void) close(2);                        /* set up log file */
113         if (open(pp->log_file, O_WRONLY|O_APPEND, 0664) < 0) {
114                 syslog(LOG_ERR, "%s: %m", pp->log_file);
115                 (void) open(_PATH_DEVNULL, O_WRONLY);
116         }
117
118         if (chdir(pp->spool_dir) < 0)
119                 frecverr("%s: %s: %m", pp->printer, pp->spool_dir);
120         if (stat(pp->lock_file, &stb) == 0) {
121                 if (stb.st_mode & 010) {
122                         /* queue is disabled */
123                         putchar('\1');          /* return error code */
124                         exit(1);
125                 }
126         } else if (stat(pp->spool_dir, &stb) < 0)
127                 frecverr("%s: %s: %m", pp->printer, pp->spool_dir);
128         minfree = 2 * read_number("minfree");   /* scale KB to 512 blocks */
129         signal(SIGTERM, rcleanup);
130         signal(SIGPIPE, rcleanup);
131
132         if (readjob(pp))
133                 printjob(pp);
134 }
135
136 /*
137  * Read printer jobs sent by lpd and copy them to the spooling directory.
138  * Return the number of jobs successfully transfered.
139  */
140 static int
141 readjob(pp)
142         struct printer *pp;
143 {
144         register int size, nfiles;
145         register char *cp;
146
147         ack();
148         nfiles = 0;
149         for (;;) {
150                 /*
151                  * Read a command to tell us what to do
152                  */
153                 cp = line;
154                 do {
155                         if ((size = read(1, cp, 1)) != 1) {
156                                 if (size < 0)
157                                         frecverr("%s: lost connection",
158                                             pp->printer);
159                                 return(nfiles);
160                         }
161                 } while (*cp++ != '\n' && (cp - line + 1) < sizeof(line));
162                 if (cp - line + 1 >= sizeof(line))
163                         frecverr("readjob overflow");
164                 *--cp = '\0';
165                 cp = line;
166                 switch (*cp++) {
167                 case '\1':      /* cleanup because data sent was bad */
168                         rcleanup(0);
169                         continue;
170
171                 case '\2':      /* read cf file */
172                         size = 0;
173                         while (*cp >= '0' && *cp <= '9')
174                                 size = size * 10 + (*cp++ - '0');
175                         if (*cp++ != ' ')
176                                 break;
177                         /*
178                          * host name has been authenticated, we use our
179                          * view of the host name since we may be passed
180                          * something different than what gethostbyaddr()
181                          * returns
182                          */
183                         strncpy(cp + 6, from, sizeof(line) + line - cp - 7);
184                         line[sizeof(line) - 1 ] = '\0';
185                         strncpy(tfname, cp, sizeof(tfname) - 1);
186                         tfname[sizeof (tfname) - 1] = '\0';
187                         tfname[0] = 't';
188                         if (strchr(tfname, '/'))
189                                 frecverr("readjob: %s: illegal path name",
190                                     tfname);
191                         if (!chksize(size)) {
192                                 (void) write(1, "\2", 1);
193                                 continue;
194                         }
195                         if (!readfile(tfname, size)) {
196                                 rcleanup(0);
197                                 continue;
198                         }
199                         if (link(tfname, cp) < 0)
200                                 frecverr("%s: %m", tfname);
201                         (void) unlink(tfname);
202                         tfname[0] = '\0';
203                         nfiles++;
204                         continue;
205
206                 case '\3':      /* read df file */
207                         size = 0;
208                         while (*cp >= '0' && *cp <= '9')
209                                 size = size * 10 + (*cp++ - '0');
210                         if (*cp++ != ' ')
211                                 break;
212                         if (!chksize(size)) {
213                                 (void) write(1, "\2", 1);
214                                 continue;
215                         }
216                         (void) strncpy(dfname, cp, sizeof(dfname) - 1);
217                         dfname[sizeof(dfname) - 1] = '\0';
218                         if (strchr(dfname, '/'))
219                                 frecverr("readjob: %s: illegal path name",
220                                         dfname);
221                         (void) readfile(dfname, size);
222                         continue;
223                 }
224                 frecverr("protocol screwup: %s", line);
225         }
226 }
227
228 /*
229  * Read files send by lpd and copy them to the spooling directory.
230  */
231 static int
232 readfile(file, size)
233         char *file;
234         int size;
235 {
236         register char *cp;
237         char buf[BUFSIZ];
238         register int i, j, amt;
239         int fd, err;
240
241         fd = open(file, O_CREAT|O_EXCL|O_WRONLY, FILMOD);
242         if (fd < 0)
243                 frecverr("readfile: %s: illegal path name: %m", file);
244         ack();
245         err = 0;
246         for (i = 0; i < size; i += BUFSIZ) {
247                 amt = BUFSIZ;
248                 cp = buf;
249                 if (i + amt > size)
250                         amt = size - i;
251                 do {
252                         j = read(1, cp, amt);
253                         if (j <= 0)
254                                 frecverr("lost connection");
255                         amt -= j;
256                         cp += j;
257                 } while (amt > 0);
258                 amt = BUFSIZ;
259                 if (i + amt > size)
260                         amt = size - i;
261                 if (write(fd, buf, amt) != amt) {
262                         err++;
263                         break;
264                 }
265         }
266         (void) close(fd);
267         if (err)
268                 frecverr("%s: write error", file);
269         if (noresponse()) {             /* file sent had bad data in it */
270                 if (strchr(file, '/') == NULL)
271                         (void) unlink(file);
272                 return(0);
273         }
274         ack();
275         return(1);
276 }
277
278 static int
279 noresponse()
280 {
281         char resp;
282
283         if (read(1, &resp, 1) != 1)
284                 frecverr("lost connection");
285         if (resp == '\0')
286                 return(0);
287         return(1);
288 }
289
290 /*
291  * Check to see if there is enough space on the disk for size bytes.
292  * 1 == OK, 0 == Not OK.
293  */
294 static int
295 chksize(size)
296         int size;
297 {
298         int spacefree;
299         struct statfs sfb;
300
301         if (statfs(".", &sfb) < 0) {
302                 syslog(LOG_ERR, "%s: %m", "statfs(\".\")");
303                 return (1);
304         }
305         spacefree = sfb.f_bavail * (sfb.f_bsize / 512);
306         size = (size + 511) / 512;
307         if (minfree + size > spacefree)
308                 return(0);
309         return(1);
310 }
311
312 static int
313 read_number(fn)
314         char *fn;
315 {
316         char lin[80];
317         register FILE *fp;
318
319         if ((fp = fopen(fn, "r")) == NULL)
320                 return (0);
321         if (fgets(lin, 80, fp) == NULL) {
322                 fclose(fp);
323                 return (0);
324         }
325         fclose(fp);
326         return (atoi(lin));
327 }
328
329 /*
330  * Remove all the files associated with the current job being transfered.
331  */
332 static void
333 rcleanup(signo)
334         int signo;
335 {
336         if (tfname[0] && strchr(tfname, '/') == NULL)
337                 (void) unlink(tfname);
338         if (dfname[0] && strchr(dfname, '/') == NULL) {
339                 do {
340                         do
341                                 (void) unlink(dfname);
342                         while (dfname[2]-- != 'A');
343                         dfname[2] = 'z';
344                 } while (dfname[0]-- != 'd');
345         }
346         dfname[0] = '\0';
347 }
348
349 #ifdef __STDC__
350 #include <stdarg.h>
351 #else
352 #include <varargs.h>
353 #endif
354
355 static void
356 #ifdef __STDC__
357 frecverr(const char *msg, ...)
358 #else
359 frecverr(msg, va_alist)
360         char *msg;
361         va_dcl
362 #endif
363 {
364         va_list ap;
365 #ifdef __STDC__
366         va_start(ap, msg);
367 #else
368         va_start(ap);
369 #endif
370         rcleanup(0);
371         syslog(LOG_ERR, "%s", fromb);
372         vsyslog(LOG_ERR, msg, ap);
373         va_end(ap);
374         putchar('\1');          /* return error code */
375         exit(1);
376 }