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