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