Home | History | Annotate | Line # | Download | only in lpd
recvjob.c revision 1.7
      1 /*	$NetBSD: recvjob.c,v 1.7 1996/12/09 09:57:47 mrg Exp $	*/
      2 /*
      3  * Copyright (c) 1983, 1993
      4  *	The Regents of the University of California.  All rights reserved.
      5  *
      6  *
      7  * Redistribution and use in source and binary forms, with or without
      8  * modification, are permitted provided that the following conditions
      9  * are met:
     10  * 1. Redistributions of source code must retain the above copyright
     11  *    notice, this list of conditions and the following disclaimer.
     12  * 2. Redistributions in binary form must reproduce the above copyright
     13  *    notice, this list of conditions and the following disclaimer in the
     14  *    documentation and/or other materials provided with the distribution.
     15  * 3. All advertising materials mentioning features or use of this software
     16  *    must display the following acknowledgement:
     17  *	This product includes software developed by the University of
     18  *	California, Berkeley and its contributors.
     19  * 4. Neither the name of the University nor the names of its contributors
     20  *    may be used to endorse or promote products derived from this software
     21  *    without specific prior written permission.
     22  *
     23  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
     24  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     25  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     26  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
     27  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     28  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     29  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     30  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     31  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     32  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     33  * SUCH DAMAGE.
     34  */
     35 
     36 #ifndef lint
     37 static char copyright[] =
     38 "@(#) Copyright (c) 1983, 1993\n\
     39 	The Regents of the University of California.  All rights reserved.\n";
     40 #endif /* not lint */
     41 
     42 #ifndef lint
     43 static char sccsid[] = "@(#)recvjob.c	8.1 (Berkeley) 6/6/93";
     44 #endif /* not lint */
     45 
     46 /*
     47  * Receive printer jobs from the network, queue them and
     48  * start the printer daemon.
     49  */
     50 #include <sys/param.h>
     51 #include <sys/mount.h>
     52 #include <sys/stat.h>
     53 
     54 #include <unistd.h>
     55 #include <signal.h>
     56 #include <fcntl.h>
     57 #include <dirent.h>
     58 #include <syslog.h>
     59 #include <stdio.h>
     60 #include <stdlib.h>
     61 #include <string.h>
     62 #include "lp.h"
     63 #include "lp.local.h"
     64 #include "extern.h"
     65 #include "pathnames.h"
     66 
     67 #define ack()	(void)write(1, sp, 1);
     68 
     69 static char	 dfname[40];	/* data files */
     70 static int	 minfree;       /* keep at least minfree blocks available */
     71 static char	*sp = "";
     72 static char	 tfname[40];	/* tmp copy of cf before linking */
     73 
     74 static int        chksize __P((int));
     75 static void       frecverr __P((const char *, ...));
     76 static int        noresponse __P((void));
     77 static void       rcleanup __P((int));
     78 static int        read_number __P((char *));
     79 static int        readfile __P((char *, int));
     80 static int        readjob __P((void));
     81 
     82 
     83 void
     84 recvjob()
     85 {
     86 	struct stat stb;
     87 	int status;
     88 
     89 	/*
     90 	 * Perform lookup for printer name or abbreviation
     91 	 */
     92 	if ((status = cgetent(&bp, printcapdb, printer)) == -2)
     93 		frecverr("cannot open printer description file");
     94 	else if (status == -1)
     95 		frecverr("unknown printer %s", printer);
     96 	else if (status == -3)
     97 		fatal("potential reference loop detected in printcap file");
     98 
     99 	if (cgetstr(bp, "lf", &LF) == -1)
    100 		LF = _PATH_CONSOLE;
    101 	if (cgetstr(bp, "sd", &SD) == -1)
    102 		SD = _PATH_DEFSPOOL;
    103 	if (cgetstr(bp, "lo", &LO) == -1)
    104 		LO = DEFLOCK;
    105 
    106 	(void)close(2);			/* set up log file */
    107 	if (open(LF, O_WRONLY|O_APPEND, 0664) < 0) {
    108 		syslog(LOG_ERR, "%s: %m", LF);
    109 		(void)open(_PATH_DEVNULL, O_WRONLY);
    110 	}
    111 
    112 	if (chdir(SD) < 0)
    113 		frecverr("%s: %s: %m", printer, SD);
    114 	if (stat(LO, &stb) == 0) {
    115 		if (stb.st_mode & 010) {
    116 			/* queue is disabled */
    117 			putchar('\1');		/* return error code */
    118 			exit(1);
    119 		}
    120 	} else if (stat(SD, &stb) < 0)
    121 		frecverr("%s: %s: %m", printer, SD);
    122 	minfree = 2 * read_number("minfree");	/* scale KB to 512 blocks */
    123 	signal(SIGTERM, rcleanup);
    124 	signal(SIGPIPE, rcleanup);
    125 
    126 	if (readjob())
    127 		printjob();
    128 }
    129 
    130 /*
    131  * Read printer jobs sent by lpd and copy them to the spooling directory.
    132  * Return the number of jobs successfully transfered.
    133  */
    134 static int
    135 readjob()
    136 {
    137 	register int size, nfiles;
    138 	register char *cp;
    139 
    140 	ack();
    141 	nfiles = 0;
    142 	for (;;) {
    143 		/*
    144 		 * Read a command to tell us what to do
    145 		 */
    146 		cp = line;
    147 		do {
    148 			if ((size = read(1, cp, 1)) != 1) {
    149 				if (size < 0)
    150 					frecverr("%s: Lost connection",printer);
    151 				return(nfiles);
    152 			}
    153 		} while (*cp++ != '\n');
    154 		*--cp = '\0';
    155 		cp = line;
    156 		switch (*cp++) {
    157 		case '\1':	/* cleanup because data sent was bad */
    158 			rcleanup(0);
    159 			continue;
    160 
    161 		case '\2':	/* read cf file */
    162 			size = 0;
    163 			while (*cp >= '0' && *cp <= '9')
    164 				size = size * 10 + (*cp++ - '0');
    165 			if (*cp++ != ' ')
    166 				break;
    167 			/*
    168 			 * host name has been authenticated, we use our
    169 			 * view of the host name since we may be passed
    170 			 * something different than what gethostbyaddr()
    171 			 * returns
    172 			 */
    173 			(void)strncpy(cp + 6, from, sizeof(line) - strlen(line) - 1);
    174 			(void)strncpy(tfname, cp, sizeof(tfname) - 1);
    175 			tfname[0] = 't';
    176 			if (!chksize(size)) {
    177 				(void)write(1, "\2", 1);
    178 				continue;
    179 			}
    180 			if (!readfile(tfname, size)) {
    181 				rcleanup(0);
    182 				continue;
    183 			}
    184 			if (link(tfname, cp) < 0)
    185 				frecverr("%s: %m", tfname);
    186 			(void)unlink(tfname);
    187 			tfname[0] = '\0';
    188 			nfiles++;
    189 			continue;
    190 
    191 		case '\3':	/* read df file */
    192 			size = 0;
    193 			while (*cp >= '0' && *cp <= '9')
    194 				size = size * 10 + (*cp++ - '0');
    195 			if (*cp++ != ' ')
    196 				break;
    197 			if (!chksize(size)) {
    198 				(void)write(1, "\2", 1);
    199 				continue;
    200 			}
    201 			(void)strncpy(dfname, cp, sizeof(dfname) - 1);
    202 			if (index(dfname, '/'))
    203 				frecverr("readjob: %s: illegal path name",
    204 					dfname);
    205 			(void)readfile(dfname, size);
    206 			continue;
    207 		}
    208 		frecverr("protocol screwup: %s", line);
    209 	}
    210 }
    211 
    212 /*
    213  * Read files send by lpd and copy them to the spooling directory.
    214  */
    215 static int
    216 readfile(file, size)
    217 	char *file;
    218 	int size;
    219 {
    220 	register char *cp;
    221 	char buf[BUFSIZ];
    222 	register int i, j, amt;
    223 	int fd, err;
    224 
    225 	fd = open(file, O_CREAT|O_EXCL|O_WRONLY, FILMOD);
    226 	if (fd < 0)
    227 		frecverr("readfile: %s: illegal path name: %m", file);
    228 	ack();
    229 	err = 0;
    230 	for (i = 0; i < size; i += BUFSIZ) {
    231 		amt = BUFSIZ;
    232 		cp = buf;
    233 		if (i + amt > size)
    234 			amt = size - i;
    235 		do {
    236 			j = read(1, cp, amt);
    237 			if (j <= 0)
    238 				frecverr("Lost connection");
    239 			amt -= j;
    240 			cp += j;
    241 		} while (amt > 0);
    242 		amt = BUFSIZ;
    243 		if (i + amt > size)
    244 			amt = size - i;
    245 		if (write(fd, buf, amt) != amt) {
    246 			err++;
    247 			break;
    248 		}
    249 	}
    250 	(void)close(fd);
    251 	if (err)
    252 		frecverr("%s: write error", file);
    253 	if (noresponse()) {		/* file sent had bad data in it */
    254 		(void)unlink(file);
    255 		return(0);
    256 	}
    257 	ack();
    258 	return(1);
    259 }
    260 
    261 static int
    262 noresponse()
    263 {
    264 	char resp;
    265 
    266 	if (read(1, &resp, 1) != 1)
    267 		frecverr("Lost connection");
    268 	if (resp == '\0')
    269 		return(0);
    270 	return(1);
    271 }
    272 
    273 /*
    274  * Check to see if there is enough space on the disk for size bytes.
    275  * 1 == OK, 0 == Not OK.
    276  */
    277 static int
    278 chksize(size)
    279 	int size;
    280 {
    281 	int spacefree;
    282 	struct statfs sfb;
    283 
    284 	if (statfs(".", &sfb) < 0) {
    285 		syslog(LOG_ERR, "%s: %m", "statfs(\".\")");
    286 		return (1);
    287 	}
    288 	spacefree = sfb.f_bavail * (sfb.f_bsize / 512);
    289 	size = (size + 511) / 512;
    290 	if (minfree + size > spacefree)
    291 		return(0);
    292 	return(1);
    293 }
    294 
    295 static int
    296 read_number(fn)
    297 	char *fn;
    298 {
    299 	char lin[80];
    300 	register FILE *fp;
    301 
    302 	if ((fp = fopen(fn, "r")) == NULL)
    303 		return (0);
    304 	if (fgets(lin, 80, fp) == NULL) {
    305 		fclose(fp);
    306 		return (0);
    307 	}
    308 	fclose(fp);
    309 	return (atoi(lin));
    310 }
    311 
    312 /*
    313  * Remove all the files associated with the current job being transfered.
    314  */
    315 static void
    316 rcleanup(signo)
    317 	int signo;
    318 {
    319 	if (tfname[0])
    320 		(void)unlink(tfname);
    321 	if (dfname[0])
    322 		do {
    323 			do
    324 				(void)unlink(dfname);
    325 			while (dfname[2]-- != 'A');
    326 			dfname[2] = 'z';
    327 		} while (dfname[0]-- != 'd');
    328 	dfname[0] = '\0';
    329 }
    330 
    331 #if __STDC__
    332 #include <stdarg.h>
    333 #else
    334 #include <varargs.h>
    335 #endif
    336 
    337 static void
    338 #if __STDC__
    339 frecverr(const char *msg, ...)
    340 #else
    341 frecverr(msg, va_alist)
    342 	char *msg;
    343         va_dcl
    344 #endif
    345 {
    346 	extern char fromb[];
    347 	va_list ap;
    348 #if __STDC__
    349 	va_start(ap, msg);
    350 #else
    351 	va_start(ap);
    352 #endif
    353 	rcleanup(0);
    354 	syslog(LOG_ERR, "%s", fromb);
    355 	vsyslog(LOG_ERR, msg, ap);
    356 	va_end(ap);
    357 	putchar('\1');		/* return error code */
    358 	exit(1);
    359 }
    360