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