recvjob.c revision 1.11
1/* $OpenBSD: recvjob.c,v 1.11 1997/07/25 20:12:13 mickey Exp $ */ 2 3/* 4 * Copyright (c) 1983, 1993 5 * The Regents of the University of California. All rights reserved. 6 * 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 3. All advertising materials mentioning features or use of this software 17 * must display the following acknowledgement: 18 * This product includes software developed by the University of 19 * California, Berkeley and its contributors. 20 * 4. Neither the name of the University nor the names of its contributors 21 * may be used to endorse or promote products derived from this software 22 * without specific prior written permission. 23 * 24 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 25 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 27 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 30 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 34 * SUCH DAMAGE. 35 */ 36 37#ifndef lint 38static char copyright[] = 39"@(#) Copyright (c) 1983, 1993\n\ 40 The Regents of the University of California. All rights reserved.\n"; 41#endif /* not lint */ 42 43#ifndef lint 44#if 0 45static char sccsid[] = "@(#)recvjob.c 8.2 (Berkeley) 4/27/95"; 46#else 47static char rcsid[] = "$OpenBSD: recvjob.c,v 1.11 1997/07/25 20:12:13 mickey Exp $"; 48#endif 49#endif /* not lint */ 50 51/* 52 * Receive printer jobs from the network, queue them and 53 * start the printer daemon. 54 */ 55#include <sys/param.h> 56#include <sys/mount.h> 57#include <sys/stat.h> 58 59#include <unistd.h> 60#include <signal.h> 61#include <fcntl.h> 62#include <dirent.h> 63#include <syslog.h> 64#include <stdio.h> 65#include <stdlib.h> 66#include <string.h> 67#include "lp.h" 68#include "lp.local.h" 69#include "extern.h" 70#include "pathnames.h" 71 72#define ack() (void) write(1, sp, 1); 73 74static char dfname[NAME_MAX]; /* data files */ 75static int minfree; /* keep at least minfree blocks available */ 76static char *sp = ""; 77static char tfname[NAME_MAX]; /* tmp copy of cf before linking */ 78 79static int chksize __P((int)); 80static void frecverr __P((const char *, ...)); 81static int noresponse __P((void)); 82static void rcleanup __P((int)); 83static int read_number __P((char *)); 84static int readfile __P((char *, int)); 85static int readjob __P((void)); 86 87 88void 89recvjob() 90{ 91 struct stat stb; 92 int status; 93 94 /* 95 * Perform lookup for printer name or abbreviation 96 */ 97 if ((status = cgetent(&bp, printcapdb, printer)) == -2) 98 frecverr("cannot open printer description file"); 99 else if (status == -1) 100 frecverr("unknown printer %s", printer); 101 else if (status == -3) 102 fatal("potential reference loop detected in printcap file"); 103 104 if (cgetstr(bp, "lf", &LF) == -1) 105 LF = _PATH_CONSOLE; 106 if (cgetstr(bp, "sd", &SD) == -1) 107 SD = _PATH_DEFSPOOL; 108 if (cgetstr(bp, "lo", &LO) == -1) 109 LO = DEFLOCK; 110 111 (void) close(2); /* set up log file */ 112 if (open(LF, O_WRONLY|O_APPEND, 0664) < 0) { 113 syslog(LOG_ERR, "%s: %m", LF); 114 (void) open(_PATH_DEVNULL, O_WRONLY); 115 } 116 117 if (chdir(SD) < 0) 118 frecverr("%s: %s: %m", printer, SD); 119 if (stat(LO, &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(SD, &stb) < 0) 126 frecverr("%s: %s: %m", printer, SD); 127 minfree = 2 * read_number("minfree"); /* scale KB to 512 blocks */ 128 signal(SIGTERM, rcleanup); 129 signal(SIGPIPE, rcleanup); 130 131 if (readjob()) 132 printjob(); 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() 141{ 142 register int size, nfiles; 143 register char *cp; 144 145 ack(); 146 nfiles = 0; 147 for (;;) { 148 /* 149 * Read a command to tell us what to do 150 */ 151 cp = line; 152 do { 153 if ((size = read(1, cp, 1)) != 1) { 154 if (size < 0) 155 frecverr("%s: Lost connection", 156 printer); 157 return(nfiles); 158 } 159 } while (*cp++ != '\n' && (cp - line + 1) < sizeof line); 160 if (cp - line + 1 >= sizeof line) 161 frecverr("readjob overflow"); 162 *--cp = '\0'; 163 cp = line; 164 switch (*cp++) { 165 case '\1': /* cleanup because data sent was bad */ 166 rcleanup(0); 167 continue; 168 169 case '\2': /* read cf file */ 170 size = 0; 171 while (*cp >= '0' && *cp <= '9') 172 size = size * 10 + (*cp++ - '0'); 173 if (*cp++ != ' ') 174 break; 175 /* 176 * host name has been authenticated, we use our 177 * view of the host name since we may be passed 178 * something different than what gethostbyaddr() 179 * returns 180 */ 181 strncpy(cp + 6, from, sizeof(line) + line - cp - 7); 182 line[sizeof(line) -1 ] = '\0'; 183 strncpy(tfname, cp, sizeof tfname-1); 184 tfname[sizeof tfname-1] = '\0'; 185 tfname[0] = 't'; 186 if (strchr(tfname, '/')) 187 frecverr("readjob: %s: illegal path name", 188 tfname); 189 if (!chksize(size)) { 190 (void) write(1, "\2", 1); 191 continue; 192 } 193 if (!readfile(tfname, size)) { 194 rcleanup(0); 195 continue; 196 } 197 if (link(tfname, cp) < 0) 198 frecverr("%s: %m", tfname); 199 (void) unlink(tfname); 200 tfname[0] = '\0'; 201 nfiles++; 202 continue; 203 204 case '\3': /* read df file */ 205 size = 0; 206 while (*cp >= '0' && *cp <= '9') 207 size = size * 10 + (*cp++ - '0'); 208 if (*cp++ != ' ') 209 break; 210 if (!chksize(size)) { 211 (void) write(1, "\2", 1); 212 continue; 213 } 214 (void) strncpy(dfname, cp, sizeof dfname-1); 215 dfname[sizeof dfname-1] = '\0'; 216 if (strchr(dfname, '/')) 217 frecverr("readjob: %s: illegal path name", 218 dfname); 219 (void) readfile(dfname, size); 220 continue; 221 } 222 frecverr("protocol screwup: %s", line); 223 } 224} 225 226/* 227 * Read files send by lpd and copy them to the spooling directory. 228 */ 229static int 230readfile(file, size) 231 char *file; 232 int size; 233{ 234 register char *cp; 235 char buf[BUFSIZ]; 236 register int i, j, amt; 237 int fd, err; 238 239 fd = open(file, O_CREAT|O_EXCL|O_WRONLY, FILMOD); 240 if (fd < 0) 241 frecverr("readfile: %s: illegal path name: %m", file); 242 ack(); 243 err = 0; 244 for (i = 0; i < size; i += BUFSIZ) { 245 amt = BUFSIZ; 246 cp = buf; 247 if (i + amt > size) 248 amt = size - i; 249 do { 250 j = read(1, cp, amt); 251 if (j <= 0) 252 frecverr("Lost connection"); 253 amt -= j; 254 cp += j; 255 } while (amt > 0); 256 amt = BUFSIZ; 257 if (i + amt > size) 258 amt = size - i; 259 if (write(fd, buf, amt) != amt) { 260 err++; 261 break; 262 } 263 } 264 (void) close(fd); 265 if (err) 266 frecverr("%s: write error", file); 267 if (noresponse()) { /* file sent had bad data in it */ 268 (void) unlink(file); 269 return(0); 270 } 271 ack(); 272 return(1); 273} 274 275static int 276noresponse() 277{ 278 char resp; 279 280 if (read(1, &resp, 1) != 1) 281 frecverr("Lost connection"); 282 if (resp == '\0') 283 return(0); 284 return(1); 285} 286 287/* 288 * Check to see if there is enough space on the disk for size bytes. 289 * 1 == OK, 0 == Not OK. 290 */ 291static int 292chksize(size) 293 int size; 294{ 295 int spacefree; 296 struct statfs sfb; 297 298 if (statfs(".", &sfb) < 0) { 299 syslog(LOG_ERR, "%s: %m", "statfs(\".\")"); 300 return (1); 301 } 302 spacefree = sfb.f_bavail * (sfb.f_bsize / 512); 303 size = (size + 511) / 512; 304 if (minfree + size > spacefree) 305 return(0); 306 return(1); 307} 308 309static int 310read_number(fn) 311 char *fn; 312{ 313 char lin[80]; 314 register FILE *fp; 315 316 if ((fp = fopen(fn, "r")) == NULL) 317 return (0); 318 if (fgets(lin, 80, fp) == NULL) { 319 fclose(fp); 320 return (0); 321 } 322 fclose(fp); 323 return (atoi(lin)); 324} 325 326/* 327 * Remove all the files associated with the current job being transfered. 328 */ 329static void 330rcleanup(signo) 331 int signo; 332{ 333 if (tfname[0]) 334 (void) unlink(tfname); 335 if (dfname[0]) 336 do { 337 do 338 (void) unlink(dfname); 339 while (dfname[2]-- != 'A'); 340 dfname[2] = 'z'; 341 } while (dfname[0]-- != 'd'); 342 dfname[0] = '\0'; 343} 344 345#ifdef __STDC__ 346#include <stdarg.h> 347#else 348#include <varargs.h> 349#endif 350 351static void 352#ifdef __STDC__ 353frecverr(const char *msg, ...) 354#else 355frecverr(msg, va_alist) 356 char *msg; 357 va_dcl 358#endif 359{ 360 extern char fromb[]; 361 va_list ap; 362#ifdef __STDC__ 363 va_start(ap, msg); 364#else 365 va_start(ap); 366#endif 367 rcleanup(0); 368 syslog(LOG_ERR, "%s", fromb); 369 vsyslog(LOG_ERR, msg, ap); 370 va_end(ap); 371 putchar('\1'); /* return error code */ 372 exit(1); 373} 374