recvjob.c revision 31492
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 3629780Scharnierstatic const 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 4229780Scharnier#if 0 4315648Sjoergstatic char sccsid[] = "@(#)recvjob.c 8.2 (Berkeley) 4/27/95"; 4429780Scharnier#endif 4529780Scharnierstatic const char rcsid[] = 4631492Swollman "$Id: recvjob.c,v 1.11 1997/10/06 03:58:48 imp Exp $"; 471553Srgrimes#endif /* not lint */ 481553Srgrimes 491553Srgrimes/* 501553Srgrimes * Receive printer jobs from the network, queue them and 511553Srgrimes * start the printer daemon. 521553Srgrimes */ 531553Srgrimes#include <sys/param.h> 541553Srgrimes#include <sys/mount.h> 551553Srgrimes#include <sys/stat.h> 561553Srgrimes 571553Srgrimes#include <unistd.h> 581553Srgrimes#include <signal.h> 591553Srgrimes#include <fcntl.h> 601553Srgrimes#include <dirent.h> 611553Srgrimes#include <syslog.h> 621553Srgrimes#include <stdio.h> 631553Srgrimes#include <stdlib.h> 641553Srgrimes#include <string.h> 651553Srgrimes#include "lp.h" 661553Srgrimes#include "lp.local.h" 671553Srgrimes#include "extern.h" 681553Srgrimes#include "pathnames.h" 691553Srgrimes 701553Srgrimes#define ack() (void) write(1, sp, 1); 711553Srgrimes 7227748Simpstatic char dfname[NAME_MAX]; /* data files */ 731553Srgrimesstatic int minfree; /* keep at least minfree blocks available */ 741553Srgrimesstatic char *sp = ""; 7527748Simpstatic char tfname[NAME_MAX]; /* tmp copy of cf before linking */ 761553Srgrimes 771553Srgrimesstatic int chksize __P((int)); 781553Srgrimesstatic void frecverr __P((const char *, ...)); 791553Srgrimesstatic int noresponse __P((void)); 801553Srgrimesstatic void rcleanup __P((int)); 811553Srgrimesstatic int read_number __P((char *)); 821553Srgrimesstatic int readfile __P((char *, int)); 8331492Swollmanstatic int readjob __P((struct printer *pp)); 841553Srgrimes 851553Srgrimes 861553Srgrimesvoid 8731492Swollmanrecvjob(printer) 8831492Swollman const char *printer; 891553Srgrimes{ 901553Srgrimes struct stat stb; 911553Srgrimes int status; 9231492Swollman struct printer myprinter, *pp = &myprinter; 931553Srgrimes 941553Srgrimes /* 951553Srgrimes * Perform lookup for printer name or abbreviation 961553Srgrimes */ 9731492Swollman status = getprintcap(printer, pp); 9831492Swollman switch (status) { 9931492Swollman case PCAPERR_OSERR: 1001553Srgrimes frecverr("cannot open printer description file"); 10131492Swollman break; 10231492Swollman case PCAPERR_NOTFOUND: 1031553Srgrimes frecverr("unknown printer %s", printer); 10431492Swollman break; 10531492Swollman case PCAPERR_TCLOOP: 10631492Swollman fatal(pp, "potential reference loop detected in printcap file"); 10731492Swollman default: 10831492Swollman break; 10931492Swollman } 11027748Simp 1111553Srgrimes (void) close(2); /* set up log file */ 11231492Swollman if (open(pp->log_file, O_WRONLY|O_APPEND, 0664) < 0) { 11331492Swollman syslog(LOG_ERR, "%s: %m", pp->log_file); 1141553Srgrimes (void) open(_PATH_DEVNULL, O_WRONLY); 1151553Srgrimes } 1161553Srgrimes 11731492Swollman if (chdir(pp->spool_dir) < 0) 11831492Swollman frecverr("%s: %s: %m", pp->printer, pp->spool_dir); 11931492Swollman if (stat(pp->lock_file, &stb) == 0) { 1201553Srgrimes if (stb.st_mode & 010) { 1211553Srgrimes /* queue is disabled */ 1221553Srgrimes putchar('\1'); /* return error code */ 1231553Srgrimes exit(1); 1241553Srgrimes } 12531492Swollman } else if (stat(pp->spool_dir, &stb) < 0) 12631492Swollman frecverr("%s: %s: %m", pp->printer, pp->spool_dir); 1271553Srgrimes minfree = 2 * read_number("minfree"); /* scale KB to 512 blocks */ 1281553Srgrimes signal(SIGTERM, rcleanup); 1291553Srgrimes signal(SIGPIPE, rcleanup); 1301553Srgrimes 13131492Swollman if (readjob(pp)) 13231492Swollman printjob(pp); 1331553Srgrimes} 1341553Srgrimes 1351553Srgrimes/* 1361553Srgrimes * Read printer jobs sent by lpd and copy them to the spooling directory. 1371553Srgrimes * Return the number of jobs successfully transfered. 1381553Srgrimes */ 1391553Srgrimesstatic int 14031492Swollmanreadjob(pp) 14131492Swollman struct printer *pp; 1421553Srgrimes{ 1431553Srgrimes register int size, nfiles; 1441553Srgrimes register char *cp; 1451553Srgrimes 1461553Srgrimes ack(); 1471553Srgrimes nfiles = 0; 1481553Srgrimes for (;;) { 1491553Srgrimes /* 1501553Srgrimes * Read a command to tell us what to do 1511553Srgrimes */ 1521553Srgrimes cp = line; 1531553Srgrimes do { 1541553Srgrimes if ((size = read(1, cp, 1)) != 1) { 1551553Srgrimes if (size < 0) 15629780Scharnier frecverr("%s: lost connection", 15731492Swollman pp->printer); 1581553Srgrimes return(nfiles); 1591553Srgrimes } 16027748Simp } while (*cp++ != '\n' && (cp - line + 1) < sizeof(line)); 16127748Simp if (cp - line + 1 >= sizeof(line)) 16227748Simp frecverr("readjob overflow"); 1631553Srgrimes *--cp = '\0'; 1641553Srgrimes cp = line; 1651553Srgrimes switch (*cp++) { 1661553Srgrimes case '\1': /* cleanup because data sent was bad */ 1671553Srgrimes rcleanup(0); 1681553Srgrimes continue; 1691553Srgrimes 1701553Srgrimes case '\2': /* read cf file */ 1711553Srgrimes size = 0; 1721553Srgrimes while (*cp >= '0' && *cp <= '9') 1731553Srgrimes size = size * 10 + (*cp++ - '0'); 1741553Srgrimes if (*cp++ != ' ') 1751553Srgrimes break; 1761553Srgrimes /* 1771553Srgrimes * host name has been authenticated, we use our 1781553Srgrimes * view of the host name since we may be passed 1791553Srgrimes * something different than what gethostbyaddr() 1801553Srgrimes * returns 1811553Srgrimes */ 18227748Simp strncpy(cp + 6, from, sizeof(line) + line - cp - 7); 18327748Simp line[sizeof(line) - 1 ] = '\0'; 18427748Simp strncpy(tfname, cp, sizeof(tfname) - 1); 18527748Simp tfname[sizeof (tfname) - 1] = '\0'; 1861553Srgrimes tfname[0] = 't'; 18727748Simp if (strchr(tfname, '/')) 18827748Simp frecverr("readjob: %s: illegal path name", 18927748Simp tfname); 1901553Srgrimes if (!chksize(size)) { 1911553Srgrimes (void) write(1, "\2", 1); 1921553Srgrimes continue; 1931553Srgrimes } 1941553Srgrimes if (!readfile(tfname, size)) { 1951553Srgrimes rcleanup(0); 1961553Srgrimes continue; 1971553Srgrimes } 1981553Srgrimes if (link(tfname, cp) < 0) 1991553Srgrimes frecverr("%s: %m", tfname); 2001553Srgrimes (void) unlink(tfname); 2011553Srgrimes tfname[0] = '\0'; 2021553Srgrimes nfiles++; 2031553Srgrimes continue; 2041553Srgrimes 2051553Srgrimes case '\3': /* read df file */ 2061553Srgrimes size = 0; 2071553Srgrimes while (*cp >= '0' && *cp <= '9') 2081553Srgrimes size = size * 10 + (*cp++ - '0'); 2091553Srgrimes if (*cp++ != ' ') 2101553Srgrimes break; 2111553Srgrimes if (!chksize(size)) { 2121553Srgrimes (void) write(1, "\2", 1); 2131553Srgrimes continue; 2141553Srgrimes } 21527748Simp (void) strncpy(dfname, cp, sizeof(dfname) - 1); 21627748Simp dfname[sizeof(dfname) - 1] = '\0'; 21727635Simp if (strchr(dfname, '/')) 2181553Srgrimes frecverr("readjob: %s: illegal path name", 2191553Srgrimes dfname); 2201553Srgrimes (void) readfile(dfname, size); 2211553Srgrimes continue; 2221553Srgrimes } 2231553Srgrimes frecverr("protocol screwup: %s", line); 2241553Srgrimes } 2251553Srgrimes} 2261553Srgrimes 2271553Srgrimes/* 2281553Srgrimes * Read files send by lpd and copy them to the spooling directory. 2291553Srgrimes */ 2301553Srgrimesstatic int 2311553Srgrimesreadfile(file, size) 2321553Srgrimes char *file; 2331553Srgrimes int size; 2341553Srgrimes{ 2351553Srgrimes register char *cp; 2361553Srgrimes char buf[BUFSIZ]; 2371553Srgrimes register int i, j, amt; 2381553Srgrimes int fd, err; 2391553Srgrimes 2401553Srgrimes fd = open(file, O_CREAT|O_EXCL|O_WRONLY, FILMOD); 2411553Srgrimes if (fd < 0) 2421553Srgrimes frecverr("readfile: %s: illegal path name: %m", file); 2431553Srgrimes ack(); 2441553Srgrimes err = 0; 2451553Srgrimes for (i = 0; i < size; i += BUFSIZ) { 2461553Srgrimes amt = BUFSIZ; 2471553Srgrimes cp = buf; 2481553Srgrimes if (i + amt > size) 2491553Srgrimes amt = size - i; 2501553Srgrimes do { 2511553Srgrimes j = read(1, cp, amt); 2521553Srgrimes if (j <= 0) 25329780Scharnier frecverr("lost connection"); 2541553Srgrimes amt -= j; 2551553Srgrimes cp += j; 2561553Srgrimes } while (amt > 0); 2571553Srgrimes amt = BUFSIZ; 2581553Srgrimes if (i + amt > size) 2591553Srgrimes amt = size - i; 2601553Srgrimes if (write(fd, buf, amt) != amt) { 2611553Srgrimes err++; 2621553Srgrimes break; 2631553Srgrimes } 2641553Srgrimes } 2651553Srgrimes (void) close(fd); 2661553Srgrimes if (err) 2671553Srgrimes frecverr("%s: write error", file); 2681553Srgrimes if (noresponse()) { /* file sent had bad data in it */ 26930143Simp if (strchr(file, '/') == NULL) 27030143Simp (void) unlink(file); 2711553Srgrimes return(0); 2721553Srgrimes } 2731553Srgrimes ack(); 2741553Srgrimes return(1); 2751553Srgrimes} 2761553Srgrimes 2771553Srgrimesstatic int 2781553Srgrimesnoresponse() 2791553Srgrimes{ 2801553Srgrimes char resp; 2811553Srgrimes 2821553Srgrimes if (read(1, &resp, 1) != 1) 28329780Scharnier frecverr("lost connection"); 2841553Srgrimes if (resp == '\0') 2851553Srgrimes return(0); 2861553Srgrimes return(1); 2871553Srgrimes} 2881553Srgrimes 2891553Srgrimes/* 2901553Srgrimes * Check to see if there is enough space on the disk for size bytes. 2911553Srgrimes * 1 == OK, 0 == Not OK. 2921553Srgrimes */ 2931553Srgrimesstatic int 2941553Srgrimeschksize(size) 2951553Srgrimes int size; 2961553Srgrimes{ 2971553Srgrimes int spacefree; 2981553Srgrimes struct statfs sfb; 2991553Srgrimes 3001553Srgrimes if (statfs(".", &sfb) < 0) { 3011553Srgrimes syslog(LOG_ERR, "%s: %m", "statfs(\".\")"); 3021553Srgrimes return (1); 3031553Srgrimes } 3041553Srgrimes spacefree = sfb.f_bavail * (sfb.f_bsize / 512); 3051553Srgrimes size = (size + 511) / 512; 3061553Srgrimes if (minfree + size > spacefree) 3071553Srgrimes return(0); 3081553Srgrimes return(1); 3091553Srgrimes} 3101553Srgrimes 3111553Srgrimesstatic int 3121553Srgrimesread_number(fn) 3131553Srgrimes char *fn; 3141553Srgrimes{ 3151553Srgrimes char lin[80]; 3161553Srgrimes register FILE *fp; 3171553Srgrimes 3181553Srgrimes if ((fp = fopen(fn, "r")) == NULL) 3191553Srgrimes return (0); 3201553Srgrimes if (fgets(lin, 80, fp) == NULL) { 3211553Srgrimes fclose(fp); 3221553Srgrimes return (0); 3231553Srgrimes } 3241553Srgrimes fclose(fp); 3251553Srgrimes return (atoi(lin)); 3261553Srgrimes} 3271553Srgrimes 3281553Srgrimes/* 3291553Srgrimes * Remove all the files associated with the current job being transfered. 3301553Srgrimes */ 3311553Srgrimesstatic void 3321553Srgrimesrcleanup(signo) 3331553Srgrimes int signo; 3341553Srgrimes{ 33530143Simp if (tfname[0] && strchr(tfname, '/') == NULL) 3361553Srgrimes (void) unlink(tfname); 33730143Simp if (dfname[0] && strchr(dfname, '/') == NULL) { 3381553Srgrimes do { 3391553Srgrimes do 3401553Srgrimes (void) unlink(dfname); 3411553Srgrimes while (dfname[2]-- != 'A'); 3421553Srgrimes dfname[2] = 'z'; 3431553Srgrimes } while (dfname[0]-- != 'd'); 34430143Simp } 3451553Srgrimes dfname[0] = '\0'; 3461553Srgrimes} 3471553Srgrimes 34827757Simp#ifdef __STDC__ 3491553Srgrimes#include <stdarg.h> 3501553Srgrimes#else 3511553Srgrimes#include <varargs.h> 3521553Srgrimes#endif 3531553Srgrimes 3541553Srgrimesstatic void 35527757Simp#ifdef __STDC__ 3561553Srgrimesfrecverr(const char *msg, ...) 3571553Srgrimes#else 3581553Srgrimesfrecverr(msg, va_alist) 3591553Srgrimes char *msg; 3601553Srgrimes va_dcl 3611553Srgrimes#endif 3621553Srgrimes{ 3631553Srgrimes va_list ap; 36427757Simp#ifdef __STDC__ 3651553Srgrimes va_start(ap, msg); 3661553Srgrimes#else 3671553Srgrimes va_start(ap); 3681553Srgrimes#endif 3691553Srgrimes rcleanup(0); 3701553Srgrimes syslog(LOG_ERR, "%s", fromb); 3711553Srgrimes vsyslog(LOG_ERR, msg, ap); 3721553Srgrimes va_end(ap); 3731553Srgrimes putchar('\1'); /* return error code */ 3741553Srgrimes exit(1); 3751553Srgrimes} 376