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