Commit | Line | Data |
---|---|---|
5f84f8f0 | 1 | #ifndef lint |
84f9c0d8 | 2 | static char sccsid[] = "@(#)recvjob.c 4.8 (Berkeley) %G%"; |
5f84f8f0 SL |
3 | #endif |
4 | ||
e3127271 RC |
5 | /* |
6 | * Receive printer jobs from the network, queue them and | |
7 | * start the printer daemon. | |
8 | */ | |
9 | ||
10 | #include "lp.h" | |
47f0387b | 11 | #include <sys/fs.h> |
e3127271 | 12 | |
47f0387b RC |
13 | char *sp = ""; |
14 | #define ack() (void) write(1, sp, 1); | |
15 | ||
16 | char tfname[40]; /* tmp copy of cf before linking */ | |
17 | char *dfname; /* data files */ | |
18 | int minfree; /* keep at least minfree blocks available */ | |
19 | char *ddev; /* disk device (for checking free space) */ | |
20 | int dfd; /* file system device descriptor */ | |
21 | ||
22 | char *find_dev(); | |
e3127271 RC |
23 | |
24 | recvjob() | |
25 | { | |
88f026f7 | 26 | struct stat stb; |
e3127271 | 27 | char *bp = pbuf; |
47f0387b | 28 | int status, rcleanup(); |
e3127271 | 29 | |
e3127271 RC |
30 | /* |
31 | * Perform lookup for printer name or abbreviation | |
32 | */ | |
33 | if ((status = pgetent(line, printer)) < 0) | |
47f0387b | 34 | frecverr("cannot open printer description file"); |
e3127271 | 35 | else if (status == 0) |
47f0387b | 36 | frecverr("unknown printer %s", printer); |
e3127271 RC |
37 | if ((LF = pgetstr("lf", &bp)) == NULL) |
38 | LF = DEFLOGF; | |
39 | if ((SD = pgetstr("sd", &bp)) == NULL) | |
40 | SD = DEFSPOOL; | |
88f026f7 RC |
41 | if ((LO = pgetstr("lo", &bp)) == NULL) |
42 | LO = DEFLOCK; | |
e3127271 | 43 | |
e3127271 | 44 | if (chdir(SD) < 0) |
47f0387b RC |
45 | frecverr("%s: %s: %m", printer, SD); |
46 | if (stat(LO, &stb) == 0) { | |
47 | if (stb.st_mode & 010) { | |
48 | /* queue is disabled */ | |
49 | putchar('\1'); /* return error code */ | |
50 | exit(1); | |
51 | } | |
52 | } else if (stat(SD, &stb) < 0) | |
53 | frecverr("%s: %s: %m", printer, SD); | |
54 | minfree = read_number("minfree"); | |
55 | ddev = find_dev(stb.st_dev, S_IFBLK); | |
56 | if ((dfd = open(ddev, O_RDONLY)) < 0) | |
57 | syslog(LOG_WARNING, "%s: %s: %m", printer, ddev); | |
58 | signal(SIGTERM, rcleanup); | |
59 | signal(SIGPIPE, rcleanup); | |
e3127271 RC |
60 | |
61 | if (readjob()) | |
62 | printjob(); | |
63 | } | |
64 | ||
47f0387b RC |
65 | char * |
66 | find_dev(dev, type) | |
67 | register dev_t dev; | |
68 | register int type; | |
69 | { | |
70 | register DIR *dfd = opendir("/dev"); | |
71 | struct direct *dir; | |
72 | struct stat stb; | |
73 | char devname[MAXNAMLEN+6]; | |
74 | char *dp; | |
75 | ||
76 | strcpy(devname, "/dev/"); | |
77 | while ((dir = readdir(dfd))) { | |
78 | strcpy(devname + 5, dir->d_name); | |
79 | if (stat(devname, &stb)) | |
80 | continue; | |
81 | if ((stb.st_mode & S_IFMT) != type) | |
82 | continue; | |
83 | if (dev == stb.st_rdev) { | |
84 | closedir(dfd); | |
85 | dp = (char *)malloc(strlen(devname)+1); | |
86 | strcpy(dp, devname); | |
87 | return(dp); | |
88 | } | |
89 | } | |
90 | closedir(dfd); | |
91 | frecverr("cannot find device %d, %d", major(dev), minor(dev)); | |
92 | /*NOTREACHED*/ | |
93 | } | |
e3127271 RC |
94 | |
95 | /* | |
96 | * Read printer jobs sent by lpd and copy them to the spooling directory. | |
97 | * Return the number of jobs successfully transfered. | |
98 | */ | |
47f0387b | 99 | readjob() |
e3127271 RC |
100 | { |
101 | register int size, nfiles; | |
102 | register char *cp; | |
103 | ||
104 | ack(); | |
105 | nfiles = 0; | |
106 | for (;;) { | |
107 | /* | |
108 | * Read a command to tell us what to do | |
109 | */ | |
110 | cp = line; | |
111 | do { | |
112 | if ((size = read(1, cp, 1)) != 1) { | |
113 | if (size < 0) | |
47f0387b | 114 | frecverr("%s: Lost connection",printer); |
e3127271 RC |
115 | return(nfiles); |
116 | } | |
117 | } while (*cp++ != '\n'); | |
118 | *--cp = '\0'; | |
119 | cp = line; | |
120 | switch (*cp++) { | |
121 | case '\1': /* cleanup because data sent was bad */ | |
47f0387b | 122 | rcleanup(); |
e3127271 RC |
123 | continue; |
124 | ||
125 | case '\2': /* read cf file */ | |
126 | size = 0; | |
127 | while (*cp >= '0' && *cp <= '9') | |
128 | size = size * 10 + (*cp++ - '0'); | |
129 | if (*cp++ != ' ') | |
130 | break; | |
131 | strcpy(tfname, cp); | |
132 | tfname[0] = 't'; | |
47f0387b RC |
133 | if (!chksize(size)) { |
134 | (void) write(1, "\2", 1); | |
135 | continue; | |
136 | } | |
e3127271 | 137 | if (!readfile(tfname, size)) { |
47f0387b | 138 | rcleanup(); |
e3127271 RC |
139 | continue; |
140 | } | |
141 | if (link(tfname, cp) < 0) | |
47f0387b | 142 | frecverr("%s: %m", tfname); |
e3127271 RC |
143 | (void) unlink(tfname); |
144 | tfname[0] = '\0'; | |
145 | nfiles++; | |
146 | continue; | |
147 | ||
148 | case '\3': /* read df file */ | |
149 | size = 0; | |
150 | while (*cp >= '0' && *cp <= '9') | |
151 | size = size * 10 + (*cp++ - '0'); | |
152 | if (*cp++ != ' ') | |
153 | break; | |
47f0387b RC |
154 | if (!chksize(size)) { |
155 | (void) write(1, "\2", 1); | |
156 | continue; | |
157 | } | |
e3127271 RC |
158 | (void) readfile(dfname = cp, size); |
159 | continue; | |
160 | } | |
47f0387b | 161 | frecverr("protocol screwup"); |
e3127271 RC |
162 | } |
163 | } | |
164 | ||
165 | /* | |
166 | * Read files send by lpd and copy them to the spooling directory. | |
167 | */ | |
168 | readfile(file, size) | |
169 | char *file; | |
170 | int size; | |
171 | { | |
172 | register char *cp; | |
173 | char buf[BUFSIZ]; | |
174 | register int i, j, amt; | |
175 | int fd, err; | |
176 | ||
adec4d9e | 177 | fd = open(file, O_WRONLY|O_CREAT, FILMOD); |
e3127271 | 178 | if (fd < 0) |
47f0387b | 179 | frecverr("%s: %m", file); |
e3127271 RC |
180 | ack(); |
181 | err = 0; | |
182 | for (i = 0; i < size; i += BUFSIZ) { | |
183 | amt = BUFSIZ; | |
184 | cp = buf; | |
185 | if (i + amt > size) | |
186 | amt = size - i; | |
187 | do { | |
188 | j = read(1, cp, amt); | |
189 | if (j <= 0) | |
47f0387b | 190 | frecverr("Lost connection"); |
e3127271 RC |
191 | amt -= j; |
192 | cp += j; | |
193 | } while (amt > 0); | |
194 | amt = BUFSIZ; | |
195 | if (i + amt > size) | |
196 | amt = size - i; | |
c6d1c018 | 197 | if (write(fd, buf, amt) != amt) { |
e3127271 | 198 | err++; |
c6d1c018 RC |
199 | break; |
200 | } | |
e3127271 RC |
201 | } |
202 | (void) close(fd); | |
203 | if (err) | |
47f0387b | 204 | frecverr("%s: write error", file); |
e3127271 RC |
205 | if (noresponse()) { /* file sent had bad data in it */ |
206 | (void) unlink(file); | |
207 | return(0); | |
208 | } | |
209 | ack(); | |
210 | return(1); | |
211 | } | |
212 | ||
e3127271 RC |
213 | noresponse() |
214 | { | |
215 | char resp; | |
216 | ||
217 | if (read(1, &resp, 1) != 1) | |
47f0387b | 218 | frecverr("Lost connection"); |
e3127271 RC |
219 | if (resp == '\0') |
220 | return(0); | |
221 | return(1); | |
222 | } | |
223 | ||
47f0387b RC |
224 | /* |
225 | * Check to see if there is enough space on the disk for size bytes. | |
226 | * 1 == OK, 0 == Not OK. | |
227 | */ | |
228 | chksize(size) | |
229 | int size; | |
230 | { | |
231 | struct stat stb; | |
232 | register char *ddev; | |
233 | int spacefree; | |
234 | struct fs fs; | |
235 | ||
236 | if (dfd < 0 || lseek(dfd, (long)(SBLOCK * DEV_BSIZE), 0) < 0) | |
237 | return(1); | |
238 | if (read(dfd, (char *)&fs, sizeof fs) != sizeof fs) | |
239 | return(1); | |
240 | spacefree = (fs.fs_cstotal.cs_nbfree * fs.fs_frag + | |
241 | fs.fs_cstotal.cs_nffree - fs.fs_dsize * fs.fs_minfree / 100) * | |
242 | fs.fs_fsize / 1024; | |
243 | size = (size + 1023) / 1024; | |
244 | if (minfree + size > spacefree) | |
245 | return(0); | |
246 | return(1); | |
247 | } | |
248 | ||
249 | read_number(fn) | |
250 | char *fn; | |
251 | { | |
252 | char lin[80]; | |
253 | register FILE *fp; | |
254 | ||
255 | if ((fp = fopen(fn, "r")) == NULL) | |
256 | return (0); | |
257 | if (fgets(lin, 80, fp) == NULL) { | |
258 | fclose(fp); | |
259 | return (0); | |
260 | } | |
261 | fclose(fp); | |
262 | return (atoi(lin)); | |
263 | } | |
264 | ||
e3127271 RC |
265 | /* |
266 | * Remove all the files associated with the current job being transfered. | |
267 | */ | |
47f0387b | 268 | rcleanup() |
e3127271 RC |
269 | { |
270 | register int i; | |
271 | ||
272 | if (tfname[0]) | |
273 | (void) unlink(tfname); | |
274 | if (dfname) | |
275 | do { | |
276 | do | |
277 | (void) unlink(dfname); | |
278 | while (dfname[i]-- != 'A'); | |
279 | dfname[i] = 'z'; | |
280 | } while (dfname[i-2]-- != 'd'); | |
281 | } | |
282 | ||
47f0387b | 283 | frecverr(msg, a1, a2) |
e3127271 RC |
284 | char *msg; |
285 | { | |
47f0387b RC |
286 | rcleanup(); |
287 | syslog(LOG_ERR, msg, a1, a2); | |
e3127271 RC |
288 | putchar('\1'); /* return error code */ |
289 | exit(1); | |
290 | } |