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