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