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