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