xref: /csrg-svn/usr.sbin/lpr/lpd/recvjob.c (revision 56123)
122438Sdist /*
222438Sdist  * Copyright (c) 1983 Regents of the University of California.
334203Sbostic  * All rights reserved.
434203Sbostic  *
5*56123Selan  * Redistribution and use in source and binary forms, with or without
6*56123Selan  * modification, are permitted provided that the following conditions
7*56123Selan  * are met:
8*56123Selan  * 1. Redistributions of source code must retain the above copyright
9*56123Selan  *    notice, this list of conditions and the following disclaimer.
10*56123Selan  * 2. Redistributions in binary form must reproduce the above copyright
11*56123Selan  *    notice, this list of conditions and the following disclaimer in the
12*56123Selan  *    documentation and/or other materials provided with the distribution.
13*56123Selan  * 3. All advertising materials mentioning features or use of this software
14*56123Selan  *    must display the following acknowledgement:
15*56123Selan  *	This product includes software developed by the University of
16*56123Selan  *	California, Berkeley and its contributors.
17*56123Selan  * 4. Neither the name of the University nor the names of its contributors
18*56123Selan  *    may be used to endorse or promote products derived from this software
19*56123Selan  *    without specific prior written permission.
20*56123Selan  *
21*56123Selan  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22*56123Selan  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23*56123Selan  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24*56123Selan  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25*56123Selan  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26*56123Selan  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27*56123Selan  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28*56123Selan  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29*56123Selan  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30*56123Selan  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31*56123Selan  * SUCH DAMAGE.
3222438Sdist  */
3322438Sdist 
3413955Ssam #ifndef lint
35*56123Selan static char sccsid[] = "@(#)recvjob.c	5.18 (Berkeley) 8/6/92";
3634203Sbostic #endif /* not lint */
3713955Ssam 
3812115Sralph /*
3912115Sralph  * Receive printer jobs from the network, queue them and
4012115Sralph  * start the printer daemon.
4112115Sralph  */
4255474Sbostic #include <sys/param.h>
4355474Sbostic #include <sys/mount.h>
4455474Sbostic #include <sys/stat.h>
4512115Sralph 
46*56123Selan #include <unistd.h>
4755474Sbostic #include <signal.h>
4855474Sbostic #include <fcntl.h>
4955474Sbostic #include <dirent.h>
5055474Sbostic #include <syslog.h>
5155474Sbostic #include <stdio.h>
52*56123Selan #include <stdlib.h>
53*56123Selan #include <string.h>
5412115Sralph #include "lp.h"
5555474Sbostic #include "lp.local.h"
5655474Sbostic #include "extern.h"
5737968Sbostic #include "pathnames.h"
5812115Sralph 
5916763Sralph #define ack()	(void) write(1, sp, 1);
6012115Sralph 
61*56123Selan static char	 dfname[40];	/* data files */
62*56123Selan static int	 minfree;       /* keep at least minfree blocks available */
63*56123Selan static char	*sp = "";
64*56123Selan static char	 tfname[40];	/* tmp copy of cf before linking */
6516763Sralph 
6655474Sbostic static int        chksize __P((int));
6755474Sbostic static void       frecverr __P((const char *, ...));
68*56123Selan static int        noresponse __P((void));
69*56123Selan static void       rcleanup __P((int));
7055474Sbostic static int        read_number __P((char *));
71*56123Selan static int        readfile __P((char *, int));
72*56123Selan static int        readjob __P((void));
7316763Sralph 
7455474Sbostic 
75*56123Selan void
7612115Sralph recvjob()
7712115Sralph {
7812464Sralph 	struct stat stb;
7946913Sbostic 	int status;
8012115Sralph 
8112115Sralph 	/*
8212115Sralph 	 * Perform lookup for printer name or abbreviation
8312115Sralph 	 */
84*56123Selan 	if ((status = cgetent(&bp, printcapdb, printer)) == -2)
8516763Sralph 		frecverr("cannot open printer description file");
86*56123Selan 	else if (status == -1)
8716763Sralph 		frecverr("unknown printer %s", printer);
88*56123Selan 	else if (status == -3)
89*56123Selan 		fatal("potential reference loop detected in printcap file");
90*56123Selan 
91*56123Selan 	if (cgetstr(bp, "lf", &LF) == -1)
9237968Sbostic 		LF = _PATH_CONSOLE;
93*56123Selan 	if (cgetstr(bp, "sd", &SD) == -1)
9437968Sbostic 		SD = _PATH_DEFSPOOL;
95*56123Selan 	if (cgetstr(bp, "lo", &LO) == -1)
9612464Sralph 		LO = DEFLOCK;
9712115Sralph 
9825498Seric 	(void) close(2);			/* set up log file */
9925498Seric 	if (open(LF, O_WRONLY|O_APPEND, 0664) < 0) {
10025498Seric 		syslog(LOG_ERR, "%s: %m", LF);
10137968Sbostic 		(void) open(_PATH_DEVNULL, O_WRONLY);
10225498Seric 	}
10325498Seric 
10412115Sralph 	if (chdir(SD) < 0)
10516763Sralph 		frecverr("%s: %s: %m", printer, SD);
10616763Sralph 	if (stat(LO, &stb) == 0) {
10716763Sralph 		if (stb.st_mode & 010) {
10816763Sralph 			/* queue is disabled */
10916763Sralph 			putchar('\1');		/* return error code */
11016763Sralph 			exit(1);
11116763Sralph 		}
11216763Sralph 	} else if (stat(SD, &stb) < 0)
11316763Sralph 		frecverr("%s: %s: %m", printer, SD);
11448962Smckusick 	minfree = 2 * read_number("minfree");	/* scale KB to 512 blocks */
11516763Sralph 	signal(SIGTERM, rcleanup);
11616763Sralph 	signal(SIGPIPE, rcleanup);
11712115Sralph 
11812115Sralph 	if (readjob())
11912115Sralph 		printjob();
12012115Sralph }
12112115Sralph 
12212115Sralph /*
12312115Sralph  * Read printer jobs sent by lpd and copy them to the spooling directory.
12412115Sralph  * Return the number of jobs successfully transfered.
12512115Sralph  */
12655474Sbostic static int
12716763Sralph readjob()
12812115Sralph {
12912115Sralph 	register int size, nfiles;
13012115Sralph 	register char *cp;
13112115Sralph 
13212115Sralph 	ack();
13312115Sralph 	nfiles = 0;
13412115Sralph 	for (;;) {
13512115Sralph 		/*
13612115Sralph 		 * Read a command to tell us what to do
13712115Sralph 		 */
13812115Sralph 		cp = line;
13912115Sralph 		do {
14012115Sralph 			if ((size = read(1, cp, 1)) != 1) {
14112115Sralph 				if (size < 0)
14216763Sralph 					frecverr("%s: Lost connection",printer);
14312115Sralph 				return(nfiles);
14412115Sralph 			}
14512115Sralph 		} while (*cp++ != '\n');
14612115Sralph 		*--cp = '\0';
14712115Sralph 		cp = line;
14812115Sralph 		switch (*cp++) {
14912115Sralph 		case '\1':	/* cleanup because data sent was bad */
15055474Sbostic 			rcleanup(0);
15112115Sralph 			continue;
15212115Sralph 
15312115Sralph 		case '\2':	/* read cf file */
15412115Sralph 			size = 0;
15512115Sralph 			while (*cp >= '0' && *cp <= '9')
15612115Sralph 				size = size * 10 + (*cp++ - '0');
15712115Sralph 			if (*cp++ != ' ')
15812115Sralph 				break;
15927086Sbloom 			/*
16027086Sbloom 			 * host name has been authenticated, we use our
16127086Sbloom 			 * view of the host name since we may be passed
16227086Sbloom 			 * something different than what gethostbyaddr()
16327086Sbloom 			 * returns
16427086Sbloom 			 */
16527086Sbloom 			strcpy(cp + 6, from);
16612115Sralph 			strcpy(tfname, cp);
16712115Sralph 			tfname[0] = 't';
16816763Sralph 			if (!chksize(size)) {
16916763Sralph 				(void) write(1, "\2", 1);
17016763Sralph 				continue;
17116763Sralph 			}
17212115Sralph 			if (!readfile(tfname, size)) {
17355474Sbostic 				rcleanup(0);
17412115Sralph 				continue;
17512115Sralph 			}
17612115Sralph 			if (link(tfname, cp) < 0)
17716763Sralph 				frecverr("%s: %m", tfname);
17812115Sralph 			(void) unlink(tfname);
17912115Sralph 			tfname[0] = '\0';
18012115Sralph 			nfiles++;
18112115Sralph 			continue;
18212115Sralph 
18312115Sralph 		case '\3':	/* read df file */
18412115Sralph 			size = 0;
18512115Sralph 			while (*cp >= '0' && *cp <= '9')
18612115Sralph 				size = size * 10 + (*cp++ - '0');
18712115Sralph 			if (*cp++ != ' ')
18812115Sralph 				break;
18916763Sralph 			if (!chksize(size)) {
19016763Sralph 				(void) write(1, "\2", 1);
19116763Sralph 				continue;
19216763Sralph 			}
19339220Sbostic 			(void) strcpy(dfname, cp);
19439220Sbostic 			if (index(dfname, '/'))
19549120Smckusick 				frecverr("readjob: %s: illegal path name",
19649120Smckusick 					dfname);
19729385Smckusick 			(void) readfile(dfname, size);
19812115Sralph 			continue;
19912115Sralph 		}
20016763Sralph 		frecverr("protocol screwup");
20112115Sralph 	}
20212115Sralph }
20312115Sralph 
20412115Sralph /*
20512115Sralph  * Read files send by lpd and copy them to the spooling directory.
20612115Sralph  */
20755474Sbostic static int
20812115Sralph readfile(file, size)
20912115Sralph 	char *file;
21012115Sralph 	int size;
21112115Sralph {
21212115Sralph 	register char *cp;
21312115Sralph 	char buf[BUFSIZ];
21412115Sralph 	register int i, j, amt;
21512115Sralph 	int fd, err;
21612115Sralph 
21748962Smckusick 	fd = open(file, O_CREAT|O_EXCL|O_WRONLY, FILMOD);
21812115Sralph 	if (fd < 0)
21949120Smckusick 		frecverr("readfile: %s: illegal path name: %m", file);
22012115Sralph 	ack();
22112115Sralph 	err = 0;
22212115Sralph 	for (i = 0; i < size; i += BUFSIZ) {
22312115Sralph 		amt = BUFSIZ;
22412115Sralph 		cp = buf;
22512115Sralph 		if (i + amt > size)
22612115Sralph 			amt = size - i;
22712115Sralph 		do {
22812115Sralph 			j = read(1, cp, amt);
22912115Sralph 			if (j <= 0)
23016763Sralph 				frecverr("Lost connection");
23112115Sralph 			amt -= j;
23212115Sralph 			cp += j;
23312115Sralph 		} while (amt > 0);
23412115Sralph 		amt = BUFSIZ;
23512115Sralph 		if (i + amt > size)
23612115Sralph 			amt = size - i;
23713170Sralph 		if (write(fd, buf, amt) != amt) {
23812115Sralph 			err++;
23913170Sralph 			break;
24013170Sralph 		}
24112115Sralph 	}
24212115Sralph 	(void) close(fd);
24312115Sralph 	if (err)
24416763Sralph 		frecverr("%s: write error", file);
24512115Sralph 	if (noresponse()) {		/* file sent had bad data in it */
24612115Sralph 		(void) unlink(file);
24712115Sralph 		return(0);
24812115Sralph 	}
24912115Sralph 	ack();
25012115Sralph 	return(1);
25112115Sralph }
25212115Sralph 
25355474Sbostic static int
25412115Sralph noresponse()
25512115Sralph {
25612115Sralph 	char resp;
25712115Sralph 
25812115Sralph 	if (read(1, &resp, 1) != 1)
25916763Sralph 		frecverr("Lost connection");
26012115Sralph 	if (resp == '\0')
26112115Sralph 		return(0);
26212115Sralph 	return(1);
26312115Sralph }
26412115Sralph 
26512115Sralph /*
26616763Sralph  * Check to see if there is enough space on the disk for size bytes.
26716763Sralph  * 1 == OK, 0 == Not OK.
26816763Sralph  */
26955474Sbostic static int
27016763Sralph chksize(size)
27116763Sralph 	int size;
27216763Sralph {
27316763Sralph 	int spacefree;
27448962Smckusick 	struct statfs sfb;
27516763Sralph 
27648962Smckusick 	if (statfs(".", &sfb) < 0) {
27748962Smckusick 		syslog(LOG_ERR, "%s: %m", "statfs(\".\")");
27848962Smckusick 		return (1);
27948962Smckusick 	}
28052253Sbostic 	spacefree = sfb.f_bavail * (sfb.f_bsize / 512);
28148962Smckusick 	size = (size + 511) / 512;
28216763Sralph 	if (minfree + size > spacefree)
28316763Sralph 		return(0);
28416763Sralph 	return(1);
28516763Sralph }
28616763Sralph 
28755474Sbostic static int
28816763Sralph read_number(fn)
28916763Sralph 	char *fn;
29016763Sralph {
29116763Sralph 	char lin[80];
29216763Sralph 	register FILE *fp;
29316763Sralph 
29416763Sralph 	if ((fp = fopen(fn, "r")) == NULL)
29516763Sralph 		return (0);
29616763Sralph 	if (fgets(lin, 80, fp) == NULL) {
29716763Sralph 		fclose(fp);
29816763Sralph 		return (0);
29916763Sralph 	}
30016763Sralph 	fclose(fp);
30116763Sralph 	return (atoi(lin));
30216763Sralph }
30316763Sralph 
30416763Sralph /*
30512115Sralph  * Remove all the files associated with the current job being transfered.
30612115Sralph  */
30755474Sbostic static void
30855474Sbostic rcleanup(signo)
30955474Sbostic 	int signo;
31012115Sralph {
31112115Sralph 	if (tfname[0])
31212115Sralph 		(void) unlink(tfname);
31329385Smckusick 	if (dfname[0])
31412115Sralph 		do {
31512115Sralph 			do
31612115Sralph 				(void) unlink(dfname);
31716938Sralph 			while (dfname[2]-- != 'A');
31816938Sralph 			dfname[2] = 'z';
31916938Sralph 		} while (dfname[0]-- != 'd');
32029385Smckusick 	dfname[0] = '\0';
32112115Sralph }
32212115Sralph 
32355474Sbostic #if __STDC__
32455474Sbostic #include <stdarg.h>
32555474Sbostic #else
32655474Sbostic #include <varargs.h>
32755474Sbostic #endif
32855474Sbostic 
32955474Sbostic static void
33055474Sbostic #if __STDC__
33155474Sbostic frecverr(const char *msg, ...)
33255474Sbostic #else
33355474Sbostic frecverr(msg, va_alist)
33412115Sralph 	char *msg;
33555474Sbostic         va_dcl
33655474Sbostic #endif
33712115Sralph {
33855474Sbostic 	va_list ap;
33955474Sbostic #if __STDC__
34055474Sbostic 	va_start(ap, msg);
34155474Sbostic #else
34255474Sbostic 	va_start(ap);
34355474Sbostic #endif
34455474Sbostic 	rcleanup(0);
34555474Sbostic 	vsyslog(LOG_ERR, msg, ap);
34655474Sbostic 	va_end(ap);
34712115Sralph 	putchar('\1');		/* return error code */
34812115Sralph 	exit(1);
34912115Sralph }
350