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 * 4. Neither the name of the University nor the names of its contributors 151553Srgrimes * may be used to endorse or promote products derived from this software 161553Srgrimes * without specific prior written permission. 171553Srgrimes * 181553Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 191553Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 201553Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 211553Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 221553Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 231553Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 241553Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 251553Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 261553Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 271553Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 281553Srgrimes * SUCH DAMAGE. 291553Srgrimes */ 301553Srgrimes 311553Srgrimes#ifndef lint 3229780Scharnierstatic const char copyright[] = 331553Srgrimes"@(#) Copyright (c) 1983, 1993\n\ 341553Srgrimes The Regents of the University of California. All rights reserved.\n"; 351553Srgrimes#endif /* not lint */ 361553Srgrimes 3729780Scharnier#if 0 38117587Sgad#ifndef lint 3915648Sjoergstatic char sccsid[] = "@(#)recvjob.c 8.2 (Berkeley) 4/27/95"; 40117587Sgad#endif /* not lint */ 4129780Scharnier#endif 421553Srgrimes 43117554Sgad#include "lp.cdefs.h" /* A cross-platform version of <sys/cdefs.h> */ 44117554Sgad__FBSDID("$FreeBSD$"); 45117554Sgad 461553Srgrimes/* 471553Srgrimes * Receive printer jobs from the network, queue them and 481553Srgrimes * start the printer daemon. 491553Srgrimes */ 501553Srgrimes#include <sys/param.h> 511553Srgrimes#include <sys/mount.h> 521553Srgrimes#include <sys/stat.h> 531553Srgrimes 541553Srgrimes#include <unistd.h> 551553Srgrimes#include <signal.h> 561553Srgrimes#include <fcntl.h> 571553Srgrimes#include <dirent.h> 5879739Sgad#include <errno.h> 591553Srgrimes#include <syslog.h> 601553Srgrimes#include <stdio.h> 611553Srgrimes#include <stdlib.h> 621553Srgrimes#include <string.h> 631553Srgrimes#include "lp.h" 641553Srgrimes#include "lp.local.h" 6579746Sgad#include "ctlinfo.h" 661553Srgrimes#include "extern.h" 671553Srgrimes#include "pathnames.h" 681553Srgrimes 6980171Sgad#define ack() (void) write(STDOUT_FILENO, sp, (size_t)1); 701553Srgrimes 71119192Sgad/* 72119192Sgad * The buffer size to use when reading/writing spool files. 73119192Sgad */ 74119192Sgad#define SPL_BUFSIZ BUFSIZ 75119192Sgad 7627748Simpstatic char dfname[NAME_MAX]; /* data files */ 771553Srgrimesstatic int minfree; /* keep at least minfree blocks available */ 7878146Sgadstatic const char *sp = ""; 7927748Simpstatic char tfname[NAME_MAX]; /* tmp copy of cf before linking */ 801553Srgrimes 8178146Sgadstatic int chksize(int _size); 8279739Sgadstatic void frecverr(const char *_msg, ...) __printf0like(1, 2); 8378146Sgadstatic int noresponse(void); 8478146Sgadstatic void rcleanup(int _signo); 8578146Sgadstatic int read_number(const char *_fn); 8680171Sgadstatic int readfile(struct printer *_pp, char *_file, size_t _size); 8778146Sgadstatic int readjob(struct printer *_pp); 881553Srgrimes 891553Srgrimes 901553Srgrimesvoid 9178146Sgadrecvjob(const char *printer) 921553Srgrimes{ 931553Srgrimes struct stat stb; 941553Srgrimes int status; 9531492Swollman struct printer myprinter, *pp = &myprinter; 961553Srgrimes 971553Srgrimes /* 981553Srgrimes * Perform lookup for printer name or abbreviation 991553Srgrimes */ 10032654Swollman init_printer(pp); 10131492Swollman status = getprintcap(printer, pp); 10231492Swollman switch (status) { 10331492Swollman case PCAPERR_OSERR: 1041553Srgrimes frecverr("cannot open printer description file"); 10531492Swollman break; 10631492Swollman case PCAPERR_NOTFOUND: 1071553Srgrimes frecverr("unknown printer %s", printer); 10831492Swollman break; 10931492Swollman case PCAPERR_TCLOOP: 11031492Swollman fatal(pp, "potential reference loop detected in printcap file"); 11131492Swollman default: 11231492Swollman break; 11331492Swollman } 11427748Simp 115118881Sgad (void) close(STDERR_FILENO); /* set up log file */ 11631492Swollman if (open(pp->log_file, O_WRONLY|O_APPEND, 0664) < 0) { 11731492Swollman syslog(LOG_ERR, "%s: %m", pp->log_file); 1181553Srgrimes (void) open(_PATH_DEVNULL, O_WRONLY); 1191553Srgrimes } 1201553Srgrimes 12131492Swollman if (chdir(pp->spool_dir) < 0) 12279739Sgad frecverr("%s: chdir(%s): %s", pp->printer, pp->spool_dir, 12379739Sgad strerror(errno)); 12431492Swollman if (stat(pp->lock_file, &stb) == 0) { 1251553Srgrimes if (stb.st_mode & 010) { 1261553Srgrimes /* queue is disabled */ 1271553Srgrimes putchar('\1'); /* return error code */ 1281553Srgrimes exit(1); 1291553Srgrimes } 13031492Swollman } else if (stat(pp->spool_dir, &stb) < 0) 13179739Sgad frecverr("%s: stat(%s): %s", pp->printer, pp->spool_dir, 13279739Sgad strerror(errno)); 1331553Srgrimes minfree = 2 * read_number("minfree"); /* scale KB to 512 blocks */ 1341553Srgrimes signal(SIGTERM, rcleanup); 1351553Srgrimes signal(SIGPIPE, rcleanup); 1361553Srgrimes 13731492Swollman if (readjob(pp)) 13831492Swollman printjob(pp); 1391553Srgrimes} 1401553Srgrimes 1411553Srgrimes/* 1421553Srgrimes * Read printer jobs sent by lpd and copy them to the spooling directory. 1431553Srgrimes * Return the number of jobs successfully transfered. 1441553Srgrimes */ 1451553Srgrimesstatic int 14678146Sgadreadjob(struct printer *pp) 1471553Srgrimes{ 14868253Sgad register int size; 14968735Sgad int cfcnt, dfcnt; 15080171Sgad char *cp, *clastp, *errmsg; 15168735Sgad char givenid[32], givenhost[MAXHOSTNAMELEN]; 1521553Srgrimes 1531553Srgrimes ack(); 15468253Sgad cfcnt = 0; 15568253Sgad dfcnt = 0; 1561553Srgrimes for (;;) { 1571553Srgrimes /* 1581553Srgrimes * Read a command to tell us what to do 1591553Srgrimes */ 1601553Srgrimes cp = line; 16180171Sgad clastp = line + sizeof(line) - 1; 1621553Srgrimes do { 16380171Sgad size = read(STDOUT_FILENO, cp, (size_t)1); 16480171Sgad if (size != (ssize_t)1) { 16580171Sgad if (size < (ssize_t)0) { 16629780Scharnier frecverr("%s: lost connection", 16731492Swollman pp->printer); 16868380Sgad /*NOTREACHED*/ 16968380Sgad } 17068253Sgad return (cfcnt); 1711553Srgrimes } 17280171Sgad } while ((*cp++ != '\n') && (cp <= clastp)); 17380171Sgad if (cp > clastp) { 17468380Sgad frecverr("%s: readjob overflow", pp->printer); 17568380Sgad /*NOTREACHED*/ 17668380Sgad } 1771553Srgrimes *--cp = '\0'; 1781553Srgrimes cp = line; 1791553Srgrimes switch (*cp++) { 1801553Srgrimes case '\1': /* cleanup because data sent was bad */ 1811553Srgrimes rcleanup(0); 1821553Srgrimes continue; 1831553Srgrimes 1841553Srgrimes case '\2': /* read cf file */ 1851553Srgrimes size = 0; 18668253Sgad dfcnt = 0; 1871553Srgrimes while (*cp >= '0' && *cp <= '9') 1881553Srgrimes size = size * 10 + (*cp++ - '0'); 1891553Srgrimes if (*cp++ != ' ') 1901553Srgrimes break; 1911553Srgrimes /* 1921553Srgrimes * host name has been authenticated, we use our 1931553Srgrimes * view of the host name since we may be passed 1941553Srgrimes * something different than what gethostbyaddr() 1951553Srgrimes * returns 1961553Srgrimes */ 19780133Sgad strlcpy(cp + 6, from_host, sizeof(line) 19880133Sgad + (size_t)(line - cp - 6)); 19987375Sgad if (strchr(cp, '/')) { 20087375Sgad frecverr("readjob: %s: illegal path name", cp); 20187375Sgad /*NOTREACHED*/ 20287375Sgad } 20380133Sgad strlcpy(tfname, cp, sizeof(tfname)); 20427748Simp tfname[sizeof (tfname) - 1] = '\0'; 2051553Srgrimes tfname[0] = 't'; 2061553Srgrimes if (!chksize(size)) { 20780171Sgad (void) write(STDOUT_FILENO, "\2", (size_t)1); 2081553Srgrimes continue; 2091553Srgrimes } 21080171Sgad if (!readfile(pp, tfname, (size_t)size)) { 2111553Srgrimes rcleanup(0); 2121553Srgrimes continue; 2131553Srgrimes } 21479746Sgad errmsg = ctl_renametf(pp->printer, tfname); 2151553Srgrimes tfname[0] = '\0'; 21679746Sgad if (errmsg != NULL) { 21779746Sgad frecverr("%s: %s", pp->printer, errmsg); 21879746Sgad /*NOTREACHED*/ 21979746Sgad } 22068253Sgad cfcnt++; 2211553Srgrimes continue; 2221553Srgrimes 2231553Srgrimes case '\3': /* read df file */ 22468253Sgad *givenid = '\0'; 22568253Sgad *givenhost = '\0'; 2261553Srgrimes size = 0; 2271553Srgrimes while (*cp >= '0' && *cp <= '9') 2281553Srgrimes size = size * 10 + (*cp++ - '0'); 2291553Srgrimes if (*cp++ != ' ') 2301553Srgrimes break; 23187375Sgad if (strchr(cp, '/')) { 23287375Sgad frecverr("readjob: %s: illegal path name", cp); 23387375Sgad /*NOTREACHED*/ 23487375Sgad } 2351553Srgrimes if (!chksize(size)) { 23680171Sgad (void) write(STDOUT_FILENO, "\2", (size_t)1); 2371553Srgrimes continue; 2381553Srgrimes } 23980133Sgad strlcpy(dfname, cp, sizeof(dfname)); 24068253Sgad dfcnt++; 24168253Sgad trstat_init(pp, dfname, dfcnt); 24280171Sgad (void) readfile(pp, dfname, (size_t)size); 24380171Sgad trstat_write(pp, TR_RECVING, (size_t)size, givenid, 24480171Sgad from_host, givenhost); 2451553Srgrimes continue; 2461553Srgrimes } 2471553Srgrimes frecverr("protocol screwup: %s", line); 24868380Sgad /*NOTREACHED*/ 2491553Srgrimes } 2501553Srgrimes} 2511553Srgrimes 2521553Srgrimes/* 2531553Srgrimes * Read files send by lpd and copy them to the spooling directory. 2541553Srgrimes */ 2551553Srgrimesstatic int 25680171Sgadreadfile(struct printer *pp, char *file, size_t size) 2571553Srgrimes{ 2581553Srgrimes register char *cp; 259119192Sgad char buf[SPL_BUFSIZ]; 26080171Sgad size_t amt, i; 26180171Sgad int err, fd, j; 2621553Srgrimes 2631553Srgrimes fd = open(file, O_CREAT|O_EXCL|O_WRONLY, FILMOD); 26468380Sgad if (fd < 0) { 26579739Sgad frecverr("%s: readfile: error on open(%s): %s", 26679739Sgad pp->printer, file, strerror(errno)); 26768380Sgad /*NOTREACHED*/ 26868380Sgad } 2691553Srgrimes ack(); 2701553Srgrimes err = 0; 271119192Sgad for (i = 0; i < size; i += SPL_BUFSIZ) { 272119192Sgad amt = SPL_BUFSIZ; 2731553Srgrimes cp = buf; 2741553Srgrimes if (i + amt > size) 2751553Srgrimes amt = size - i; 2761553Srgrimes do { 27780113Sgad j = read(STDOUT_FILENO, cp, amt); 27868380Sgad if (j <= 0) { 27968380Sgad frecverr("%s: lost connection", pp->printer); 28068380Sgad /*NOTREACHED*/ 28168380Sgad } 2821553Srgrimes amt -= j; 2831553Srgrimes cp += j; 2841553Srgrimes } while (amt > 0); 285119192Sgad amt = SPL_BUFSIZ; 2861553Srgrimes if (i + amt > size) 2871553Srgrimes amt = size - i; 28880171Sgad if (write(fd, buf, amt) != (ssize_t)amt) { 2891553Srgrimes err++; 2901553Srgrimes break; 2911553Srgrimes } 2921553Srgrimes } 2931553Srgrimes (void) close(fd); 29468380Sgad if (err) { 29568380Sgad frecverr("%s: write error on close(%s)", pp->printer, file); 29668380Sgad /*NOTREACHED*/ 29768380Sgad } 2981553Srgrimes if (noresponse()) { /* file sent had bad data in it */ 29930143Simp if (strchr(file, '/') == NULL) 30030143Simp (void) unlink(file); 30168380Sgad return (0); 3021553Srgrimes } 3031553Srgrimes ack(); 30468380Sgad return (1); 3051553Srgrimes} 3061553Srgrimes 3071553Srgrimesstatic int 30878146Sgadnoresponse(void) 3091553Srgrimes{ 3101553Srgrimes char resp; 3111553Srgrimes 31280171Sgad if (read(STDOUT_FILENO, &resp, (size_t)1) != 1) { 31368380Sgad frecverr("lost connection in noresponse()"); 31468380Sgad /*NOTREACHED*/ 31568380Sgad } 3161553Srgrimes if (resp == '\0') 3171553Srgrimes return(0); 3181553Srgrimes return(1); 3191553Srgrimes} 3201553Srgrimes 3211553Srgrimes/* 3221553Srgrimes * Check to see if there is enough space on the disk for size bytes. 3231553Srgrimes * 1 == OK, 0 == Not OK. 3241553Srgrimes */ 3251553Srgrimesstatic int 32678146Sgadchksize(int size) 3271553Srgrimes{ 328182599Sticso int64_t spacefree; 3291553Srgrimes struct statfs sfb; 3301553Srgrimes 3311553Srgrimes if (statfs(".", &sfb) < 0) { 3321553Srgrimes syslog(LOG_ERR, "%s: %m", "statfs(\".\")"); 3331553Srgrimes return (1); 3341553Srgrimes } 3351553Srgrimes spacefree = sfb.f_bavail * (sfb.f_bsize / 512); 3361553Srgrimes size = (size + 511) / 512; 3371553Srgrimes if (minfree + size > spacefree) 3381553Srgrimes return(0); 3391553Srgrimes return(1); 3401553Srgrimes} 3411553Srgrimes 3421553Srgrimesstatic int 34378146Sgadread_number(const char *fn) 3441553Srgrimes{ 3451553Srgrimes char lin[80]; 3461553Srgrimes register FILE *fp; 3471553Srgrimes 3481553Srgrimes if ((fp = fopen(fn, "r")) == NULL) 3491553Srgrimes return (0); 350167260Skevlo if (fgets(lin, sizeof(lin), fp) == NULL) { 3511553Srgrimes fclose(fp); 3521553Srgrimes return (0); 3531553Srgrimes } 3541553Srgrimes fclose(fp); 3551553Srgrimes return (atoi(lin)); 3561553Srgrimes} 3571553Srgrimes 3581553Srgrimes/* 3591553Srgrimes * Remove all the files associated with the current job being transfered. 3601553Srgrimes */ 3611553Srgrimesstatic void 36278146Sgadrcleanup(int signo __unused) 3631553Srgrimes{ 36430143Simp if (tfname[0] && strchr(tfname, '/') == NULL) 3651553Srgrimes (void) unlink(tfname); 36630143Simp if (dfname[0] && strchr(dfname, '/') == NULL) { 3671553Srgrimes do { 3681553Srgrimes do 3691553Srgrimes (void) unlink(dfname); 3701553Srgrimes while (dfname[2]-- != 'A'); 3711553Srgrimes dfname[2] = 'z'; 3721553Srgrimes } while (dfname[0]-- != 'd'); 37330143Simp } 3741553Srgrimes dfname[0] = '\0'; 3751553Srgrimes} 3761553Srgrimes 3771553Srgrimes#include <stdarg.h> 3781553Srgrimes 3791553Srgrimesstatic void 3801553Srgrimesfrecverr(const char *msg, ...) 3811553Srgrimes{ 3821553Srgrimes va_list ap; 3831553Srgrimes va_start(ap, msg); 38478300Sgad syslog(LOG_ERR, "Error receiving job from %s:", from_host); 3851553Srgrimes vsyslog(LOG_ERR, msg, ap); 3861553Srgrimes va_end(ap); 38768340Sgad /* 38868735Sgad * rcleanup is not called until AFTER logging the error message, 38968735Sgad * because rcleanup will zap some variables which may have been 39068735Sgad * supplied as parameters for that msg... 39168340Sgad */ 39268340Sgad rcleanup(0); 39368340Sgad /* 39468340Sgad * Add a minimal delay before returning the final error code to 39568340Sgad * the sending host. This just in case that machine responds 39668340Sgad * this error by INSTANTLY retrying (and instantly re-failing...). 39768340Sgad * It would be stupid of the sending host to do that, but if there 39868340Sgad * was a broken implementation which did it, the result might be 39968340Sgad * obscure performance problems and a flood of syslog messages on 40068340Sgad * the receiving host. 40168340Sgad */ 40268340Sgad sleep(2); /* a paranoid throttling measure */ 4031553Srgrimes putchar('\1'); /* return error code */ 4041553Srgrimes exit(1); 4051553Srgrimes} 406