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