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