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