recvjob.c revision 87375
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[] = 4650479Speter "$FreeBSD: head/usr.sbin/lpr/lpd/recvjob.c 87375 2001-12-05 02:07:20Z gad $"; 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> 6179739Sgad#include <errno.h> 621553Srgrimes#include <syslog.h> 631553Srgrimes#include <stdio.h> 641553Srgrimes#include <stdlib.h> 651553Srgrimes#include <string.h> 661553Srgrimes#include "lp.h" 671553Srgrimes#include "lp.local.h" 6879746Sgad#include "ctlinfo.h" 691553Srgrimes#include "extern.h" 701553Srgrimes#include "pathnames.h" 711553Srgrimes 7280171Sgad#define ack() (void) write(STDOUT_FILENO, sp, (size_t)1); 731553Srgrimes 7427748Simpstatic char dfname[NAME_MAX]; /* data files */ 751553Srgrimesstatic int minfree; /* keep at least minfree blocks available */ 7678146Sgadstatic const char *sp = ""; 7727748Simpstatic char tfname[NAME_MAX]; /* tmp copy of cf before linking */ 781553Srgrimes 7978146Sgadstatic int chksize(int _size); 8079739Sgadstatic void frecverr(const char *_msg, ...) __printf0like(1, 2); 8178146Sgadstatic int noresponse(void); 8278146Sgadstatic void rcleanup(int _signo); 8378146Sgadstatic int read_number(const char *_fn); 8480171Sgadstatic int readfile(struct printer *_pp, char *_file, size_t _size); 8578146Sgadstatic int readjob(struct printer *_pp); 861553Srgrimes 871553Srgrimes 881553Srgrimesvoid 8978146Sgadrecvjob(const char *printer) 901553Srgrimes{ 911553Srgrimes struct stat stb; 921553Srgrimes int status; 9331492Swollman struct printer myprinter, *pp = &myprinter; 941553Srgrimes 951553Srgrimes /* 961553Srgrimes * Perform lookup for printer name or abbreviation 971553Srgrimes */ 9832654Swollman init_printer(pp); 9931492Swollman status = getprintcap(printer, pp); 10031492Swollman switch (status) { 10131492Swollman case PCAPERR_OSERR: 1021553Srgrimes frecverr("cannot open printer description file"); 10331492Swollman break; 10431492Swollman case PCAPERR_NOTFOUND: 1051553Srgrimes frecverr("unknown printer %s", printer); 10631492Swollman break; 10731492Swollman case PCAPERR_TCLOOP: 10831492Swollman fatal(pp, "potential reference loop detected in printcap file"); 10931492Swollman default: 11031492Swollman break; 11131492Swollman } 11227748Simp 1131553Srgrimes (void) close(2); /* set up log file */ 11431492Swollman if (open(pp->log_file, O_WRONLY|O_APPEND, 0664) < 0) { 11531492Swollman syslog(LOG_ERR, "%s: %m", pp->log_file); 1161553Srgrimes (void) open(_PATH_DEVNULL, O_WRONLY); 1171553Srgrimes } 1181553Srgrimes 11931492Swollman if (chdir(pp->spool_dir) < 0) 12079739Sgad frecverr("%s: chdir(%s): %s", pp->printer, pp->spool_dir, 12179739Sgad strerror(errno)); 12231492Swollman if (stat(pp->lock_file, &stb) == 0) { 1231553Srgrimes if (stb.st_mode & 010) { 1241553Srgrimes /* queue is disabled */ 1251553Srgrimes putchar('\1'); /* return error code */ 1261553Srgrimes exit(1); 1271553Srgrimes } 12831492Swollman } else if (stat(pp->spool_dir, &stb) < 0) 12979739Sgad frecverr("%s: stat(%s): %s", pp->printer, pp->spool_dir, 13079739Sgad strerror(errno)); 1311553Srgrimes minfree = 2 * read_number("minfree"); /* scale KB to 512 blocks */ 1321553Srgrimes signal(SIGTERM, rcleanup); 1331553Srgrimes signal(SIGPIPE, rcleanup); 1341553Srgrimes 13531492Swollman if (readjob(pp)) 13631492Swollman printjob(pp); 1371553Srgrimes} 1381553Srgrimes 1391553Srgrimes/* 1401553Srgrimes * Read printer jobs sent by lpd and copy them to the spooling directory. 1411553Srgrimes * Return the number of jobs successfully transfered. 1421553Srgrimes */ 1431553Srgrimesstatic int 14478146Sgadreadjob(struct printer *pp) 1451553Srgrimes{ 14668253Sgad register int size; 14768735Sgad int cfcnt, dfcnt; 14880171Sgad char *cp, *clastp, *errmsg; 14968735Sgad char givenid[32], givenhost[MAXHOSTNAMELEN]; 1501553Srgrimes 1511553Srgrimes ack(); 15268253Sgad cfcnt = 0; 15368253Sgad dfcnt = 0; 1541553Srgrimes for (;;) { 1551553Srgrimes /* 1561553Srgrimes * Read a command to tell us what to do 1571553Srgrimes */ 1581553Srgrimes cp = line; 15980171Sgad clastp = line + sizeof(line) - 1; 1601553Srgrimes do { 16180171Sgad size = read(STDOUT_FILENO, cp, (size_t)1); 16280171Sgad if (size != (ssize_t)1) { 16380171Sgad if (size < (ssize_t)0) { 16429780Scharnier frecverr("%s: lost connection", 16531492Swollman pp->printer); 16668380Sgad /*NOTREACHED*/ 16768380Sgad } 16868253Sgad return (cfcnt); 1691553Srgrimes } 17080171Sgad } while ((*cp++ != '\n') && (cp <= clastp)); 17180171Sgad if (cp > clastp) { 17268380Sgad frecverr("%s: readjob overflow", pp->printer); 17368380Sgad /*NOTREACHED*/ 17468380Sgad } 1751553Srgrimes *--cp = '\0'; 1761553Srgrimes cp = line; 1771553Srgrimes switch (*cp++) { 1781553Srgrimes case '\1': /* cleanup because data sent was bad */ 1791553Srgrimes rcleanup(0); 1801553Srgrimes continue; 1811553Srgrimes 1821553Srgrimes case '\2': /* read cf file */ 1831553Srgrimes size = 0; 18468253Sgad dfcnt = 0; 1851553Srgrimes while (*cp >= '0' && *cp <= '9') 1861553Srgrimes size = size * 10 + (*cp++ - '0'); 1871553Srgrimes if (*cp++ != ' ') 1881553Srgrimes break; 1891553Srgrimes /* 1901553Srgrimes * host name has been authenticated, we use our 1911553Srgrimes * view of the host name since we may be passed 1921553Srgrimes * something different than what gethostbyaddr() 1931553Srgrimes * returns 1941553Srgrimes */ 19580133Sgad strlcpy(cp + 6, from_host, sizeof(line) 19680133Sgad + (size_t)(line - cp - 6)); 19787375Sgad if (strchr(cp, '/')) { 19887375Sgad frecverr("readjob: %s: illegal path name", cp); 19987375Sgad /*NOTREACHED*/ 20087375Sgad } 20180133Sgad strlcpy(tfname, cp, sizeof(tfname)); 20227748Simp tfname[sizeof (tfname) - 1] = '\0'; 2031553Srgrimes tfname[0] = 't'; 2041553Srgrimes if (!chksize(size)) { 20580171Sgad (void) write(STDOUT_FILENO, "\2", (size_t)1); 2061553Srgrimes continue; 2071553Srgrimes } 20880171Sgad if (!readfile(pp, tfname, (size_t)size)) { 2091553Srgrimes rcleanup(0); 2101553Srgrimes continue; 2111553Srgrimes } 21279746Sgad errmsg = ctl_renametf(pp->printer, tfname); 2131553Srgrimes tfname[0] = '\0'; 21479746Sgad if (errmsg != NULL) { 21579746Sgad frecverr("%s: %s", pp->printer, errmsg); 21679746Sgad /*NOTREACHED*/ 21779746Sgad } 21868253Sgad cfcnt++; 2191553Srgrimes continue; 2201553Srgrimes 2211553Srgrimes case '\3': /* read df file */ 22268253Sgad *givenid = '\0'; 22368253Sgad *givenhost = '\0'; 2241553Srgrimes size = 0; 2251553Srgrimes while (*cp >= '0' && *cp <= '9') 2261553Srgrimes size = size * 10 + (*cp++ - '0'); 2271553Srgrimes if (*cp++ != ' ') 2281553Srgrimes break; 22987375Sgad if (strchr(cp, '/')) { 23087375Sgad frecverr("readjob: %s: illegal path name", cp); 23187375Sgad /*NOTREACHED*/ 23287375Sgad } 2331553Srgrimes if (!chksize(size)) { 23480171Sgad (void) write(STDOUT_FILENO, "\2", (size_t)1); 2351553Srgrimes continue; 2361553Srgrimes } 23780133Sgad strlcpy(dfname, cp, sizeof(dfname)); 23868253Sgad dfcnt++; 23968253Sgad trstat_init(pp, dfname, dfcnt); 24080171Sgad (void) readfile(pp, dfname, (size_t)size); 24180171Sgad trstat_write(pp, TR_RECVING, (size_t)size, givenid, 24280171Sgad from_host, givenhost); 2431553Srgrimes continue; 2441553Srgrimes } 2451553Srgrimes frecverr("protocol screwup: %s", line); 24668380Sgad /*NOTREACHED*/ 2471553Srgrimes } 2481553Srgrimes} 2491553Srgrimes 2501553Srgrimes/* 2511553Srgrimes * Read files send by lpd and copy them to the spooling directory. 2521553Srgrimes */ 2531553Srgrimesstatic int 25480171Sgadreadfile(struct printer *pp, char *file, size_t size) 2551553Srgrimes{ 2561553Srgrimes register char *cp; 2571553Srgrimes char buf[BUFSIZ]; 25880171Sgad size_t amt, i; 25980171Sgad int err, fd, j; 2601553Srgrimes 2611553Srgrimes fd = open(file, O_CREAT|O_EXCL|O_WRONLY, FILMOD); 26268380Sgad if (fd < 0) { 26379739Sgad frecverr("%s: readfile: error on open(%s): %s", 26479739Sgad pp->printer, file, strerror(errno)); 26568380Sgad /*NOTREACHED*/ 26668380Sgad } 2671553Srgrimes ack(); 2681553Srgrimes err = 0; 2691553Srgrimes for (i = 0; i < size; i += BUFSIZ) { 2701553Srgrimes amt = BUFSIZ; 2711553Srgrimes cp = buf; 2721553Srgrimes if (i + amt > size) 2731553Srgrimes amt = size - i; 2741553Srgrimes do { 27580113Sgad j = read(STDOUT_FILENO, cp, amt); 27668380Sgad if (j <= 0) { 27768380Sgad frecverr("%s: lost connection", pp->printer); 27868380Sgad /*NOTREACHED*/ 27968380Sgad } 2801553Srgrimes amt -= j; 2811553Srgrimes cp += j; 2821553Srgrimes } while (amt > 0); 2831553Srgrimes amt = BUFSIZ; 2841553Srgrimes if (i + amt > size) 2851553Srgrimes amt = size - i; 28680171Sgad if (write(fd, buf, amt) != (ssize_t)amt) { 2871553Srgrimes err++; 2881553Srgrimes break; 2891553Srgrimes } 2901553Srgrimes } 2911553Srgrimes (void) close(fd); 29268380Sgad if (err) { 29368380Sgad frecverr("%s: write error on close(%s)", pp->printer, file); 29468380Sgad /*NOTREACHED*/ 29568380Sgad } 2961553Srgrimes if (noresponse()) { /* file sent had bad data in it */ 29730143Simp if (strchr(file, '/') == NULL) 29830143Simp (void) unlink(file); 29968380Sgad return (0); 3001553Srgrimes } 3011553Srgrimes ack(); 30268380Sgad return (1); 3031553Srgrimes} 3041553Srgrimes 3051553Srgrimesstatic int 30678146Sgadnoresponse(void) 3071553Srgrimes{ 3081553Srgrimes char resp; 3091553Srgrimes 31080171Sgad if (read(STDOUT_FILENO, &resp, (size_t)1) != 1) { 31168380Sgad frecverr("lost connection in noresponse()"); 31268380Sgad /*NOTREACHED*/ 31368380Sgad } 3141553Srgrimes if (resp == '\0') 3151553Srgrimes return(0); 3161553Srgrimes return(1); 3171553Srgrimes} 3181553Srgrimes 3191553Srgrimes/* 3201553Srgrimes * Check to see if there is enough space on the disk for size bytes. 3211553Srgrimes * 1 == OK, 0 == Not OK. 3221553Srgrimes */ 3231553Srgrimesstatic int 32478146Sgadchksize(int size) 3251553Srgrimes{ 3261553Srgrimes int spacefree; 3271553Srgrimes struct statfs sfb; 3281553Srgrimes 3291553Srgrimes if (statfs(".", &sfb) < 0) { 3301553Srgrimes syslog(LOG_ERR, "%s: %m", "statfs(\".\")"); 3311553Srgrimes return (1); 3321553Srgrimes } 3331553Srgrimes spacefree = sfb.f_bavail * (sfb.f_bsize / 512); 3341553Srgrimes size = (size + 511) / 512; 3351553Srgrimes if (minfree + size > spacefree) 3361553Srgrimes return(0); 3371553Srgrimes return(1); 3381553Srgrimes} 3391553Srgrimes 3401553Srgrimesstatic int 34178146Sgadread_number(const char *fn) 3421553Srgrimes{ 3431553Srgrimes char lin[80]; 3441553Srgrimes register FILE *fp; 3451553Srgrimes 3461553Srgrimes if ((fp = fopen(fn, "r")) == NULL) 3471553Srgrimes return (0); 3481553Srgrimes if (fgets(lin, 80, fp) == NULL) { 3491553Srgrimes fclose(fp); 3501553Srgrimes return (0); 3511553Srgrimes } 3521553Srgrimes fclose(fp); 3531553Srgrimes return (atoi(lin)); 3541553Srgrimes} 3551553Srgrimes 3561553Srgrimes/* 3571553Srgrimes * Remove all the files associated with the current job being transfered. 3581553Srgrimes */ 3591553Srgrimesstatic void 36078146Sgadrcleanup(int signo __unused) 3611553Srgrimes{ 36230143Simp if (tfname[0] && strchr(tfname, '/') == NULL) 3631553Srgrimes (void) unlink(tfname); 36430143Simp if (dfname[0] && strchr(dfname, '/') == NULL) { 3651553Srgrimes do { 3661553Srgrimes do 3671553Srgrimes (void) unlink(dfname); 3681553Srgrimes while (dfname[2]-- != 'A'); 3691553Srgrimes dfname[2] = 'z'; 3701553Srgrimes } while (dfname[0]-- != 'd'); 37130143Simp } 3721553Srgrimes dfname[0] = '\0'; 3731553Srgrimes} 3741553Srgrimes 37527757Simp#ifdef __STDC__ 3761553Srgrimes#include <stdarg.h> 3771553Srgrimes#else 3781553Srgrimes#include <varargs.h> 3791553Srgrimes#endif 3801553Srgrimes 3811553Srgrimesstatic void 38227757Simp#ifdef __STDC__ 3831553Srgrimesfrecverr(const char *msg, ...) 3841553Srgrimes#else 3851553Srgrimesfrecverr(msg, va_alist) 3861553Srgrimes char *msg; 3871553Srgrimes va_dcl 3881553Srgrimes#endif 3891553Srgrimes{ 3901553Srgrimes va_list ap; 39127757Simp#ifdef __STDC__ 3921553Srgrimes va_start(ap, msg); 3931553Srgrimes#else 3941553Srgrimes va_start(ap); 3951553Srgrimes#endif 39678300Sgad syslog(LOG_ERR, "Error receiving job from %s:", from_host); 3971553Srgrimes vsyslog(LOG_ERR, msg, ap); 3981553Srgrimes va_end(ap); 39968340Sgad /* 40068735Sgad * rcleanup is not called until AFTER logging the error message, 40168735Sgad * because rcleanup will zap some variables which may have been 40268735Sgad * supplied as parameters for that msg... 40368340Sgad */ 40468340Sgad rcleanup(0); 40568340Sgad /* 40668340Sgad * Add a minimal delay before returning the final error code to 40768340Sgad * the sending host. This just in case that machine responds 40868340Sgad * this error by INSTANTLY retrying (and instantly re-failing...). 40968340Sgad * It would be stupid of the sending host to do that, but if there 41068340Sgad * was a broken implementation which did it, the result might be 41168340Sgad * obscure performance problems and a flood of syslog messages on 41268340Sgad * the receiving host. 41368340Sgad */ 41468340Sgad sleep(2); /* a paranoid throttling measure */ 4151553Srgrimes putchar('\1'); /* return error code */ 4161553Srgrimes exit(1); 4171553Srgrimes} 418