recvjob.c revision 27748
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 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 42static char sccsid[] = "@(#)recvjob.c 8.2 (Berkeley) 4/27/95"; 43#endif /* not lint */ 44 45/* 46 * Receive printer jobs from the network, queue them and 47 * start the printer daemon. 48 */ 49#include <sys/param.h> 50#include <sys/mount.h> 51#include <sys/stat.h> 52 53#include <unistd.h> 54#include <signal.h> 55#include <fcntl.h> 56#include <dirent.h> 57#include <syslog.h> 58#include <stdio.h> 59#include <stdlib.h> 60#include <string.h> 61#include "lp.h" 62#include "lp.local.h" 63#include "extern.h" 64#include "pathnames.h" 65 66#define ack() (void) write(1, sp, 1); 67 68static char dfname[NAME_MAX]; /* data files */ 69static int minfree; /* keep at least minfree blocks available */ 70static char *sp = ""; 71static char tfname[NAME_MAX]; /* tmp copy of cf before linking */ 72 73static int chksize __P((int)); 74static void frecverr __P((const char *, ...)); 75static int noresponse __P((void)); 76static void rcleanup __P((int)); 77static int read_number __P((char *)); 78static int readfile __P((char *, int)); 79static int readjob __P((void)); 80 81 82void 83recvjob() 84{ 85 struct stat stb; 86 int status; 87 88 /* 89 * Perform lookup for printer name or abbreviation 90 */ 91 if ((status = cgetent(&bp, printcapdb, printer)) == -2) 92 frecverr("cannot open printer description file"); 93 else if (status == -1) 94 frecverr("unknown printer %s", printer); 95 else if (status == -3) 96 fatal("potential reference loop detected in printcap file"); 97 98 if (cgetstr(bp, "lf", &LF) == -1) 99 LF = _PATH_CONSOLE; 100 if (cgetstr(bp, "sd", &SD) == -1) 101 SD = _PATH_DEFSPOOL; 102 if (cgetstr(bp, "lo", &LO) == -1) 103 LO = DEFLOCK; 104 105 (void) close(2); /* set up log file */ 106 if (open(LF, O_WRONLY|O_APPEND, 0664) < 0) { 107 syslog(LOG_ERR, "%s: %m", LF); 108 (void) open(_PATH_DEVNULL, O_WRONLY); 109 } 110 111 if (chdir(SD) < 0) 112 frecverr("%s: %s: %m", printer, SD); 113 if (stat(LO, &stb) == 0) { 114 if (stb.st_mode & 010) { 115 /* queue is disabled */ 116 putchar('\1'); /* return error code */ 117 exit(1); 118 } 119 } else if (stat(SD, &stb) < 0) 120 frecverr("%s: %s: %m", printer, SD); 121 minfree = 2 * read_number("minfree"); /* scale KB to 512 blocks */ 122 signal(SIGTERM, rcleanup); 123 signal(SIGPIPE, rcleanup); 124 125 if (readjob()) 126 printjob(); 127} 128 129/* 130 * Read printer jobs sent by lpd and copy them to the spooling directory. 131 * Return the number of jobs successfully transfered. 132 */ 133static int 134readjob() 135{ 136 register int size, nfiles; 137 register char *cp; 138 139 ack(); 140 nfiles = 0; 141 for (;;) { 142 /* 143 * Read a command to tell us what to do 144 */ 145 cp = line; 146 do { 147 if ((size = read(1, cp, 1)) != 1) { 148 if (size < 0) 149 frecverr("%s: Lost connection", 150 printer); 151 return(nfiles); 152 } 153 } while (*cp++ != '\n' && (cp - line + 1) < sizeof(line)); 154 if (cp - line + 1 >= sizeof(line)) 155 frecverr("readjob overflow"); 156 *--cp = '\0'; 157 cp = line; 158 switch (*cp++) { 159 case '\1': /* cleanup because data sent was bad */ 160 rcleanup(0); 161 continue; 162 163 case '\2': /* read cf file */ 164 size = 0; 165 while (*cp >= '0' && *cp <= '9') 166 size = size * 10 + (*cp++ - '0'); 167 if (*cp++ != ' ') 168 break; 169 /* 170 * host name has been authenticated, we use our 171 * view of the host name since we may be passed 172 * something different than what gethostbyaddr() 173 * returns 174 */ 175 strncpy(cp + 6, from, sizeof(line) + line - cp - 7); 176 line[sizeof(line) - 1 ] = '\0'; 177 strncpy(tfname, cp, sizeof(tfname) - 1); 178 tfname[sizeof (tfname) - 1] = '\0'; 179 tfname[0] = 't'; 180 if (strchr(tfname, '/')) 181 frecverr("readjob: %s: illegal path name", 182 tfname); 183 if (!chksize(size)) { 184 (void) write(1, "\2", 1); 185 continue; 186 } 187 if (!readfile(tfname, size)) { 188 rcleanup(0); 189 continue; 190 } 191 if (link(tfname, cp) < 0) 192 frecverr("%s: %m", tfname); 193 (void) unlink(tfname); 194 tfname[0] = '\0'; 195 nfiles++; 196 continue; 197 198 case '\3': /* read df file */ 199 size = 0; 200 while (*cp >= '0' && *cp <= '9') 201 size = size * 10 + (*cp++ - '0'); 202 if (*cp++ != ' ') 203 break; 204 if (!chksize(size)) { 205 (void) write(1, "\2", 1); 206 continue; 207 } 208 (void) strncpy(dfname, cp, sizeof(dfname) - 1); 209 dfname[sizeof(dfname) - 1] = '\0'; 210 if (strchr(dfname, '/')) 211 frecverr("readjob: %s: illegal path name", 212 dfname); 213 (void) readfile(dfname, size); 214 continue; 215 } 216 frecverr("protocol screwup: %s", line); 217 } 218} 219 220/* 221 * Read files send by lpd and copy them to the spooling directory. 222 */ 223static int 224readfile(file, size) 225 char *file; 226 int size; 227{ 228 register char *cp; 229 char buf[BUFSIZ]; 230 register int i, j, amt; 231 int fd, err; 232 233 fd = open(file, O_CREAT|O_EXCL|O_WRONLY, FILMOD); 234 if (fd < 0) 235 frecverr("readfile: %s: illegal path name: %m", file); 236 ack(); 237 err = 0; 238 for (i = 0; i < size; i += BUFSIZ) { 239 amt = BUFSIZ; 240 cp = buf; 241 if (i + amt > size) 242 amt = size - i; 243 do { 244 j = read(1, cp, amt); 245 if (j <= 0) 246 frecverr("Lost connection"); 247 amt -= j; 248 cp += j; 249 } while (amt > 0); 250 amt = BUFSIZ; 251 if (i + amt > size) 252 amt = size - i; 253 if (write(fd, buf, amt) != amt) { 254 err++; 255 break; 256 } 257 } 258 (void) close(fd); 259 if (err) 260 frecverr("%s: write error", file); 261 if (noresponse()) { /* file sent had bad data in it */ 262 (void) unlink(file); 263 return(0); 264 } 265 ack(); 266 return(1); 267} 268 269static int 270noresponse() 271{ 272 char resp; 273 274 if (read(1, &resp, 1) != 1) 275 frecverr("Lost connection"); 276 if (resp == '\0') 277 return(0); 278 return(1); 279} 280 281/* 282 * Check to see if there is enough space on the disk for size bytes. 283 * 1 == OK, 0 == Not OK. 284 */ 285static int 286chksize(size) 287 int size; 288{ 289 int spacefree; 290 struct statfs sfb; 291 292 if (statfs(".", &sfb) < 0) { 293 syslog(LOG_ERR, "%s: %m", "statfs(\".\")"); 294 return (1); 295 } 296 spacefree = sfb.f_bavail * (sfb.f_bsize / 512); 297 size = (size + 511) / 512; 298 if (minfree + size > spacefree) 299 return(0); 300 return(1); 301} 302 303static int 304read_number(fn) 305 char *fn; 306{ 307 char lin[80]; 308 register FILE *fp; 309 310 if ((fp = fopen(fn, "r")) == NULL) 311 return (0); 312 if (fgets(lin, 80, fp) == NULL) { 313 fclose(fp); 314 return (0); 315 } 316 fclose(fp); 317 return (atoi(lin)); 318} 319 320/* 321 * Remove all the files associated with the current job being transfered. 322 */ 323static void 324rcleanup(signo) 325 int signo; 326{ 327 if (tfname[0]) 328 (void) unlink(tfname); 329 if (dfname[0]) 330 do { 331 do 332 (void) unlink(dfname); 333 while (dfname[2]-- != 'A'); 334 dfname[2] = 'z'; 335 } while (dfname[0]-- != 'd'); 336 dfname[0] = '\0'; 337} 338 339#if __STDC__ 340#include <stdarg.h> 341#else 342#include <varargs.h> 343#endif 344 345static void 346#if __STDC__ 347frecverr(const char *msg, ...) 348#else 349frecverr(msg, va_alist) 350 char *msg; 351 va_dcl 352#endif 353{ 354 va_list ap; 355#if __STDC__ 356 va_start(ap, msg); 357#else 358 va_start(ap); 359#endif 360 rcleanup(0); 361 syslog(LOG_ERR, "%s", fromb); 362 vsyslog(LOG_ERR, msg, ap); 363 va_end(ap); 364 putchar('\1'); /* return error code */ 365 exit(1); 366} 367