xref: /csrg-svn/usr.sbin/lpr/lpd/recvjob.c (revision 38493)
122438Sdist /*
222438Sdist  * Copyright (c) 1983 Regents of the University of California.
334203Sbostic  * All rights reserved.
434203Sbostic  *
534203Sbostic  * Redistribution and use in source and binary forms are permitted
634936Sbostic  * provided that the above copyright notice and this paragraph are
734936Sbostic  * duplicated in all such forms and that any documentation,
834936Sbostic  * advertising materials, and other materials related to such
934936Sbostic  * distribution and use acknowledge that the software was developed
1034936Sbostic  * by the University of California, Berkeley.  The name of the
1134936Sbostic  * University may not be used to endorse or promote products derived
1234936Sbostic  * from this software without specific prior written permission.
1334936Sbostic  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
1434936Sbostic  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
1534936Sbostic  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
1622438Sdist  */
1722438Sdist 
1813955Ssam #ifndef lint
19*38493Skarels static char sccsid[] = "@(#)recvjob.c	5.9 (Berkeley) 07/28/89";
2034203Sbostic #endif /* not lint */
2113955Ssam 
2212115Sralph /*
2312115Sralph  * Receive printer jobs from the network, queue them and
2412115Sralph  * start the printer daemon.
2512115Sralph  */
2612115Sralph 
2712115Sralph #include "lp.h"
28*38493Skarels #include <ufs/fs.h>
2937968Sbostic #include "pathnames.h"
3012115Sralph 
3116763Sralph char	*sp = "";
3216763Sralph #define ack()	(void) write(1, sp, 1);
3312115Sralph 
3416763Sralph char    tfname[40];		/* tmp copy of cf before linking */
3529385Smckusick char    dfname[40];		/* data files */
3616763Sralph int	minfree;		/* keep at least minfree blocks available */
3716763Sralph char	*ddev;			/* disk device (for checking free space) */
3816763Sralph int	dfd;			/* file system device descriptor */
3916763Sralph 
4016763Sralph char	*find_dev();
4116763Sralph 
4212115Sralph recvjob()
4312115Sralph {
4412464Sralph 	struct stat stb;
4512115Sralph 	char *bp = pbuf;
4616763Sralph 	int status, rcleanup();
4712115Sralph 
4812115Sralph 	/*
4912115Sralph 	 * Perform lookup for printer name or abbreviation
5012115Sralph 	 */
5112115Sralph 	if ((status = pgetent(line, printer)) < 0)
5216763Sralph 		frecverr("cannot open printer description file");
5312115Sralph 	else if (status == 0)
5416763Sralph 		frecverr("unknown printer %s", printer);
5512115Sralph 	if ((LF = pgetstr("lf", &bp)) == NULL)
5637968Sbostic 		LF = _PATH_CONSOLE;
5712115Sralph 	if ((SD = pgetstr("sd", &bp)) == NULL)
5837968Sbostic 		SD = _PATH_DEFSPOOL;
5912464Sralph 	if ((LO = pgetstr("lo", &bp)) == NULL)
6012464Sralph 		LO = DEFLOCK;
6112115Sralph 
6225498Seric 	(void) close(2);			/* set up log file */
6325498Seric 	if (open(LF, O_WRONLY|O_APPEND, 0664) < 0) {
6425498Seric 		syslog(LOG_ERR, "%s: %m", LF);
6537968Sbostic 		(void) open(_PATH_DEVNULL, O_WRONLY);
6625498Seric 	}
6725498Seric 
6812115Sralph 	if (chdir(SD) < 0)
6916763Sralph 		frecverr("%s: %s: %m", printer, SD);
7016763Sralph 	if (stat(LO, &stb) == 0) {
7116763Sralph 		if (stb.st_mode & 010) {
7216763Sralph 			/* queue is disabled */
7316763Sralph 			putchar('\1');		/* return error code */
7416763Sralph 			exit(1);
7516763Sralph 		}
7616763Sralph 	} else if (stat(SD, &stb) < 0)
7716763Sralph 		frecverr("%s: %s: %m", printer, SD);
7816763Sralph 	minfree = read_number("minfree");
7916763Sralph 	ddev = find_dev(stb.st_dev, S_IFBLK);
8016763Sralph 	if ((dfd = open(ddev, O_RDONLY)) < 0)
8116763Sralph 		syslog(LOG_WARNING, "%s: %s: %m", printer, ddev);
8216763Sralph 	signal(SIGTERM, rcleanup);
8316763Sralph 	signal(SIGPIPE, rcleanup);
8412115Sralph 
8512115Sralph 	if (readjob())
8612115Sralph 		printjob();
8712115Sralph }
8812115Sralph 
8916763Sralph char *
9016763Sralph find_dev(dev, type)
9116763Sralph 	register dev_t dev;
9216763Sralph 	register int type;
9316763Sralph {
9437968Sbostic 	register DIR *dfd = opendir(_PATH_DEV);
9516763Sralph 	struct direct *dir;
9616763Sralph 	struct stat stb;
9716763Sralph 	char devname[MAXNAMLEN+6];
9816763Sralph 	char *dp;
9912115Sralph 
10037968Sbostic 	strcpy(devname, _PATH_DEV);
10116763Sralph 	while ((dir = readdir(dfd))) {
10216763Sralph 		strcpy(devname + 5, dir->d_name);
10316763Sralph 		if (stat(devname, &stb))
10416763Sralph 			continue;
10516763Sralph 		if ((stb.st_mode & S_IFMT) != type)
10616763Sralph 			continue;
10716763Sralph 		if (dev == stb.st_rdev) {
10816763Sralph 			closedir(dfd);
10916763Sralph 			dp = (char *)malloc(strlen(devname)+1);
11016763Sralph 			strcpy(dp, devname);
11116763Sralph 			return(dp);
11216763Sralph 		}
11316763Sralph 	}
11416763Sralph 	closedir(dfd);
11516763Sralph 	frecverr("cannot find device %d, %d", major(dev), minor(dev));
11616763Sralph 	/*NOTREACHED*/
11716763Sralph }
11816763Sralph 
11912115Sralph /*
12012115Sralph  * Read printer jobs sent by lpd and copy them to the spooling directory.
12112115Sralph  * Return the number of jobs successfully transfered.
12212115Sralph  */
12316763Sralph readjob()
12412115Sralph {
12512115Sralph 	register int size, nfiles;
12612115Sralph 	register char *cp;
12712115Sralph 
12812115Sralph 	ack();
12912115Sralph 	nfiles = 0;
13012115Sralph 	for (;;) {
13112115Sralph 		/*
13212115Sralph 		 * Read a command to tell us what to do
13312115Sralph 		 */
13412115Sralph 		cp = line;
13512115Sralph 		do {
13612115Sralph 			if ((size = read(1, cp, 1)) != 1) {
13712115Sralph 				if (size < 0)
13816763Sralph 					frecverr("%s: Lost connection",printer);
13912115Sralph 				return(nfiles);
14012115Sralph 			}
14112115Sralph 		} while (*cp++ != '\n');
14212115Sralph 		*--cp = '\0';
14312115Sralph 		cp = line;
14412115Sralph 		switch (*cp++) {
14512115Sralph 		case '\1':	/* cleanup because data sent was bad */
14616763Sralph 			rcleanup();
14712115Sralph 			continue;
14812115Sralph 
14912115Sralph 		case '\2':	/* read cf file */
15012115Sralph 			size = 0;
15112115Sralph 			while (*cp >= '0' && *cp <= '9')
15212115Sralph 				size = size * 10 + (*cp++ - '0');
15312115Sralph 			if (*cp++ != ' ')
15412115Sralph 				break;
15527086Sbloom 			/*
15627086Sbloom 			 * host name has been authenticated, we use our
15727086Sbloom 			 * view of the host name since we may be passed
15827086Sbloom 			 * something different than what gethostbyaddr()
15927086Sbloom 			 * returns
16027086Sbloom 			 */
16127086Sbloom 			strcpy(cp + 6, from);
16212115Sralph 			strcpy(tfname, cp);
16312115Sralph 			tfname[0] = 't';
16416763Sralph 			if (!chksize(size)) {
16516763Sralph 				(void) write(1, "\2", 1);
16616763Sralph 				continue;
16716763Sralph 			}
16812115Sralph 			if (!readfile(tfname, size)) {
16916763Sralph 				rcleanup();
17012115Sralph 				continue;
17112115Sralph 			}
17212115Sralph 			if (link(tfname, cp) < 0)
17316763Sralph 				frecverr("%s: %m", tfname);
17412115Sralph 			(void) unlink(tfname);
17512115Sralph 			tfname[0] = '\0';
17612115Sralph 			nfiles++;
17712115Sralph 			continue;
17812115Sralph 
17912115Sralph 		case '\3':	/* read df file */
18012115Sralph 			size = 0;
18112115Sralph 			while (*cp >= '0' && *cp <= '9')
18212115Sralph 				size = size * 10 + (*cp++ - '0');
18312115Sralph 			if (*cp++ != ' ')
18412115Sralph 				break;
18516763Sralph 			if (!chksize(size)) {
18616763Sralph 				(void) write(1, "\2", 1);
18716763Sralph 				continue;
18816763Sralph 			}
18929385Smckusick 			strcpy(dfname, cp);
19029385Smckusick 			(void) readfile(dfname, size);
19112115Sralph 			continue;
19212115Sralph 		}
19316763Sralph 		frecverr("protocol screwup");
19412115Sralph 	}
19512115Sralph }
19612115Sralph 
19712115Sralph /*
19812115Sralph  * Read files send by lpd and copy them to the spooling directory.
19912115Sralph  */
20012115Sralph readfile(file, size)
20112115Sralph 	char *file;
20212115Sralph 	int size;
20312115Sralph {
20412115Sralph 	register char *cp;
20512115Sralph 	char buf[BUFSIZ];
20612115Sralph 	register int i, j, amt;
20712115Sralph 	int fd, err;
20812115Sralph 
20913149Ssam 	fd = open(file, O_WRONLY|O_CREAT, FILMOD);
21012115Sralph 	if (fd < 0)
21116763Sralph 		frecverr("%s: %m", file);
21212115Sralph 	ack();
21312115Sralph 	err = 0;
21412115Sralph 	for (i = 0; i < size; i += BUFSIZ) {
21512115Sralph 		amt = BUFSIZ;
21612115Sralph 		cp = buf;
21712115Sralph 		if (i + amt > size)
21812115Sralph 			amt = size - i;
21912115Sralph 		do {
22012115Sralph 			j = read(1, cp, amt);
22112115Sralph 			if (j <= 0)
22216763Sralph 				frecverr("Lost connection");
22312115Sralph 			amt -= j;
22412115Sralph 			cp += j;
22512115Sralph 		} while (amt > 0);
22612115Sralph 		amt = BUFSIZ;
22712115Sralph 		if (i + amt > size)
22812115Sralph 			amt = size - i;
22913170Sralph 		if (write(fd, buf, amt) != amt) {
23012115Sralph 			err++;
23113170Sralph 			break;
23213170Sralph 		}
23312115Sralph 	}
23412115Sralph 	(void) close(fd);
23512115Sralph 	if (err)
23616763Sralph 		frecverr("%s: write error", file);
23712115Sralph 	if (noresponse()) {		/* file sent had bad data in it */
23812115Sralph 		(void) unlink(file);
23912115Sralph 		return(0);
24012115Sralph 	}
24112115Sralph 	ack();
24212115Sralph 	return(1);
24312115Sralph }
24412115Sralph 
24512115Sralph noresponse()
24612115Sralph {
24712115Sralph 	char resp;
24812115Sralph 
24912115Sralph 	if (read(1, &resp, 1) != 1)
25016763Sralph 		frecverr("Lost connection");
25112115Sralph 	if (resp == '\0')
25212115Sralph 		return(0);
25312115Sralph 	return(1);
25412115Sralph }
25512115Sralph 
25612115Sralph /*
25716763Sralph  * Check to see if there is enough space on the disk for size bytes.
25816763Sralph  * 1 == OK, 0 == Not OK.
25916763Sralph  */
26016763Sralph chksize(size)
26116763Sralph 	int size;
26216763Sralph {
26316763Sralph 	struct stat stb;
26416763Sralph 	register char *ddev;
26516763Sralph 	int spacefree;
26616763Sralph 	struct fs fs;
26716763Sralph 
26830656Smckusick 	if (dfd < 0 || lseek(dfd, (long)(SBOFF), 0) < 0)
26916763Sralph 		return(1);
27016763Sralph 	if (read(dfd, (char *)&fs, sizeof fs) != sizeof fs)
27116763Sralph 		return(1);
27230656Smckusick 	spacefree = freespace(&fs, fs.fs_minfree) * fs.fs_fsize / 1024;
27316763Sralph 	size = (size + 1023) / 1024;
27416763Sralph 	if (minfree + size > spacefree)
27516763Sralph 		return(0);
27616763Sralph 	return(1);
27716763Sralph }
27816763Sralph 
27916763Sralph read_number(fn)
28016763Sralph 	char *fn;
28116763Sralph {
28216763Sralph 	char lin[80];
28316763Sralph 	register FILE *fp;
28416763Sralph 
28516763Sralph 	if ((fp = fopen(fn, "r")) == NULL)
28616763Sralph 		return (0);
28716763Sralph 	if (fgets(lin, 80, fp) == NULL) {
28816763Sralph 		fclose(fp);
28916763Sralph 		return (0);
29016763Sralph 	}
29116763Sralph 	fclose(fp);
29216763Sralph 	return (atoi(lin));
29316763Sralph }
29416763Sralph 
29516763Sralph /*
29612115Sralph  * Remove all the files associated with the current job being transfered.
29712115Sralph  */
29816763Sralph rcleanup()
29912115Sralph {
30012115Sralph 
30112115Sralph 	if (tfname[0])
30212115Sralph 		(void) unlink(tfname);
30329385Smckusick 	if (dfname[0])
30412115Sralph 		do {
30512115Sralph 			do
30612115Sralph 				(void) unlink(dfname);
30716938Sralph 			while (dfname[2]-- != 'A');
30816938Sralph 			dfname[2] = 'z';
30916938Sralph 		} while (dfname[0]-- != 'd');
31029385Smckusick 	dfname[0] = '\0';
31112115Sralph }
31212115Sralph 
31316763Sralph frecverr(msg, a1, a2)
31412115Sralph 	char *msg;
31512115Sralph {
31616763Sralph 	rcleanup();
31716763Sralph 	syslog(LOG_ERR, msg, a1, a2);
31812115Sralph 	putchar('\1');		/* return error code */
31912115Sralph 	exit(1);
32012115Sralph }
321