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