recvjob.c revision 182599
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 4129780Scharnier#if 0 42117587Sgad#ifndef lint 4315648Sjoergstatic char sccsid[] = "@(#)recvjob.c 8.2 (Berkeley) 4/27/95"; 44117587Sgad#endif /* not lint */ 4529780Scharnier#endif 461553Srgrimes 47117554Sgad#include "lp.cdefs.h" /* A cross-platform version of <sys/cdefs.h> */ 48117554Sgad__FBSDID("$FreeBSD: head/usr.sbin/lpr/lpd/recvjob.c 182599 2008-09-01 12:32:40Z ticso $"); 49117554Sgad 501553Srgrimes/* 511553Srgrimes * Receive printer jobs from the network, queue them and 521553Srgrimes * start the printer daemon. 531553Srgrimes */ 541553Srgrimes#include <sys/param.h> 551553Srgrimes#include <sys/mount.h> 561553Srgrimes#include <sys/stat.h> 571553Srgrimes 581553Srgrimes#include <unistd.h> 591553Srgrimes#include <signal.h> 601553Srgrimes#include <fcntl.h> 611553Srgrimes#include <dirent.h> 6279739Sgad#include <errno.h> 631553Srgrimes#include <syslog.h> 641553Srgrimes#include <stdio.h> 651553Srgrimes#include <stdlib.h> 661553Srgrimes#include <string.h> 671553Srgrimes#include "lp.h" 681553Srgrimes#include "lp.local.h" 6979746Sgad#include "ctlinfo.h" 701553Srgrimes#include "extern.h" 711553Srgrimes#include "pathnames.h" 721553Srgrimes 7380171Sgad#define ack() (void) write(STDOUT_FILENO, sp, (size_t)1); 741553Srgrimes 75119192Sgad/* 76119192Sgad * The buffer size to use when reading/writing spool files. 77119192Sgad */ 78119192Sgad#define SPL_BUFSIZ BUFSIZ 79119192Sgad 8027748Simpstatic char dfname[NAME_MAX]; /* data files */ 811553Srgrimesstatic int minfree; /* keep at least minfree blocks available */ 8278146Sgadstatic const char *sp = ""; 8327748Simpstatic char tfname[NAME_MAX]; /* tmp copy of cf before linking */ 841553Srgrimes 8578146Sgadstatic int chksize(int _size); 8679739Sgadstatic void frecverr(const char *_msg, ...) __printf0like(1, 2); 8778146Sgadstatic int noresponse(void); 8878146Sgadstatic void rcleanup(int _signo); 8978146Sgadstatic int read_number(const char *_fn); 9080171Sgadstatic int readfile(struct printer *_pp, char *_file, size_t _size); 9178146Sgadstatic int readjob(struct printer *_pp); 921553Srgrimes 931553Srgrimes 941553Srgrimesvoid 9578146Sgadrecvjob(const char *printer) 961553Srgrimes{ 971553Srgrimes struct stat stb; 981553Srgrimes int status; 9931492Swollman struct printer myprinter, *pp = &myprinter; 1001553Srgrimes 1011553Srgrimes /* 1021553Srgrimes * Perform lookup for printer name or abbreviation 1031553Srgrimes */ 10432654Swollman init_printer(pp); 10531492Swollman status = getprintcap(printer, pp); 10631492Swollman switch (status) { 10731492Swollman case PCAPERR_OSERR: 1081553Srgrimes frecverr("cannot open printer description file"); 10931492Swollman break; 11031492Swollman case PCAPERR_NOTFOUND: 1111553Srgrimes frecverr("unknown printer %s", printer); 11231492Swollman break; 11331492Swollman case PCAPERR_TCLOOP: 11431492Swollman fatal(pp, "potential reference loop detected in printcap file"); 11531492Swollman default: 11631492Swollman break; 11731492Swollman } 11827748Simp 119118881Sgad (void) close(STDERR_FILENO); /* set up log file */ 12031492Swollman if (open(pp->log_file, O_WRONLY|O_APPEND, 0664) < 0) { 12131492Swollman syslog(LOG_ERR, "%s: %m", pp->log_file); 1221553Srgrimes (void) open(_PATH_DEVNULL, O_WRONLY); 1231553Srgrimes } 1241553Srgrimes 12531492Swollman if (chdir(pp->spool_dir) < 0) 12679739Sgad frecverr("%s: chdir(%s): %s", pp->printer, pp->spool_dir, 12779739Sgad strerror(errno)); 12831492Swollman if (stat(pp->lock_file, &stb) == 0) { 1291553Srgrimes if (stb.st_mode & 010) { 1301553Srgrimes /* queue is disabled */ 1311553Srgrimes putchar('\1'); /* return error code */ 1321553Srgrimes exit(1); 1331553Srgrimes } 13431492Swollman } else if (stat(pp->spool_dir, &stb) < 0) 13579739Sgad frecverr("%s: stat(%s): %s", pp->printer, pp->spool_dir, 13679739Sgad strerror(errno)); 1371553Srgrimes minfree = 2 * read_number("minfree"); /* scale KB to 512 blocks */ 1381553Srgrimes signal(SIGTERM, rcleanup); 1391553Srgrimes signal(SIGPIPE, rcleanup); 1401553Srgrimes 14131492Swollman if (readjob(pp)) 14231492Swollman printjob(pp); 1431553Srgrimes} 1441553Srgrimes 1451553Srgrimes/* 1461553Srgrimes * Read printer jobs sent by lpd and copy them to the spooling directory. 1471553Srgrimes * Return the number of jobs successfully transfered. 1481553Srgrimes */ 1491553Srgrimesstatic int 15078146Sgadreadjob(struct printer *pp) 1511553Srgrimes{ 15268253Sgad register int size; 15368735Sgad int cfcnt, dfcnt; 15480171Sgad char *cp, *clastp, *errmsg; 15568735Sgad char givenid[32], givenhost[MAXHOSTNAMELEN]; 1561553Srgrimes 1571553Srgrimes ack(); 15868253Sgad cfcnt = 0; 15968253Sgad dfcnt = 0; 1601553Srgrimes for (;;) { 1611553Srgrimes /* 1621553Srgrimes * Read a command to tell us what to do 1631553Srgrimes */ 1641553Srgrimes cp = line; 16580171Sgad clastp = line + sizeof(line) - 1; 1661553Srgrimes do { 16780171Sgad size = read(STDOUT_FILENO, cp, (size_t)1); 16880171Sgad if (size != (ssize_t)1) { 16980171Sgad if (size < (ssize_t)0) { 17029780Scharnier frecverr("%s: lost connection", 17131492Swollman pp->printer); 17268380Sgad /*NOTREACHED*/ 17368380Sgad } 17468253Sgad return (cfcnt); 1751553Srgrimes } 17680171Sgad } while ((*cp++ != '\n') && (cp <= clastp)); 17780171Sgad if (cp > clastp) { 17868380Sgad frecverr("%s: readjob overflow", pp->printer); 17968380Sgad /*NOTREACHED*/ 18068380Sgad } 1811553Srgrimes *--cp = '\0'; 1821553Srgrimes cp = line; 1831553Srgrimes switch (*cp++) { 1841553Srgrimes case '\1': /* cleanup because data sent was bad */ 1851553Srgrimes rcleanup(0); 1861553Srgrimes continue; 1871553Srgrimes 1881553Srgrimes case '\2': /* read cf file */ 1891553Srgrimes size = 0; 19068253Sgad dfcnt = 0; 1911553Srgrimes while (*cp >= '0' && *cp <= '9') 1921553Srgrimes size = size * 10 + (*cp++ - '0'); 1931553Srgrimes if (*cp++ != ' ') 1941553Srgrimes break; 1951553Srgrimes /* 1961553Srgrimes * host name has been authenticated, we use our 1971553Srgrimes * view of the host name since we may be passed 1981553Srgrimes * something different than what gethostbyaddr() 1991553Srgrimes * returns 2001553Srgrimes */ 20180133Sgad strlcpy(cp + 6, from_host, sizeof(line) 20280133Sgad + (size_t)(line - cp - 6)); 20387375Sgad if (strchr(cp, '/')) { 20487375Sgad frecverr("readjob: %s: illegal path name", cp); 20587375Sgad /*NOTREACHED*/ 20687375Sgad } 20780133Sgad strlcpy(tfname, cp, sizeof(tfname)); 20827748Simp tfname[sizeof (tfname) - 1] = '\0'; 2091553Srgrimes tfname[0] = 't'; 2101553Srgrimes if (!chksize(size)) { 21180171Sgad (void) write(STDOUT_FILENO, "\2", (size_t)1); 2121553Srgrimes continue; 2131553Srgrimes } 21480171Sgad if (!readfile(pp, tfname, (size_t)size)) { 2151553Srgrimes rcleanup(0); 2161553Srgrimes continue; 2171553Srgrimes } 21879746Sgad errmsg = ctl_renametf(pp->printer, tfname); 2191553Srgrimes tfname[0] = '\0'; 22079746Sgad if (errmsg != NULL) { 22179746Sgad frecverr("%s: %s", pp->printer, errmsg); 22279746Sgad /*NOTREACHED*/ 22379746Sgad } 22468253Sgad cfcnt++; 2251553Srgrimes continue; 2261553Srgrimes 2271553Srgrimes case '\3': /* read df file */ 22868253Sgad *givenid = '\0'; 22968253Sgad *givenhost = '\0'; 2301553Srgrimes size = 0; 2311553Srgrimes while (*cp >= '0' && *cp <= '9') 2321553Srgrimes size = size * 10 + (*cp++ - '0'); 2331553Srgrimes if (*cp++ != ' ') 2341553Srgrimes break; 23587375Sgad if (strchr(cp, '/')) { 23687375Sgad frecverr("readjob: %s: illegal path name", cp); 23787375Sgad /*NOTREACHED*/ 23887375Sgad } 2391553Srgrimes if (!chksize(size)) { 24080171Sgad (void) write(STDOUT_FILENO, "\2", (size_t)1); 2411553Srgrimes continue; 2421553Srgrimes } 24380133Sgad strlcpy(dfname, cp, sizeof(dfname)); 24468253Sgad dfcnt++; 24568253Sgad trstat_init(pp, dfname, dfcnt); 24680171Sgad (void) readfile(pp, dfname, (size_t)size); 24780171Sgad trstat_write(pp, TR_RECVING, (size_t)size, givenid, 24880171Sgad from_host, givenhost); 2491553Srgrimes continue; 2501553Srgrimes } 2511553Srgrimes frecverr("protocol screwup: %s", line); 25268380Sgad /*NOTREACHED*/ 2531553Srgrimes } 2541553Srgrimes} 2551553Srgrimes 2561553Srgrimes/* 2571553Srgrimes * Read files send by lpd and copy them to the spooling directory. 2581553Srgrimes */ 2591553Srgrimesstatic int 26080171Sgadreadfile(struct printer *pp, char *file, size_t size) 2611553Srgrimes{ 2621553Srgrimes register char *cp; 263119192Sgad char buf[SPL_BUFSIZ]; 26480171Sgad size_t amt, i; 26580171Sgad int err, fd, j; 2661553Srgrimes 2671553Srgrimes fd = open(file, O_CREAT|O_EXCL|O_WRONLY, FILMOD); 26868380Sgad if (fd < 0) { 26979739Sgad frecverr("%s: readfile: error on open(%s): %s", 27079739Sgad pp->printer, file, strerror(errno)); 27168380Sgad /*NOTREACHED*/ 27268380Sgad } 2731553Srgrimes ack(); 2741553Srgrimes err = 0; 275119192Sgad for (i = 0; i < size; i += SPL_BUFSIZ) { 276119192Sgad amt = SPL_BUFSIZ; 2771553Srgrimes cp = buf; 2781553Srgrimes if (i + amt > size) 2791553Srgrimes amt = size - i; 2801553Srgrimes do { 28180113Sgad j = read(STDOUT_FILENO, cp, amt); 28268380Sgad if (j <= 0) { 28368380Sgad frecverr("%s: lost connection", pp->printer); 28468380Sgad /*NOTREACHED*/ 28568380Sgad } 2861553Srgrimes amt -= j; 2871553Srgrimes cp += j; 2881553Srgrimes } while (amt > 0); 289119192Sgad amt = SPL_BUFSIZ; 2901553Srgrimes if (i + amt > size) 2911553Srgrimes amt = size - i; 29280171Sgad if (write(fd, buf, amt) != (ssize_t)amt) { 2931553Srgrimes err++; 2941553Srgrimes break; 2951553Srgrimes } 2961553Srgrimes } 2971553Srgrimes (void) close(fd); 29868380Sgad if (err) { 29968380Sgad frecverr("%s: write error on close(%s)", pp->printer, file); 30068380Sgad /*NOTREACHED*/ 30168380Sgad } 3021553Srgrimes if (noresponse()) { /* file sent had bad data in it */ 30330143Simp if (strchr(file, '/') == NULL) 30430143Simp (void) unlink(file); 30568380Sgad return (0); 3061553Srgrimes } 3071553Srgrimes ack(); 30868380Sgad return (1); 3091553Srgrimes} 3101553Srgrimes 3111553Srgrimesstatic int 31278146Sgadnoresponse(void) 3131553Srgrimes{ 3141553Srgrimes char resp; 3151553Srgrimes 31680171Sgad if (read(STDOUT_FILENO, &resp, (size_t)1) != 1) { 31768380Sgad frecverr("lost connection in noresponse()"); 31868380Sgad /*NOTREACHED*/ 31968380Sgad } 3201553Srgrimes if (resp == '\0') 3211553Srgrimes return(0); 3221553Srgrimes return(1); 3231553Srgrimes} 3241553Srgrimes 3251553Srgrimes/* 3261553Srgrimes * Check to see if there is enough space on the disk for size bytes. 3271553Srgrimes * 1 == OK, 0 == Not OK. 3281553Srgrimes */ 3291553Srgrimesstatic int 33078146Sgadchksize(int size) 3311553Srgrimes{ 332182599Sticso int64_t spacefree; 3331553Srgrimes struct statfs sfb; 3341553Srgrimes 3351553Srgrimes if (statfs(".", &sfb) < 0) { 3361553Srgrimes syslog(LOG_ERR, "%s: %m", "statfs(\".\")"); 3371553Srgrimes return (1); 3381553Srgrimes } 3391553Srgrimes spacefree = sfb.f_bavail * (sfb.f_bsize / 512); 3401553Srgrimes size = (size + 511) / 512; 3411553Srgrimes if (minfree + size > spacefree) 3421553Srgrimes return(0); 3431553Srgrimes return(1); 3441553Srgrimes} 3451553Srgrimes 3461553Srgrimesstatic int 34778146Sgadread_number(const char *fn) 3481553Srgrimes{ 3491553Srgrimes char lin[80]; 3501553Srgrimes register FILE *fp; 3511553Srgrimes 3521553Srgrimes if ((fp = fopen(fn, "r")) == NULL) 3531553Srgrimes return (0); 354167260Skevlo if (fgets(lin, sizeof(lin), fp) == NULL) { 3551553Srgrimes fclose(fp); 3561553Srgrimes return (0); 3571553Srgrimes } 3581553Srgrimes fclose(fp); 3591553Srgrimes return (atoi(lin)); 3601553Srgrimes} 3611553Srgrimes 3621553Srgrimes/* 3631553Srgrimes * Remove all the files associated with the current job being transfered. 3641553Srgrimes */ 3651553Srgrimesstatic void 36678146Sgadrcleanup(int signo __unused) 3671553Srgrimes{ 36830143Simp if (tfname[0] && strchr(tfname, '/') == NULL) 3691553Srgrimes (void) unlink(tfname); 37030143Simp if (dfname[0] && strchr(dfname, '/') == NULL) { 3711553Srgrimes do { 3721553Srgrimes do 3731553Srgrimes (void) unlink(dfname); 3741553Srgrimes while (dfname[2]-- != 'A'); 3751553Srgrimes dfname[2] = 'z'; 3761553Srgrimes } while (dfname[0]-- != 'd'); 37730143Simp } 3781553Srgrimes dfname[0] = '\0'; 3791553Srgrimes} 3801553Srgrimes 3811553Srgrimes#include <stdarg.h> 3821553Srgrimes 3831553Srgrimesstatic void 3841553Srgrimesfrecverr(const char *msg, ...) 3851553Srgrimes{ 3861553Srgrimes va_list ap; 3871553Srgrimes va_start(ap, msg); 38878300Sgad syslog(LOG_ERR, "Error receiving job from %s:", from_host); 3891553Srgrimes vsyslog(LOG_ERR, msg, ap); 3901553Srgrimes va_end(ap); 39168340Sgad /* 39268735Sgad * rcleanup is not called until AFTER logging the error message, 39368735Sgad * because rcleanup will zap some variables which may have been 39468735Sgad * supplied as parameters for that msg... 39568340Sgad */ 39668340Sgad rcleanup(0); 39768340Sgad /* 39868340Sgad * Add a minimal delay before returning the final error code to 39968340Sgad * the sending host. This just in case that machine responds 40068340Sgad * this error by INSTANTLY retrying (and instantly re-failing...). 40168340Sgad * It would be stupid of the sending host to do that, but if there 40268340Sgad * was a broken implementation which did it, the result might be 40368340Sgad * obscure performance problems and a flood of syslog messages on 40468340Sgad * the receiving host. 40568340Sgad */ 40668340Sgad sleep(2); /* a paranoid throttling measure */ 4071553Srgrimes putchar('\1'); /* return error code */ 4081553Srgrimes exit(1); 4091553Srgrimes} 410