recvjob.c revision 27748
11553Srgrimes/* 21553Srgrimes * Copyright (c) 1983, 1993 31553Srgrimes * The Regents of the University of California. All rights reserved. 41553Srgrimes * 51553Srgrimes * 61553Srgrimes * Redistribution and use in source and binary forms, with or without 71553Srgrimes * modification, are permitted provided that the following conditions 81553Srgrimes * are met: 91553Srgrimes * 1. Redistributions of source code must retain the above copyright 101553Srgrimes * notice, this list of conditions and the following disclaimer. 111553Srgrimes * 2. Redistributions in binary form must reproduce the above copyright 121553Srgrimes * notice, this list of conditions and the following disclaimer in the 131553Srgrimes * documentation and/or other materials provided with the distribution. 141553Srgrimes * 3. All advertising materials mentioning features or use of this software 151553Srgrimes * must display the following acknowledgement: 161553Srgrimes * This product includes software developed by the University of 171553Srgrimes * California, Berkeley and its contributors. 181553Srgrimes * 4. Neither the name of the University nor the names of its contributors 191553Srgrimes * may be used to endorse or promote products derived from this software 201553Srgrimes * without specific prior written permission. 211553Srgrimes * 221553Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 231553Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 241553Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 251553Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 261553Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 271553Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 281553Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 291553Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 301553Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 311553Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 321553Srgrimes * SUCH DAMAGE. 331553Srgrimes */ 341553Srgrimes 351553Srgrimes#ifndef lint 361553Srgrimesstatic char copyright[] = 371553Srgrimes"@(#) Copyright (c) 1983, 1993\n\ 381553Srgrimes The Regents of the University of California. All rights reserved.\n"; 391553Srgrimes#endif /* not lint */ 401553Srgrimes 411553Srgrimes#ifndef lint 4215648Sjoergstatic char sccsid[] = "@(#)recvjob.c 8.2 (Berkeley) 4/27/95"; 431553Srgrimes#endif /* not lint */ 441553Srgrimes 451553Srgrimes/* 461553Srgrimes * Receive printer jobs from the network, queue them and 471553Srgrimes * start the printer daemon. 481553Srgrimes */ 491553Srgrimes#include <sys/param.h> 501553Srgrimes#include <sys/mount.h> 511553Srgrimes#include <sys/stat.h> 521553Srgrimes 531553Srgrimes#include <unistd.h> 541553Srgrimes#include <signal.h> 551553Srgrimes#include <fcntl.h> 561553Srgrimes#include <dirent.h> 571553Srgrimes#include <syslog.h> 581553Srgrimes#include <stdio.h> 591553Srgrimes#include <stdlib.h> 601553Srgrimes#include <string.h> 611553Srgrimes#include "lp.h" 621553Srgrimes#include "lp.local.h" 631553Srgrimes#include "extern.h" 641553Srgrimes#include "pathnames.h" 651553Srgrimes 661553Srgrimes#define ack() (void) write(1, sp, 1); 671553Srgrimes 6827748Simpstatic char dfname[NAME_MAX]; /* data files */ 691553Srgrimesstatic int minfree; /* keep at least minfree blocks available */ 701553Srgrimesstatic char *sp = ""; 7127748Simpstatic char tfname[NAME_MAX]; /* tmp copy of cf before linking */ 721553Srgrimes 731553Srgrimesstatic int chksize __P((int)); 741553Srgrimesstatic void frecverr __P((const char *, ...)); 751553Srgrimesstatic int noresponse __P((void)); 761553Srgrimesstatic void rcleanup __P((int)); 771553Srgrimesstatic int read_number __P((char *)); 781553Srgrimesstatic int readfile __P((char *, int)); 791553Srgrimesstatic int readjob __P((void)); 801553Srgrimes 811553Srgrimes 821553Srgrimesvoid 831553Srgrimesrecvjob() 841553Srgrimes{ 851553Srgrimes struct stat stb; 861553Srgrimes int status; 871553Srgrimes 881553Srgrimes /* 891553Srgrimes * Perform lookup for printer name or abbreviation 901553Srgrimes */ 911553Srgrimes if ((status = cgetent(&bp, printcapdb, printer)) == -2) 921553Srgrimes frecverr("cannot open printer description file"); 931553Srgrimes else if (status == -1) 941553Srgrimes frecverr("unknown printer %s", printer); 951553Srgrimes else if (status == -3) 961553Srgrimes fatal("potential reference loop detected in printcap file"); 9727748Simp 981553Srgrimes if (cgetstr(bp, "lf", &LF) == -1) 991553Srgrimes LF = _PATH_CONSOLE; 1001553Srgrimes if (cgetstr(bp, "sd", &SD) == -1) 1011553Srgrimes SD = _PATH_DEFSPOOL; 1021553Srgrimes if (cgetstr(bp, "lo", &LO) == -1) 1031553Srgrimes LO = DEFLOCK; 1041553Srgrimes 1051553Srgrimes (void) close(2); /* set up log file */ 1061553Srgrimes if (open(LF, O_WRONLY|O_APPEND, 0664) < 0) { 1071553Srgrimes syslog(LOG_ERR, "%s: %m", LF); 1081553Srgrimes (void) open(_PATH_DEVNULL, O_WRONLY); 1091553Srgrimes } 1101553Srgrimes 1111553Srgrimes if (chdir(SD) < 0) 1121553Srgrimes frecverr("%s: %s: %m", printer, SD); 1131553Srgrimes if (stat(LO, &stb) == 0) { 1141553Srgrimes if (stb.st_mode & 010) { 1151553Srgrimes /* queue is disabled */ 1161553Srgrimes putchar('\1'); /* return error code */ 1171553Srgrimes exit(1); 1181553Srgrimes } 1191553Srgrimes } else if (stat(SD, &stb) < 0) 1201553Srgrimes frecverr("%s: %s: %m", printer, SD); 1211553Srgrimes minfree = 2 * read_number("minfree"); /* scale KB to 512 blocks */ 1221553Srgrimes signal(SIGTERM, rcleanup); 1231553Srgrimes signal(SIGPIPE, rcleanup); 1241553Srgrimes 1251553Srgrimes if (readjob()) 1261553Srgrimes printjob(); 1271553Srgrimes} 1281553Srgrimes 1291553Srgrimes/* 1301553Srgrimes * Read printer jobs sent by lpd and copy them to the spooling directory. 1311553Srgrimes * Return the number of jobs successfully transfered. 1321553Srgrimes */ 1331553Srgrimesstatic int 1341553Srgrimesreadjob() 1351553Srgrimes{ 1361553Srgrimes register int size, nfiles; 1371553Srgrimes register char *cp; 1381553Srgrimes 1391553Srgrimes ack(); 1401553Srgrimes nfiles = 0; 1411553Srgrimes for (;;) { 1421553Srgrimes /* 1431553Srgrimes * Read a command to tell us what to do 1441553Srgrimes */ 1451553Srgrimes cp = line; 1461553Srgrimes do { 1471553Srgrimes if ((size = read(1, cp, 1)) != 1) { 1481553Srgrimes if (size < 0) 14927748Simp frecverr("%s: Lost connection", 15027748Simp printer); 1511553Srgrimes return(nfiles); 1521553Srgrimes } 15327748Simp } while (*cp++ != '\n' && (cp - line + 1) < sizeof(line)); 15427748Simp if (cp - line + 1 >= sizeof(line)) 15527748Simp frecverr("readjob overflow"); 1561553Srgrimes *--cp = '\0'; 1571553Srgrimes cp = line; 1581553Srgrimes switch (*cp++) { 1591553Srgrimes case '\1': /* cleanup because data sent was bad */ 1601553Srgrimes rcleanup(0); 1611553Srgrimes continue; 1621553Srgrimes 1631553Srgrimes case '\2': /* read cf file */ 1641553Srgrimes size = 0; 1651553Srgrimes while (*cp >= '0' && *cp <= '9') 1661553Srgrimes size = size * 10 + (*cp++ - '0'); 1671553Srgrimes if (*cp++ != ' ') 1681553Srgrimes break; 1691553Srgrimes /* 1701553Srgrimes * host name has been authenticated, we use our 1711553Srgrimes * view of the host name since we may be passed 1721553Srgrimes * something different than what gethostbyaddr() 1731553Srgrimes * returns 1741553Srgrimes */ 17527748Simp strncpy(cp + 6, from, sizeof(line) + line - cp - 7); 17627748Simp line[sizeof(line) - 1 ] = '\0'; 17727748Simp strncpy(tfname, cp, sizeof(tfname) - 1); 17827748Simp tfname[sizeof (tfname) - 1] = '\0'; 1791553Srgrimes tfname[0] = 't'; 18027748Simp if (strchr(tfname, '/')) 18127748Simp frecverr("readjob: %s: illegal path name", 18227748Simp tfname); 1831553Srgrimes if (!chksize(size)) { 1841553Srgrimes (void) write(1, "\2", 1); 1851553Srgrimes continue; 1861553Srgrimes } 1871553Srgrimes if (!readfile(tfname, size)) { 1881553Srgrimes rcleanup(0); 1891553Srgrimes continue; 1901553Srgrimes } 1911553Srgrimes if (link(tfname, cp) < 0) 1921553Srgrimes frecverr("%s: %m", tfname); 1931553Srgrimes (void) unlink(tfname); 1941553Srgrimes tfname[0] = '\0'; 1951553Srgrimes nfiles++; 1961553Srgrimes continue; 1971553Srgrimes 1981553Srgrimes case '\3': /* read df file */ 1991553Srgrimes size = 0; 2001553Srgrimes while (*cp >= '0' && *cp <= '9') 2011553Srgrimes size = size * 10 + (*cp++ - '0'); 2021553Srgrimes if (*cp++ != ' ') 2031553Srgrimes break; 2041553Srgrimes if (!chksize(size)) { 2051553Srgrimes (void) write(1, "\2", 1); 2061553Srgrimes continue; 2071553Srgrimes } 20827748Simp (void) strncpy(dfname, cp, sizeof(dfname) - 1); 20927748Simp dfname[sizeof(dfname) - 1] = '\0'; 21027635Simp if (strchr(dfname, '/')) 2111553Srgrimes frecverr("readjob: %s: illegal path name", 2121553Srgrimes dfname); 2131553Srgrimes (void) readfile(dfname, size); 2141553Srgrimes continue; 2151553Srgrimes } 2161553Srgrimes frecverr("protocol screwup: %s", line); 2171553Srgrimes } 2181553Srgrimes} 2191553Srgrimes 2201553Srgrimes/* 2211553Srgrimes * Read files send by lpd and copy them to the spooling directory. 2221553Srgrimes */ 2231553Srgrimesstatic int 2241553Srgrimesreadfile(file, size) 2251553Srgrimes char *file; 2261553Srgrimes int size; 2271553Srgrimes{ 2281553Srgrimes register char *cp; 2291553Srgrimes char buf[BUFSIZ]; 2301553Srgrimes register int i, j, amt; 2311553Srgrimes int fd, err; 2321553Srgrimes 2331553Srgrimes fd = open(file, O_CREAT|O_EXCL|O_WRONLY, FILMOD); 2341553Srgrimes if (fd < 0) 2351553Srgrimes frecverr("readfile: %s: illegal path name: %m", file); 2361553Srgrimes ack(); 2371553Srgrimes err = 0; 2381553Srgrimes for (i = 0; i < size; i += BUFSIZ) { 2391553Srgrimes amt = BUFSIZ; 2401553Srgrimes cp = buf; 2411553Srgrimes if (i + amt > size) 2421553Srgrimes amt = size - i; 2431553Srgrimes do { 2441553Srgrimes j = read(1, cp, amt); 2451553Srgrimes if (j <= 0) 2461553Srgrimes frecverr("Lost connection"); 2471553Srgrimes amt -= j; 2481553Srgrimes cp += j; 2491553Srgrimes } while (amt > 0); 2501553Srgrimes amt = BUFSIZ; 2511553Srgrimes if (i + amt > size) 2521553Srgrimes amt = size - i; 2531553Srgrimes if (write(fd, buf, amt) != amt) { 2541553Srgrimes err++; 2551553Srgrimes break; 2561553Srgrimes } 2571553Srgrimes } 2581553Srgrimes (void) close(fd); 2591553Srgrimes if (err) 2601553Srgrimes frecverr("%s: write error", file); 2611553Srgrimes if (noresponse()) { /* file sent had bad data in it */ 2621553Srgrimes (void) unlink(file); 2631553Srgrimes return(0); 2641553Srgrimes } 2651553Srgrimes ack(); 2661553Srgrimes return(1); 2671553Srgrimes} 2681553Srgrimes 2691553Srgrimesstatic int 2701553Srgrimesnoresponse() 2711553Srgrimes{ 2721553Srgrimes char resp; 2731553Srgrimes 2741553Srgrimes if (read(1, &resp, 1) != 1) 2751553Srgrimes frecverr("Lost connection"); 2761553Srgrimes if (resp == '\0') 2771553Srgrimes return(0); 2781553Srgrimes return(1); 2791553Srgrimes} 2801553Srgrimes 2811553Srgrimes/* 2821553Srgrimes * Check to see if there is enough space on the disk for size bytes. 2831553Srgrimes * 1 == OK, 0 == Not OK. 2841553Srgrimes */ 2851553Srgrimesstatic int 2861553Srgrimeschksize(size) 2871553Srgrimes int size; 2881553Srgrimes{ 2891553Srgrimes int spacefree; 2901553Srgrimes struct statfs sfb; 2911553Srgrimes 2921553Srgrimes if (statfs(".", &sfb) < 0) { 2931553Srgrimes syslog(LOG_ERR, "%s: %m", "statfs(\".\")"); 2941553Srgrimes return (1); 2951553Srgrimes } 2961553Srgrimes spacefree = sfb.f_bavail * (sfb.f_bsize / 512); 2971553Srgrimes size = (size + 511) / 512; 2981553Srgrimes if (minfree + size > spacefree) 2991553Srgrimes return(0); 3001553Srgrimes return(1); 3011553Srgrimes} 3021553Srgrimes 3031553Srgrimesstatic int 3041553Srgrimesread_number(fn) 3051553Srgrimes char *fn; 3061553Srgrimes{ 3071553Srgrimes char lin[80]; 3081553Srgrimes register FILE *fp; 3091553Srgrimes 3101553Srgrimes if ((fp = fopen(fn, "r")) == NULL) 3111553Srgrimes return (0); 3121553Srgrimes if (fgets(lin, 80, fp) == NULL) { 3131553Srgrimes fclose(fp); 3141553Srgrimes return (0); 3151553Srgrimes } 3161553Srgrimes fclose(fp); 3171553Srgrimes return (atoi(lin)); 3181553Srgrimes} 3191553Srgrimes 3201553Srgrimes/* 3211553Srgrimes * Remove all the files associated with the current job being transfered. 3221553Srgrimes */ 3231553Srgrimesstatic void 3241553Srgrimesrcleanup(signo) 3251553Srgrimes int signo; 3261553Srgrimes{ 3271553Srgrimes if (tfname[0]) 3281553Srgrimes (void) unlink(tfname); 3291553Srgrimes if (dfname[0]) 3301553Srgrimes do { 3311553Srgrimes do 3321553Srgrimes (void) unlink(dfname); 3331553Srgrimes while (dfname[2]-- != 'A'); 3341553Srgrimes dfname[2] = 'z'; 3351553Srgrimes } while (dfname[0]-- != 'd'); 3361553Srgrimes dfname[0] = '\0'; 3371553Srgrimes} 3381553Srgrimes 3391553Srgrimes#if __STDC__ 3401553Srgrimes#include <stdarg.h> 3411553Srgrimes#else 3421553Srgrimes#include <varargs.h> 3431553Srgrimes#endif 3441553Srgrimes 3451553Srgrimesstatic void 3461553Srgrimes#if __STDC__ 3471553Srgrimesfrecverr(const char *msg, ...) 3481553Srgrimes#else 3491553Srgrimesfrecverr(msg, va_alist) 3501553Srgrimes char *msg; 3511553Srgrimes va_dcl 3521553Srgrimes#endif 3531553Srgrimes{ 3541553Srgrimes va_list ap; 3551553Srgrimes#if __STDC__ 3561553Srgrimes va_start(ap, msg); 3571553Srgrimes#else 3581553Srgrimes va_start(ap); 3591553Srgrimes#endif 3601553Srgrimes rcleanup(0); 3611553Srgrimes syslog(LOG_ERR, "%s", fromb); 3621553Srgrimes vsyslog(LOG_ERR, msg, ap); 3631553Srgrimes va_end(ap); 3641553Srgrimes putchar('\1'); /* return error code */ 3651553Srgrimes exit(1); 3661553Srgrimes} 367