recvjob.c revision 31492
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 "$Id: recvjob.c,v 1.11 1997/10/06 03:58:48 imp Exp $"; 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 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(pp) 141 struct printer *pp; 142{ 143 register int size, nfiles; 144 register char *cp; 145 146 ack(); 147 nfiles = 0; 148 for (;;) { 149 /* 150 * Read a command to tell us what to do 151 */ 152 cp = line; 153 do { 154 if ((size = read(1, cp, 1)) != 1) { 155 if (size < 0) 156 frecverr("%s: lost connection", 157 pp->printer); 158 return(nfiles); 159 } 160 } while (*cp++ != '\n' && (cp - line + 1) < sizeof(line)); 161 if (cp - line + 1 >= sizeof(line)) 162 frecverr("readjob overflow"); 163 *--cp = '\0'; 164 cp = line; 165 switch (*cp++) { 166 case '\1': /* cleanup because data sent was bad */ 167 rcleanup(0); 168 continue; 169 170 case '\2': /* read cf file */ 171 size = 0; 172 while (*cp >= '0' && *cp <= '9') 173 size = size * 10 + (*cp++ - '0'); 174 if (*cp++ != ' ') 175 break; 176 /* 177 * host name has been authenticated, we use our 178 * view of the host name since we may be passed 179 * something different than what gethostbyaddr() 180 * returns 181 */ 182 strncpy(cp + 6, from, sizeof(line) + line - cp - 7); 183 line[sizeof(line) - 1 ] = '\0'; 184 strncpy(tfname, cp, sizeof(tfname) - 1); 185 tfname[sizeof (tfname) - 1] = '\0'; 186 tfname[0] = 't'; 187 if (strchr(tfname, '/')) 188 frecverr("readjob: %s: illegal path name", 189 tfname); 190 if (!chksize(size)) { 191 (void) write(1, "\2", 1); 192 continue; 193 } 194 if (!readfile(tfname, size)) { 195 rcleanup(0); 196 continue; 197 } 198 if (link(tfname, cp) < 0) 199 frecverr("%s: %m", tfname); 200 (void) unlink(tfname); 201 tfname[0] = '\0'; 202 nfiles++; 203 continue; 204 205 case '\3': /* read df file */ 206 size = 0; 207 while (*cp >= '0' && *cp <= '9') 208 size = size * 10 + (*cp++ - '0'); 209 if (*cp++ != ' ') 210 break; 211 if (!chksize(size)) { 212 (void) write(1, "\2", 1); 213 continue; 214 } 215 (void) strncpy(dfname, cp, sizeof(dfname) - 1); 216 dfname[sizeof(dfname) - 1] = '\0'; 217 if (strchr(dfname, '/')) 218 frecverr("readjob: %s: illegal path name", 219 dfname); 220 (void) readfile(dfname, size); 221 continue; 222 } 223 frecverr("protocol screwup: %s", line); 224 } 225} 226 227/* 228 * Read files send by lpd and copy them to the spooling directory. 229 */ 230static int 231readfile(file, size) 232 char *file; 233 int size; 234{ 235 register char *cp; 236 char buf[BUFSIZ]; 237 register int i, j, amt; 238 int fd, err; 239 240 fd = open(file, O_CREAT|O_EXCL|O_WRONLY, FILMOD); 241 if (fd < 0) 242 frecverr("readfile: %s: illegal path name: %m", file); 243 ack(); 244 err = 0; 245 for (i = 0; i < size; i += BUFSIZ) { 246 amt = BUFSIZ; 247 cp = buf; 248 if (i + amt > size) 249 amt = size - i; 250 do { 251 j = read(1, cp, amt); 252 if (j <= 0) 253 frecverr("lost connection"); 254 amt -= j; 255 cp += j; 256 } while (amt > 0); 257 amt = BUFSIZ; 258 if (i + amt > size) 259 amt = size - i; 260 if (write(fd, buf, amt) != amt) { 261 err++; 262 break; 263 } 264 } 265 (void) close(fd); 266 if (err) 267 frecverr("%s: write error", file); 268 if (noresponse()) { /* file sent had bad data in it */ 269 if (strchr(file, '/') == NULL) 270 (void) unlink(file); 271 return(0); 272 } 273 ack(); 274 return(1); 275} 276 277static int 278noresponse() 279{ 280 char resp; 281 282 if (read(1, &resp, 1) != 1) 283 frecverr("lost connection"); 284 if (resp == '\0') 285 return(0); 286 return(1); 287} 288 289/* 290 * Check to see if there is enough space on the disk for size bytes. 291 * 1 == OK, 0 == Not OK. 292 */ 293static int 294chksize(size) 295 int size; 296{ 297 int spacefree; 298 struct statfs sfb; 299 300 if (statfs(".", &sfb) < 0) { 301 syslog(LOG_ERR, "%s: %m", "statfs(\".\")"); 302 return (1); 303 } 304 spacefree = sfb.f_bavail * (sfb.f_bsize / 512); 305 size = (size + 511) / 512; 306 if (minfree + size > spacefree) 307 return(0); 308 return(1); 309} 310 311static int 312read_number(fn) 313 char *fn; 314{ 315 char lin[80]; 316 register FILE *fp; 317 318 if ((fp = fopen(fn, "r")) == NULL) 319 return (0); 320 if (fgets(lin, 80, fp) == NULL) { 321 fclose(fp); 322 return (0); 323 } 324 fclose(fp); 325 return (atoi(lin)); 326} 327 328/* 329 * Remove all the files associated with the current job being transfered. 330 */ 331static void 332rcleanup(signo) 333 int signo; 334{ 335 if (tfname[0] && strchr(tfname, '/') == NULL) 336 (void) unlink(tfname); 337 if (dfname[0] && strchr(dfname, '/') == NULL) { 338 do { 339 do 340 (void) unlink(dfname); 341 while (dfname[2]-- != 'A'); 342 dfname[2] = 'z'; 343 } while (dfname[0]-- != 'd'); 344 } 345 dfname[0] = '\0'; 346} 347 348#ifdef __STDC__ 349#include <stdarg.h> 350#else 351#include <varargs.h> 352#endif 353 354static void 355#ifdef __STDC__ 356frecverr(const char *msg, ...) 357#else 358frecverr(msg, va_alist) 359 char *msg; 360 va_dcl 361#endif 362{ 363 va_list ap; 364#ifdef __STDC__ 365 va_start(ap, msg); 366#else 367 va_start(ap); 368#endif 369 rcleanup(0); 370 syslog(LOG_ERR, "%s", fromb); 371 vsyslog(LOG_ERR, msg, ap); 372 va_end(ap); 373 putchar('\1'); /* return error code */ 374 exit(1); 375} 376