recvjob.c revision 80133
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#ifndef lint 42#if 0 43static char sccsid[] = "@(#)recvjob.c 8.2 (Berkeley) 4/27/95"; 44#endif 45static const char rcsid[] = 46 "$FreeBSD: head/usr.sbin/lpr/lpd/recvjob.c 80133 2001-07-22 07:25:27Z gad $"; 47#endif /* not lint */ 48 49/* 50 * Receive printer jobs from the network, queue them and 51 * start the printer daemon. 52 */ 53#include <sys/param.h> 54#include <sys/mount.h> 55#include <sys/stat.h> 56 57#include <unistd.h> 58#include <signal.h> 59#include <fcntl.h> 60#include <dirent.h> 61#include <errno.h> 62#include <syslog.h> 63#include <stdio.h> 64#include <stdlib.h> 65#include <string.h> 66#include "lp.h" 67#include "lp.local.h" 68#include "ctlinfo.h" 69#include "extern.h" 70#include "pathnames.h" 71 72#define ack() (void) write(STDOUT_FILENO, sp, 1); 73 74static char dfname[NAME_MAX]; /* data files */ 75static int minfree; /* keep at least minfree blocks available */ 76static const char *sp = ""; 77static char tfname[NAME_MAX]; /* tmp copy of cf before linking */ 78 79static int chksize(int _size); 80static void frecverr(const char *_msg, ...) __printf0like(1, 2); 81static int noresponse(void); 82static void rcleanup(int _signo); 83static int read_number(const char *_fn); 84static int readfile(struct printer *_pp, char *_file, int _size); 85static int readjob(struct printer *_pp); 86 87 88void 89recvjob(const char *printer) 90{ 91 struct stat stb; 92 int status; 93 struct printer myprinter, *pp = &myprinter; 94 95 /* 96 * Perform lookup for printer name or abbreviation 97 */ 98 init_printer(pp); 99 status = getprintcap(printer, pp); 100 switch (status) { 101 case PCAPERR_OSERR: 102 frecverr("cannot open printer description file"); 103 break; 104 case PCAPERR_NOTFOUND: 105 frecverr("unknown printer %s", printer); 106 break; 107 case PCAPERR_TCLOOP: 108 fatal(pp, "potential reference loop detected in printcap file"); 109 default: 110 break; 111 } 112 113 (void) close(2); /* set up log file */ 114 if (open(pp->log_file, O_WRONLY|O_APPEND, 0664) < 0) { 115 syslog(LOG_ERR, "%s: %m", pp->log_file); 116 (void) open(_PATH_DEVNULL, O_WRONLY); 117 } 118 119 if (chdir(pp->spool_dir) < 0) 120 frecverr("%s: chdir(%s): %s", pp->printer, pp->spool_dir, 121 strerror(errno)); 122 if (stat(pp->lock_file, &stb) == 0) { 123 if (stb.st_mode & 010) { 124 /* queue is disabled */ 125 putchar('\1'); /* return error code */ 126 exit(1); 127 } 128 } else if (stat(pp->spool_dir, &stb) < 0) 129 frecverr("%s: stat(%s): %s", pp->printer, pp->spool_dir, 130 strerror(errno)); 131 minfree = 2 * read_number("minfree"); /* scale KB to 512 blocks */ 132 signal(SIGTERM, rcleanup); 133 signal(SIGPIPE, rcleanup); 134 135 if (readjob(pp)) 136 printjob(pp); 137} 138 139/* 140 * Read printer jobs sent by lpd and copy them to the spooling directory. 141 * Return the number of jobs successfully transfered. 142 */ 143static int 144readjob(struct printer *pp) 145{ 146 register int size; 147 register char *cp; 148 int cfcnt, dfcnt; 149 char *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 do { 161 if ((size = read(STDOUT_FILENO, cp, 1)) != 1) { 162 if (size < 0) { 163 frecverr("%s: lost connection", 164 pp->printer); 165 /*NOTREACHED*/ 166 } 167 return (cfcnt); 168 } 169 } while (*cp++ != '\n' && (cp - line + 1) < sizeof(line)); 170 if (cp - line + 1 >= sizeof(line)) { 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 strlcpy(tfname, cp, sizeof(tfname)); 197 tfname[sizeof (tfname) - 1] = '\0'; 198 tfname[0] = 't'; 199 if (strchr(tfname, '/')) 200 frecverr("readjob: %s: illegal path name", 201 tfname); 202 if (!chksize(size)) { 203 (void) write(STDOUT_FILENO, "\2", 1); 204 continue; 205 } 206 if (!readfile(pp, tfname, size)) { 207 rcleanup(0); 208 continue; 209 } 210 errmsg = ctl_renametf(pp->printer, tfname); 211 tfname[0] = '\0'; 212 if (errmsg != NULL) { 213 frecverr("%s: %s", pp->printer, errmsg); 214 /*NOTREACHED*/ 215 } 216 cfcnt++; 217 continue; 218 219 case '\3': /* read df file */ 220 *givenid = '\0'; 221 *givenhost = '\0'; 222 size = 0; 223 while (*cp >= '0' && *cp <= '9') 224 size = size * 10 + (*cp++ - '0'); 225 if (*cp++ != ' ') 226 break; 227 if (!chksize(size)) { 228 (void) write(STDOUT_FILENO, "\2", 1); 229 continue; 230 } 231 strlcpy(dfname, cp, sizeof(dfname)); 232 if (strchr(dfname, '/')) { 233 frecverr("readjob: %s: illegal path name", 234 dfname); 235 /*NOTREACHED*/ 236 } 237 dfcnt++; 238 trstat_init(pp, dfname, dfcnt); 239 (void) readfile(pp, dfname, size); 240 trstat_write(pp, TR_RECVING, size, givenid, from_host, 241 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, int size) 254{ 255 register char *cp; 256 char buf[BUFSIZ]; 257 register int i, j, amt; 258 int fd, err; 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) != 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, 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#ifdef __STDC__ 375#include <stdarg.h> 376#else 377#include <varargs.h> 378#endif 379 380static void 381#ifdef __STDC__ 382frecverr(const char *msg, ...) 383#else 384frecverr(msg, va_alist) 385 char *msg; 386 va_dcl 387#endif 388{ 389 va_list ap; 390#ifdef __STDC__ 391 va_start(ap, msg); 392#else 393 va_start(ap); 394#endif 395 syslog(LOG_ERR, "Error receiving job from %s:", from_host); 396 vsyslog(LOG_ERR, msg, ap); 397 va_end(ap); 398 /* 399 * rcleanup is not called until AFTER logging the error message, 400 * because rcleanup will zap some variables which may have been 401 * supplied as parameters for that msg... 402 */ 403 rcleanup(0); 404 /* 405 * Add a minimal delay before returning the final error code to 406 * the sending host. This just in case that machine responds 407 * this error by INSTANTLY retrying (and instantly re-failing...). 408 * It would be stupid of the sending host to do that, but if there 409 * was a broken implementation which did it, the result might be 410 * obscure performance problems and a flood of syslog messages on 411 * the receiving host. 412 */ 413 sleep(2); /* a paranoid throttling measure */ 414 putchar('\1'); /* return error code */ 415 exit(1); 416} 417