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