xref: /csrg-svn/usr.sbin/lpr/lpd/printjob.c (revision 15811)
113954Ssam #ifndef lint
2*15811Sralph static char sccsid[] = "@(#)printjob.c	4.16 (Berkeley) 01/05/84";
313954Ssam #endif
413954Ssam 
512111Sralph /*
612111Sralph  * printjob -- print jobs in the queue.
712111Sralph  *
812111Sralph  *	NOTE: the lock file is used to pass information to lpq and lprm.
912111Sralph  *	it does not need to be removed because file locks are dynamic.
1012111Sralph  */
1112111Sralph 
1212111Sralph #include "lp.h"
1312111Sralph 
1412877Sralph #define DORETURN	0		/* absorb fork error */
1512877Sralph #define DOABORT		1		/* abort if dofork fails */
1612111Sralph 
1712877Sralph static char	title[80];		/* ``pr'' title */
1812877Sralph static FILE	*cfp;			/* control file */
1912877Sralph static int	pfd;			/* printer file descriptor */
2012877Sralph static int	ofd;			/* output filter file descriptor */
2112877Sralph static int	lfd;			/* lock file descriptor */
2212877Sralph static int	pid;			/* pid of lpd process */
2312877Sralph static int	prchild;		/* id of pr process */
2412877Sralph static int	child;			/* id of any filters */
2512877Sralph static int	ofilter;		/* id of output filter, if any */
2612877Sralph static int	tof;			/* true if at top of form */
2714150Sralph static int	count;			/* Number of files actually printed */
2812877Sralph static int	remote;			/* true if sending files to remote */
2912111Sralph 
3014150Sralph static char	fromhost[32];		/* user's host machine */
3112877Sralph static char	logname[32];		/* user's login name */
3215552Sralph static char	jobname[100];		/* job or file name */
3312877Sralph static char	class[32];		/* classification field */
3412877Sralph static char	width[10] = "-w";	/* page width in characters */
3512877Sralph static char	length[10] = "-l";	/* page length in lines */
3612877Sralph static char	pxwidth[10] = "-x";	/* page width in pixels */
3712877Sralph static char	pxlength[10] = "-y";	/* page length in pixels */
3812877Sralph static char	indent[10] = "-i0";	/* indentation size in characters */
39*15811Sralph static char	tmpfile[] = "errsXXXXXX"; /* file name for filter output */
4012111Sralph 
4112111Sralph printjob()
4212111Sralph {
4312111Sralph 	struct stat stb;
4412111Sralph 	register struct queue *q, **qp;
4512111Sralph 	struct queue **queue;
4612111Sralph 	register int i, nitems;
4712111Sralph 	long pidoff;
4812111Sralph 	extern int onintr();
4912111Sralph 
5012111Sralph 	init();					/* set up capabilities */
5113442Sralph 	(void) write(1, "", 1);			/* ack that daemon is started */
5212877Sralph 	(void) close(1);			/* set up log file */
5312877Sralph 	(void) close(2);
5413148Ssam 	if (open(LF, O_WRONLY|O_APPEND) < 0)
5513148Ssam 		(void) open("/dev/null", O_WRONLY);
5612877Sralph 	dup(1);
5712463Sralph 	pid = getpid();				/* for use with lprm */
5812111Sralph 	setpgrp(0, pid);
5914709Sralph 	signal(SIGHUP, onintr);
6013148Ssam 	signal(SIGINT, onintr);
6114709Sralph 	signal(SIGQUIT, onintr);
6214709Sralph 	signal(SIGTERM, onintr);
6312111Sralph 
64*15811Sralph 	(void) mktemp(tmpfile);
65*15811Sralph 
6612111Sralph 	/*
6712111Sralph 	 * uses short form file names
6812111Sralph 	 */
6912111Sralph 	if (chdir(SD) < 0) {
7012111Sralph 		log("cannot chdir to %s", SD);
7112111Sralph 		exit(1);
7212111Sralph 	}
7312463Sralph 	if (stat(LO, &stb) == 0 && (stb.st_mode & 0100))
7412463Sralph 		exit(0);		/* printing disabled */
7514150Sralph 	lfd = open(LO, O_WRONLY|O_CREAT, 0644);
7613169Sralph 	if (lfd < 0) {
7713169Sralph 		log("cannot create %s", LO);
7813169Sralph 		exit(1);
7913169Sralph 	}
8013169Sralph 	if (flock(lfd, LOCK_EX|LOCK_NB) < 0) {
8112111Sralph 		if (errno == EWOULDBLOCK)	/* active deamon present */
8212111Sralph 			exit(0);
8313169Sralph 		log("cannot lock %s", LO);
8412111Sralph 		exit(1);
8512111Sralph 	}
8613148Ssam 	ftruncate(lfd, 0);
8712111Sralph 	/*
8812111Sralph 	 * write process id for others to know
8912111Sralph 	 */
9012111Sralph 	sprintf(line, "%u\n", pid);
9112111Sralph 	pidoff = i = strlen(line);
9212463Sralph 	if (write(lfd, line, i) != i) {
9312111Sralph 		log("cannot write daemon pid");
9412111Sralph 		exit(1);
9512111Sralph 	}
9612111Sralph 	/*
9712111Sralph 	 * search the spool directory for work and sort by queue order.
9812111Sralph 	 */
9912111Sralph 	if ((nitems = getq(&queue)) < 0) {
10012111Sralph 		log("can't scan spool directory %s", SD);
10112111Sralph 		exit(1);
10212111Sralph 	}
10312463Sralph 	if (nitems == 0)		/* no work to do */
10412111Sralph 		exit(0);
10513169Sralph 	if (stb.st_mode & 01) {		/* reset queue flag */
10613169Sralph 		if (fchmod(lfd, stb.st_mode & 0776) < 0)
10713169Sralph 			log("cannot chmod %s", LO);
10813169Sralph 	}
10912463Sralph 	openpr();			/* open printer or remote */
11012463Sralph again:
11112111Sralph 	/*
11212111Sralph 	 * we found something to do now do it --
11312111Sralph 	 *    write the name of the current control file into the lock file
11412111Sralph 	 *    so the spool queue program can tell what we're working on
11512111Sralph 	 */
11612111Sralph 	for (qp = queue; nitems--; free((char *) q)) {
11712111Sralph 		q = *qp++;
11812111Sralph 		if (stat(q->q_name, &stb) < 0)
11912111Sralph 			continue;
12012463Sralph 	restart:
12112111Sralph 		(void) lseek(lfd, pidoff, 0);
12212111Sralph 		(void) sprintf(line, "%s\n", q->q_name);
12312111Sralph 		i = strlen(line);
12412111Sralph 		if (write(lfd, line, i) != i)
12512111Sralph 			log("can't write (%d) control file name", errno);
12612111Sralph 		if (!remote)
12712111Sralph 			i = printit(q->q_name);
12812111Sralph 		else
12912111Sralph 			i = sendit(q->q_name);
13012463Sralph 		/*
13113169Sralph 		 * Check to see if we are supposed to stop printing or
13213169Sralph 		 * if we are to rebuild the queue.
13312463Sralph 		 */
13413169Sralph 		if (fstat(lfd, &stb) == 0) {
13513169Sralph 			if (stb.st_mode & 0100)
13613169Sralph 				goto done;
13713169Sralph 			if (stb.st_mode & 01) {
13813169Sralph 				for (free((char *) q); nitems--; free((char *) q))
13913169Sralph 					q = *qp++;
14013169Sralph 				if (fchmod(lfd, stb.st_mode & 0776) < 0)
14113169Sralph 					log("cannot chmod %s", LO);
14213169Sralph 				break;
14313169Sralph 			}
14413169Sralph 		}
14514150Sralph 		if (i == 0)		/* file ok and printed */
14614150Sralph 			count++;
14714150Sralph 		else if (i > 0) {	/* try reprinting the job */
14812111Sralph 			log("restarting");
14912111Sralph 			if (ofilter > 0) {
15012111Sralph 				kill(ofilter, SIGCONT);	/* to be sure */
15112111Sralph 				(void) close(ofd);
15212111Sralph 				while ((i = wait(0)) > 0 && i != ofilter)
15312111Sralph 					;
15412111Sralph 				ofilter = 0;
15512111Sralph 			}
15612463Sralph 			(void) close(pfd);	/* close printer */
157*15811Sralph 			if (ftruncate(lfd, pidoff) < 0)
158*15811Sralph 				log("can't truncate lock file (%d)", errno);
15912463Sralph 			openpr();		/* try to reopen printer */
16012111Sralph 			goto restart;
16112111Sralph 		}
16212111Sralph 	}
16312111Sralph 	free((char *) queue);
16412463Sralph 	/*
16512463Sralph 	 * search the spool directory for more work.
16612463Sralph 	 */
16712463Sralph 	if ((nitems = getq(&queue)) < 0) {
16812463Sralph 		log("can't scan spool directory %s", SD);
16912463Sralph 		exit(1);
17012463Sralph 	}
17112463Sralph 	if (nitems == 0) {		/* no more work to do */
17212463Sralph 	done:
17314150Sralph 		if (count > 0) {	/* Files actually printed */
17414150Sralph 			if (!SF && !tof)
17514150Sralph 				(void) write(ofd, FF, strlen(FF));
17614150Sralph 			if (TR != NULL)		/* output trailer */
17714150Sralph 				(void) write(ofd, TR, strlen(TR));
17814150Sralph 		}
179*15811Sralph 		(void) unlink(tmpfile);
18012463Sralph 		exit(0);
18112463Sralph 	}
18212111Sralph 	goto again;
18312111Sralph }
18412111Sralph 
18512111Sralph char	fonts[4][50];	/* fonts for troff */
18612111Sralph 
18712111Sralph static char ifonts[4][18] = {
18812111Sralph 	"/usr/lib/vfont/R",
18912111Sralph 	"/usr/lib/vfont/I",
19012111Sralph 	"/usr/lib/vfont/B",
19112111Sralph 	"/usr/lib/vfont/S"
19212111Sralph };
19312111Sralph 
19412111Sralph /*
19512111Sralph  * The remaining part is the reading of the control file (cf)
19612111Sralph  * and performing the various actions.
19712111Sralph  * Returns 0 if everthing was OK, 1 if we should try to reprint the job and
19812111Sralph  * -1 if a non-recoverable error occured.
19912111Sralph  */
20012877Sralph static
20112111Sralph printit(file)
20212111Sralph 	char *file;
20312111Sralph {
20412111Sralph 	register int i;
20512111Sralph 	int bombed = 0;
20612111Sralph 
20712111Sralph 	/*
20812111Sralph 	 * open control file
20912111Sralph 	 */
21012111Sralph 	if ((cfp = fopen(file, "r")) == NULL) {
21112111Sralph 		log("control file (%s) open failure <errno = %d>", file, errno);
21212111Sralph 		return(0);
21312111Sralph 	}
21412111Sralph 	/*
21512111Sralph 	 * Reset troff fonts.
21612111Sralph 	 */
21712111Sralph 	for (i = 0; i < 4; i++)
21812111Sralph 		strcpy(fonts[i], ifonts[i]);
21912111Sralph 
22012111Sralph 	/*
22112111Sralph 	 *      read the control file for work to do
22212111Sralph 	 *
22312111Sralph 	 *      file format -- first character in the line is a command
22412111Sralph 	 *      rest of the line is the argument.
22512111Sralph 	 *      valid commands are:
22612111Sralph 	 *
22712111Sralph 	 *		J -- "job name" on banner page
22812111Sralph 	 *		C -- "class name" on banner page
22912111Sralph 	 *              L -- "literal" user's name to print on banner
23012111Sralph 	 *		T -- "title" for pr
23112111Sralph 	 *		H -- "host name" of machine where lpr was done
23212111Sralph 	 *              P -- "person" user's login name
23312581Sralph 	 *              I -- "indent" amount to indent output
23412111Sralph 	 *              f -- "file name" name of text file to print
23512111Sralph 	 *		l -- "file name" text file with control chars
23612111Sralph 	 *		p -- "file name" text file to print with pr(1)
23712111Sralph 	 *		t -- "file name" troff(1) file to print
23813233Sralph 	 *		n -- "file name" ditroff(1) file to print
23912111Sralph 	 *		d -- "file name" dvi file to print
24012111Sralph 	 *		g -- "file name" plot(1G) file to print
24112111Sralph 	 *		v -- "file name" plain raster file to print
24212111Sralph 	 *		c -- "file name" cifplot file to print
24312111Sralph 	 *		1 -- "R font file" for troff
24412111Sralph 	 *		2 -- "I font file" for troff
24512111Sralph 	 *		3 -- "B font file" for troff
24612111Sralph 	 *		4 -- "S font file" for troff
24712111Sralph 	 *		N -- "name" of file (used by lpq)
24812111Sralph 	 *              U -- "unlink" name of file to remove
24912111Sralph 	 *                    (after we print it. (Pass 2 only)).
25012111Sralph 	 *		M -- "mail" to user when done printing
25112111Sralph 	 *
25212111Sralph 	 *      getline reads a line and expands tabs to blanks
25312111Sralph 	 */
25412111Sralph 
25512111Sralph 	/* pass 1 */
25612111Sralph 
25712111Sralph 	while (getline(cfp))
25812111Sralph 		switch (line[0]) {
25912111Sralph 		case 'H':
26014150Sralph 			strcpy(fromhost, line+1);
26112111Sralph 			if (class[0] == '\0')
26215552Sralph 				strncpy(class, line+1, sizeof(class)-1);
26312111Sralph 			continue;
26412111Sralph 
26512111Sralph 		case 'P':
26615552Sralph 			strncpy(logname, line+1, sizeof(logname)-1);
26712463Sralph 			if (RS) {			/* restricted */
26812463Sralph 				if (getpwnam(logname) == (struct passwd *)0) {
26912463Sralph 					bombed = 2;
270*15811Sralph 					sendmail(line+1, bombed);
27112463Sralph 					goto pass2;
27212463Sralph 				}
27312463Sralph 			}
27412111Sralph 			continue;
27512111Sralph 
27612111Sralph 		case 'J':
27712111Sralph 			if (line[1] != '\0')
27815552Sralph 				strncpy(jobname, line+1, sizeof(jobname)-1);
27912111Sralph 			else
28012111Sralph 				strcpy(jobname, " ");
28112111Sralph 			continue;
28212111Sralph 
28312111Sralph 		case 'C':
28412111Sralph 			if (line[1] != '\0')
28515552Sralph 				strncpy(class, line+1, sizeof(class)-1);
28612111Sralph 			else if (class[0] == '\0')
287*15811Sralph 				gethostname(class, sizeof(class));
28812111Sralph 			continue;
28912111Sralph 
29012111Sralph 		case 'T':	/* header title for pr */
29115552Sralph 			strncpy(title, line+1, sizeof(title)-1);
29212111Sralph 			continue;
29312111Sralph 
29412111Sralph 		case 'L':	/* identification line */
29512111Sralph 			if (!SH)
29612111Sralph 				banner(line+1, jobname);
29712111Sralph 			continue;
29812111Sralph 
29912111Sralph 		case '1':	/* troff fonts */
30012111Sralph 		case '2':
30112111Sralph 		case '3':
30212111Sralph 		case '4':
30312111Sralph 			if (line[1] != '\0')
30412111Sralph 				strcpy(fonts[line[0]-'1'], line+1);
30512111Sralph 			continue;
30612111Sralph 
30712111Sralph 		case 'W':	/* page width */
30815552Sralph 			strncpy(width+2, line+1, sizeof(width)-3);
30912111Sralph 			continue;
31012111Sralph 
31112581Sralph 		case 'I':	/* indent amount */
31215552Sralph 			strncpy(indent+2, line+1, sizeof(indent)-3);
31312581Sralph 			continue;
31412581Sralph 
31512111Sralph 		default:	/* some file to print */
316*15811Sralph 			switch (i = print(line[0], line+1)) {
317*15811Sralph 			case -1:
318*15811Sralph 				if (!bombed)
319*15811Sralph 					bombed = 1;
320*15811Sralph 				break;
321*15811Sralph 			case 1:
32212111Sralph 				(void) fclose(cfp);
32312111Sralph 				return(1);
324*15811Sralph 			case 2:
325*15811Sralph 				bombed = 3;
326*15811Sralph 				sendmail(logname, bombed);
327*15811Sralph 			}
32812111Sralph 			title[0] = '\0';
32912111Sralph 			continue;
33012111Sralph 
33112111Sralph 		case 'N':
33212111Sralph 		case 'U':
33312111Sralph 		case 'M':
33412111Sralph 			continue;
33512111Sralph 		}
33612111Sralph 
33712111Sralph 	/* pass 2 */
33812111Sralph 
33912463Sralph pass2:
34012111Sralph 	fseek(cfp, 0L, 0);
34112111Sralph 	while (getline(cfp))
34212111Sralph 		switch (line[0]) {
34312111Sralph 		case 'M':
344*15811Sralph 			if (bombed < 2)		/* already sent if >= 2 */
345*15811Sralph 				sendmail(line+1, bombed);
34612111Sralph 			continue;
34712111Sralph 
34812111Sralph 		case 'U':
34912111Sralph 			(void) unlink(line+1);
35012111Sralph 		}
35112111Sralph 	/*
352*15811Sralph 	 * clean-up in case another control file exists
35312111Sralph 	 */
35412111Sralph 	(void) fclose(cfp);
35512111Sralph 	(void) unlink(file);
35614150Sralph 	return(bombed ? -1 : 0);
35712111Sralph }
35812111Sralph 
35912111Sralph /*
36012111Sralph  * Print a file.
36113233Sralph  * Set up the chain [ PR [ | {IF, OF} ] ] or {IF, RF, TF, NF, DF, CF, VF}.
362*15811Sralph  * Return -1 if a non-recoverable error occured,
363*15811Sralph  * 2 if the filter detected some errors (but printed the job anyway),
364*15811Sralph  * 1 if we should try to reprint this job and
36512111Sralph  * 0 if all is well.
36612111Sralph  * Note: all filters take stdin as the file, stdout as the printer,
36712111Sralph  * stderr as the log file, and must not ignore SIGINT.
36812111Sralph  */
36912877Sralph static
37012111Sralph print(format, file)
37112111Sralph 	int format;
37212111Sralph 	char *file;
37312111Sralph {
374*15811Sralph 	register int n;
37512111Sralph 	register char *prog;
376*15811Sralph 	int fi, fo;
37712111Sralph 	char *av[15], buf[BUFSIZ];
37812111Sralph 	int pid, p[2], stopped = 0;
37912111Sralph 	union wait status;
38012111Sralph 
38113148Ssam 	if ((fi = open(file, O_RDONLY)) < 0) {
38212111Sralph 		log("%s: open failure <errno = %d>", file, errno);
38312111Sralph 		return(-1);
38412111Sralph 	}
38512111Sralph 	if (!SF && !tof) {		/* start on a fresh page */
38612111Sralph 		(void) write(ofd, FF, strlen(FF));
38712111Sralph 		tof = 1;
38812111Sralph 	}
38912111Sralph 	if (IF == NULL && (format == 'f' || format == 'l')) {
39012111Sralph 		tof = 0;
39112111Sralph 		while ((n = read(fi, buf, BUFSIZ)) > 0)
39212111Sralph 			if (write(ofd, buf, n) != n) {
39312111Sralph 				(void) close(fi);
39412111Sralph 				return(1);
39512111Sralph 			}
39612111Sralph 		(void) close(fi);
39712111Sralph 		return(0);
39812111Sralph 	}
39912111Sralph 	switch (format) {
40012111Sralph 	case 'p':	/* print file using 'pr' */
40112111Sralph 		if (IF == NULL) {	/* use output filter */
40212111Sralph 			prog = PR;
40312111Sralph 			av[0] = "pr";
40412111Sralph 			av[1] = width;
40512111Sralph 			av[2] = length;
40612111Sralph 			av[3] = "-h";
40712111Sralph 			av[4] = *title ? title : " ";
40812111Sralph 			av[5] = 0;
40912111Sralph 			fo = ofd;
41012111Sralph 			goto start;
41112111Sralph 		}
41212111Sralph 		pipe(p);
41312111Sralph 		if ((prchild = dofork(DORETURN)) == 0) {	/* child */
41412111Sralph 			dup2(fi, 0);		/* file is stdin */
41512111Sralph 			dup2(p[1], 1);		/* pipe is stdout */
41612111Sralph 			for (n = 3; n < NOFILE; n++)
41712111Sralph 				(void) close(n);
41812111Sralph 			execl(PR, "pr", width, length, "-h", *title ? title : " ", 0);
41912111Sralph 			log("cannot execl %s", PR);
42012111Sralph 			exit(2);
42112111Sralph 		}
42212111Sralph 		(void) close(p[1]);		/* close output side */
42312111Sralph 		(void) close(fi);
42412111Sralph 		if (prchild < 0) {
42512111Sralph 			prchild = 0;
42612111Sralph 			(void) close(p[0]);
42712111Sralph 			return(-1);
42812111Sralph 		}
42912111Sralph 		fi = p[0];			/* use pipe for input */
43012111Sralph 	case 'f':	/* print plain text file */
43112111Sralph 		prog = IF;
43212111Sralph 		av[1] = width;
43312111Sralph 		av[2] = length;
43412581Sralph 		av[3] = indent;
43512581Sralph 		n = 4;
43612111Sralph 		break;
43712111Sralph 	case 'l':	/* like 'f' but pass control characters */
43812111Sralph 		prog = IF;
43914325Sralph 		av[1] = "-c";
44012111Sralph 		av[2] = width;
44112111Sralph 		av[3] = length;
44212581Sralph 		av[4] = indent;
44312581Sralph 		n = 5;
44412111Sralph 		break;
44512463Sralph 	case 'r':	/* print a fortran text file */
44612463Sralph 		prog = RF;
44712463Sralph 		av[1] = width;
44812463Sralph 		av[2] = length;
44912463Sralph 		n = 3;
45012463Sralph 		break;
45112111Sralph 	case 't':	/* print troff output */
45213233Sralph 	case 'n':	/* print ditroff output */
45312463Sralph 	case 'd':	/* print tex output */
45412111Sralph 		(void) unlink(".railmag");
45512463Sralph 		if ((fo = creat(".railmag", FILMOD)) < 0) {
45612111Sralph 			log("cannot create .railmag");
45712111Sralph 			(void) unlink(".railmag");
45812111Sralph 		} else {
45912111Sralph 			for (n = 0; n < 4; n++) {
46012111Sralph 				if (fonts[n][0] != '/')
46112111Sralph 					(void) write(fo, "/usr/lib/vfont/", 15);
46212111Sralph 				(void) write(fo, fonts[n], strlen(fonts[n]));
46312111Sralph 				(void) write(fo, "\n", 1);
46412111Sralph 			}
46512111Sralph 			(void) close(fo);
46612111Sralph 		}
46713233Sralph 		prog = (format == 't') ? TF : (format == 'n') ? NF : DF;
46812463Sralph 		av[1] = pxwidth;
46912463Sralph 		av[2] = pxlength;
47012463Sralph 		n = 3;
47112111Sralph 		break;
47212111Sralph 	case 'c':	/* print cifplot output */
47312111Sralph 		prog = CF;
47412463Sralph 		av[1] = pxwidth;
47512463Sralph 		av[2] = pxlength;
47612463Sralph 		n = 3;
47712111Sralph 		break;
47812111Sralph 	case 'g':	/* print plot(1G) output */
47912111Sralph 		prog = GF;
48012463Sralph 		av[1] = pxwidth;
48112463Sralph 		av[2] = pxlength;
48212463Sralph 		n = 3;
48312111Sralph 		break;
48412111Sralph 	case 'v':	/* print raster output */
48512111Sralph 		prog = VF;
48612463Sralph 		av[1] = pxwidth;
48712463Sralph 		av[2] = pxlength;
48812463Sralph 		n = 3;
48912111Sralph 		break;
49012111Sralph 	default:
49112111Sralph 		(void) close(fi);
49212111Sralph 		log("illegal format character '%c'", format);
49312111Sralph 		return(-1);
49412111Sralph 	}
49512111Sralph 	if ((av[0] = rindex(prog, '/')) != NULL)
49612111Sralph 		av[0]++;
49712111Sralph 	else
49812111Sralph 		av[0] = prog;
49912111Sralph 	av[n++] = "-n";
50012111Sralph 	av[n++] = logname;
50112111Sralph 	av[n++] = "-h";
50214150Sralph 	av[n++] = fromhost;
50312111Sralph 	av[n++] = AF;
50412111Sralph 	av[n] = 0;
50512111Sralph 	fo = pfd;
50612111Sralph 	if (ofilter > 0) {		/* stop output filter */
50712111Sralph 		write(ofd, "\031\1", 2);
50812111Sralph 		while ((pid = wait3(&status, WUNTRACED, 0)) > 0 && pid != ofilter)
50912111Sralph 			;
51012111Sralph 		if (status.w_stopval != WSTOPPED) {
51112111Sralph 			(void) close(fi);
51212111Sralph 			log("output filter died (%d)", status.w_retcode);
51312111Sralph 			return(1);
51412111Sralph 		}
51512111Sralph 		stopped++;
51612111Sralph 	}
51712111Sralph start:
51812111Sralph 	if ((child = dofork(DORETURN)) == 0) {	/* child */
51912111Sralph 		dup2(fi, 0);
52012111Sralph 		dup2(fo, 1);
521*15811Sralph 		n = open(tmpfile, O_WRONLY|O_CREAT, 0664);
522*15811Sralph 		if (n >= 0)
523*15811Sralph 			dup2(n, 2);
52412111Sralph 		for (n = 3; n < NOFILE; n++)
52512111Sralph 			(void) close(n);
52612111Sralph 		execv(prog, av);
52712111Sralph 		log("cannot execl %s", prog);
52812111Sralph 		exit(2);
52912111Sralph 	}
53012111Sralph 	(void) close(fi);
53112111Sralph 	if (child < 0)
53212111Sralph 		status.w_retcode = 100;
53312111Sralph 	else
53412111Sralph 		while ((pid = wait(&status)) > 0 && pid != child)
53512111Sralph 			;
53612111Sralph 	child = 0;
53712111Sralph 	prchild = 0;
53812111Sralph 	if (stopped) {		/* restart output filter */
53912111Sralph 		if (kill(ofilter, SIGCONT) < 0) {
54012111Sralph 			log("cannot restart output filter");
54112111Sralph 			exit(1);
54212111Sralph 		}
54312111Sralph 	}
54412111Sralph 	tof = 0;
545*15811Sralph 	if (!WIFEXITED(status)) {
546*15811Sralph 		log("Daemon filter '%c' terminated (%d)", format, status.w_termsig);
54712111Sralph 		return(-1);
548*15811Sralph 	} else if (status.w_retcode > 2) {
549*15811Sralph 		log("Daemon filter '%c' exited (%d)", format, status.w_retcode);
550*15811Sralph 		return(-1);
551*15811Sralph 	} else if (status.w_retcode == 0)
552*15811Sralph 		tof = 1;
553*15811Sralph 	return(status.w_retcode);
55412111Sralph }
55512111Sralph 
55612111Sralph /*
55712111Sralph  * Send the daemon control file (cf) and any data files.
55812111Sralph  * Return -1 if a non-recoverable error occured, 1 if a recoverable error and
55912111Sralph  * 0 if all is well.
56012111Sralph  */
56112877Sralph static
56212111Sralph sendit(file)
56312111Sralph 	char *file;
56412111Sralph {
56512111Sralph 	register int linelen, err = 0;
56612111Sralph 	char last[132];
56712111Sralph 
56812111Sralph 	/*
56912111Sralph 	 * open control file
57012111Sralph 	 */
57112111Sralph 	if ((cfp = fopen(file, "r")) == NULL) {
57212111Sralph 		log("control file (%s) open failure <errno = %d>", file, errno);
57312111Sralph 		return(0);
57412111Sralph 	}
57512111Sralph 	/*
57612111Sralph 	 *      read the control file for work to do
57712111Sralph 	 *
57812111Sralph 	 *      file format -- first character in the line is a command
57912111Sralph 	 *      rest of the line is the argument.
58012111Sralph 	 *      commands of interest are:
58112111Sralph 	 *
58212111Sralph 	 *            a-z -- "file name" name of file to print
58312111Sralph 	 *              U -- "unlink" name of file to remove
58412111Sralph 	 *                    (after we print it. (Pass 2 only)).
58512111Sralph 	 */
58612111Sralph 
58712111Sralph 	/*
58812111Sralph 	 * pass 1
58912111Sralph 	 */
59012111Sralph 	while (getline(cfp)) {
59112111Sralph 	again:
59212111Sralph 		if (line[0] >= 'a' && line[0] <= 'z') {
59312111Sralph 			strcpy(last, line);
59412111Sralph 			while (linelen = getline(cfp))
59512111Sralph 				if (strcmp(last, line))
59612111Sralph 					break;
59712111Sralph 			if ((err = sendfile('\3', last+1)) > 0) {
59812111Sralph 				(void) fclose(cfp);
59912111Sralph 				return(1);
60012111Sralph 			} else if (err)
60112111Sralph 				break;
60212111Sralph 			if (linelen)
60312111Sralph 				goto again;
60412111Sralph 			break;
60512111Sralph 		}
60612111Sralph 	}
60712111Sralph 	if (!err && sendfile('\2', file) > 0) {
60812111Sralph 		(void) fclose(cfp);
60912111Sralph 		return(1);
61012111Sralph 	}
61112111Sralph 	/*
61212111Sralph 	 * pass 2
61312111Sralph 	 */
61412111Sralph 	fseek(cfp, 0L, 0);
61512111Sralph 	while (getline(cfp))
61612111Sralph 		if (line[0] == 'U')
61712111Sralph 			(void) unlink(line+1);
61812111Sralph 	/*
61912111Sralph 	 * clean-up incase another control file exists
62012111Sralph 	 */
62112111Sralph 	(void) fclose(cfp);
62212111Sralph 	(void) unlink(file);
62312111Sralph 	return(0);
62412111Sralph }
62512111Sralph 
62612111Sralph /*
62712111Sralph  * Send a data file to the remote machine and spool it.
62812111Sralph  * Return positive if we should try resending.
62912111Sralph  */
63012877Sralph static
63112111Sralph sendfile(type, file)
63212111Sralph 	char type, *file;
63312111Sralph {
63412111Sralph 	register int f, i, amt;
63512111Sralph 	struct stat stb;
63612111Sralph 	char buf[BUFSIZ];
63712111Sralph 	int sizerr;
63812111Sralph 
63913148Ssam 	if ((f = open(file, O_RDONLY)) < 0 || fstat(f, &stb) < 0) {
64012111Sralph 		log("file (%s) open failure <errno = %d>", file, errno);
64112111Sralph 		return(-1);
64212111Sralph 	}
64312111Sralph 	(void) sprintf(buf, "%c%d %s\n", type, stb.st_size, file);
64412111Sralph 	amt = strlen(buf);
64512692Sralph 	if (write(pfd, buf, amt) != amt) {
64612692Sralph 		(void) close(f);
64712111Sralph 		return(1);
64812692Sralph 	}
64912692Sralph 	if (noresponse()) {
65012692Sralph 		(void) close(f);
65112111Sralph 		return(1);
65212692Sralph 	}
65312111Sralph 	sizerr = 0;
65412111Sralph 	for (i = 0; i < stb.st_size; i += BUFSIZ) {
65512111Sralph 		amt = BUFSIZ;
65612111Sralph 		if (i + amt > stb.st_size)
65712111Sralph 			amt = stb.st_size - i;
65812111Sralph 		if (sizerr == 0 && read(f, buf, amt) != amt)
65912111Sralph 			sizerr = 1;
66012692Sralph 		if (write(pfd, buf, amt) != amt) {
66112692Sralph 			(void) close(f);
66212111Sralph 			return(1);
66312692Sralph 		}
66412111Sralph 	}
66512111Sralph 	(void) close(f);
66612111Sralph 	if (sizerr) {
66712111Sralph 		log("%s: changed size", file);
66812111Sralph 		(void) write(pfd, "\1", 1);  /* tell recvjob to ignore this file */
66912111Sralph 		return(-1);
67012111Sralph 	}
67112111Sralph 	if (write(pfd, "", 1) != 1)
67212111Sralph 		return(1);
67312111Sralph 	if (noresponse())
67412111Sralph 		return(1);
67512111Sralph 	return(0);
67612111Sralph }
67712111Sralph 
67812111Sralph /*
67912111Sralph  * Check to make sure there have been no errors and that both programs
68012111Sralph  * are in sync with eachother.
68112111Sralph  * Return non-zero if the connection was lost.
68212111Sralph  */
68312111Sralph static
68412111Sralph noresponse()
68512111Sralph {
68612111Sralph 	char resp;
68712111Sralph 
68812111Sralph 	if (read(pfd, &resp, 1) != 1 || resp != '\0') {
68912111Sralph 		log("lost connection or error in recvjob");
69012111Sralph 		return(1);
69112111Sralph 	}
69212111Sralph 	return(0);
69312111Sralph }
69412111Sralph 
69512111Sralph /*
69612111Sralph  * Banner printing stuff
69712111Sralph  */
69812877Sralph static
69912111Sralph banner(name1, name2)
70012111Sralph 	char *name1, *name2;
70112111Sralph {
70212111Sralph 	time_t tvec;
70312111Sralph 	extern char *ctime();
70412111Sralph 
70512111Sralph 	time(&tvec);
70612111Sralph 	if (!SF && !tof)
70712111Sralph 		(void) write(ofd, FF, strlen(FF));
70812111Sralph 	if (SB) {	/* short banner only */
70912111Sralph 		if (class[0]) {
71012111Sralph 			(void) write(ofd, class, strlen(class));
71112111Sralph 			(void) write(ofd, ":", 1);
71212111Sralph 		}
71312111Sralph 		(void) write(ofd, name1, strlen(name1));
71412111Sralph 		(void) write(ofd, "  Job: ", 7);
71512111Sralph 		(void) write(ofd, name2, strlen(name2));
71612111Sralph 		(void) write(ofd, "  Date: ", 8);
71712111Sralph 		(void) write(ofd, ctime(&tvec), 24);
71812111Sralph 		(void) write(ofd, "\n", 1);
71912111Sralph 	} else {	/* normal banner */
72012111Sralph 		(void) write(ofd, "\n\n\n", 3);
72112111Sralph 		scan_out(ofd, name1, '\0');
72212111Sralph 		(void) write(ofd, "\n\n", 2);
72312111Sralph 		scan_out(ofd, name2, '\0');
72412111Sralph 		if (class[0]) {
72512111Sralph 			(void) write(ofd,"\n\n\n",3);
72612111Sralph 			scan_out(ofd, class, '\0');
72712111Sralph 		}
72812111Sralph 		(void) write(ofd, "\n\n\n\n\t\t\t\t\tJob:  ", 15);
72912111Sralph 		(void) write(ofd, name2, strlen(name2));
73012111Sralph 		(void) write(ofd, "\n\t\t\t\t\tDate: ", 12);
73112111Sralph 		(void) write(ofd, ctime(&tvec), 24);
73212111Sralph 		(void) write(ofd, "\n", 1);
73312111Sralph 	}
73412111Sralph 	if (!SF)
73512111Sralph 		(void) write(ofd, FF, strlen(FF));
73612111Sralph 	tof = 1;
73712111Sralph }
73812111Sralph 
73912877Sralph static char *
74012111Sralph scnline(key, p, c)
74112111Sralph 	register char key, *p;
74212111Sralph 	char c;
74312111Sralph {
74412111Sralph 	register scnwidth;
74512111Sralph 
74612111Sralph 	for (scnwidth = WIDTH; --scnwidth;) {
74712111Sralph 		key <<= 1;
74812111Sralph 		*p++ = key & 0200 ? c : BACKGND;
74912111Sralph 	}
75012111Sralph 	return (p);
75112111Sralph }
75212111Sralph 
75312111Sralph #define TRC(q)	(((q)-' ')&0177)
75412111Sralph 
75512877Sralph static
75612111Sralph scan_out(scfd, scsp, dlm)
75712111Sralph 	int scfd;
75812111Sralph 	char *scsp, dlm;
75912111Sralph {
76012111Sralph 	register char *strp;
76112111Sralph 	register nchrs, j;
76212111Sralph 	char outbuf[LINELEN+1], *sp, c, cc;
76312111Sralph 	int d, scnhgt;
76412111Sralph 	extern char scnkey[][HEIGHT];	/* in lpdchar.c */
76512111Sralph 
76612111Sralph 	for (scnhgt = 0; scnhgt++ < HEIGHT+DROP; ) {
76712111Sralph 		strp = &outbuf[0];
76812111Sralph 		sp = scsp;
76912111Sralph 		for (nchrs = 0; ; ) {
77012111Sralph 			d = dropit(c = TRC(cc = *sp++));
77112111Sralph 			if ((!d && scnhgt > HEIGHT) || (scnhgt <= DROP && d))
77212111Sralph 				for (j = WIDTH; --j;)
77312111Sralph 					*strp++ = BACKGND;
77412111Sralph 			else
77512111Sralph 				strp = scnline(scnkey[c][scnhgt-1-d], strp, cc);
77612111Sralph 			if (*sp == dlm || *sp == '\0' || nchrs++ >= PW/(WIDTH+1)-1)
77712111Sralph 				break;
77812111Sralph 			*strp++ = BACKGND;
77912111Sralph 			*strp++ = BACKGND;
78012111Sralph 		}
78112111Sralph 		while (*--strp == BACKGND && strp >= outbuf)
78212111Sralph 			;
78312111Sralph 		strp++;
78412111Sralph 		*strp++ = '\n';
78512111Sralph 		(void) write(scfd, outbuf, strp-outbuf);
78612111Sralph 	}
78712111Sralph }
78812111Sralph 
78912877Sralph static
79012111Sralph dropit(c)
79112111Sralph 	char c;
79212111Sralph {
79312111Sralph 	switch(c) {
79412111Sralph 
79512111Sralph 	case TRC('_'):
79612111Sralph 	case TRC(';'):
79712111Sralph 	case TRC(','):
79812111Sralph 	case TRC('g'):
79912111Sralph 	case TRC('j'):
80012111Sralph 	case TRC('p'):
80112111Sralph 	case TRC('q'):
80212111Sralph 	case TRC('y'):
80312111Sralph 		return (DROP);
80412111Sralph 
80512111Sralph 	default:
80612111Sralph 		return (0);
80712111Sralph 	}
80812111Sralph }
80912111Sralph 
81012111Sralph /*
81112111Sralph  * sendmail ---
81212111Sralph  *   tell people about job completion
81312111Sralph  */
81412877Sralph static
815*15811Sralph sendmail(user, bombed)
816*15811Sralph 	char *user;
81712111Sralph 	int bombed;
81812111Sralph {
81912111Sralph 	register int i;
820*15811Sralph 	int p[2], s;
82112111Sralph 	register char *cp;
82212111Sralph 	char buf[100];
823*15811Sralph 	struct stat stb;
824*15811Sralph 	FILE *fp;
82512111Sralph 
82612111Sralph 	pipe(p);
827*15811Sralph 	if ((s = dofork(DORETURN)) == 0) {		/* child */
82812111Sralph 		dup2(p[0], 0);
82912111Sralph 		for (i = 3; i < NOFILE; i++)
83012111Sralph 			(void) close(i);
83112111Sralph 		if ((cp = rindex(MAIL, '/')) != NULL)
83212111Sralph 			cp++;
83312111Sralph 		else
83412111Sralph 			cp = MAIL;
835*15811Sralph 		sprintf(buf, "%s@%s", user, fromhost);
83612111Sralph 		execl(MAIL, cp, buf, 0);
83712111Sralph 		exit(0);
838*15811Sralph 	} else if (s > 0) {				/* parent */
83912111Sralph 		dup2(p[1], 1);
840*15811Sralph 		printf("To: %s@%s\n", user, fromhost);
84112111Sralph 		printf("Subject: printer job\n\n");
84212111Sralph 		printf("Your printer job ");
84312111Sralph 		if (*jobname)
84412111Sralph 			printf("(%s) ", jobname);
84512463Sralph 		switch (bombed) {
84612463Sralph 		case 0:
84712463Sralph 			printf("\ncompleted successfully\n");
84812463Sralph 			break;
84912463Sralph 		default:
85012463Sralph 		case 1:
85112463Sralph 			printf("\ncould not be printed\n");
85212463Sralph 			break;
85312463Sralph 		case 2:
85412463Sralph 			printf("\ncould not be printed without an account on %s\n", host);
85512463Sralph 			break;
856*15811Sralph 		case 3:
857*15811Sralph 			if (stat(tmpfile, &stb) < 0 || stb.st_size == 0 ||
858*15811Sralph 			    (fp = fopen(tmpfile, "r")) == NULL) {
859*15811Sralph 				printf("\nwas printed but had some errors\n");
860*15811Sralph 				break;
861*15811Sralph 			}
862*15811Sralph 			printf("\nwas printed but had the following errors:\n");
863*15811Sralph 			while ((i = getc(fp)) != EOF)
864*15811Sralph 				putchar(i);
865*15811Sralph 			(void) fclose(fp);
86612463Sralph 		}
86712111Sralph 		fflush(stdout);
86812111Sralph 		(void) close(1);
86912111Sralph 	}
87012111Sralph 	(void) close(p[0]);
87112111Sralph 	(void) close(p[1]);
872*15811Sralph 	wait(&s);
87312111Sralph }
87412111Sralph 
87512111Sralph /*
87612111Sralph  * dofork - fork with retries on failure
87712111Sralph  */
87812877Sralph static
87912111Sralph dofork(action)
88012111Sralph 	int action;
88112111Sralph {
88212111Sralph 	register int i, pid;
88312111Sralph 
88412111Sralph 	for (i = 0; i < 20; i++) {
88512463Sralph 		if ((pid = fork()) < 0) {
88612111Sralph 			sleep((unsigned)(i*i));
88712463Sralph 			continue;
88812463Sralph 		}
88912463Sralph 		/*
89012463Sralph 		 * Child should run as daemon instead of root
89112463Sralph 		 */
89212463Sralph 		if (pid == 0)
89312463Sralph 			setuid(DU);
89412463Sralph 		return(pid);
89512111Sralph 	}
89612111Sralph 	log("can't fork");
89712111Sralph 
89812111Sralph 	switch (action) {
89912111Sralph 	case DORETURN:
90012111Sralph 		return (-1);
90112111Sralph 	default:
90212111Sralph 		log("bad action (%d) to dofork", action);
90312111Sralph 		/*FALL THRU*/
90412111Sralph 	case DOABORT:
90512111Sralph 		exit(1);
90612111Sralph 	}
90712111Sralph 	/*NOTREACHED*/
90812111Sralph }
90912111Sralph 
91012111Sralph /*
91114709Sralph  * Cleanup child processes when a signal is caught.
91212111Sralph  */
91312877Sralph static
91412111Sralph onintr()
91512111Sralph {
916*15811Sralph 	(void) unlink(tmpfile);
91712111Sralph 	kill(0, SIGINT);
91812111Sralph 	if (ofilter > 0)
91912111Sralph 		kill(ofilter, SIGCONT);
92012111Sralph 	while (wait(0) > 0)
92112111Sralph 		;
92212111Sralph 	exit(0);
92312111Sralph }
92412111Sralph 
92512877Sralph static
92612111Sralph init()
92712111Sralph {
92812111Sralph 	int status;
92912111Sralph 
93013169Sralph 	if ((status = pgetent(line, printer)) < 0)
93113169Sralph 		fatal("can't open printer description file");
93213169Sralph 	else if (status == 0)
93313169Sralph 		fatal("unknown printer");
93412111Sralph 	if ((LP = pgetstr("lp", &bp)) == NULL)
93512111Sralph 		LP = DEFDEVLP;
93612111Sralph 	if ((RP = pgetstr("rp", &bp)) == NULL)
93712463Sralph 		RP = DEFLP;
93812111Sralph 	if ((LO = pgetstr("lo", &bp)) == NULL)
93912111Sralph 		LO = DEFLOCK;
94012111Sralph 	if ((ST = pgetstr("st", &bp)) == NULL)
94112111Sralph 		ST = DEFSTAT;
94212111Sralph 	if ((LF = pgetstr("lf", &bp)) == NULL)
94312111Sralph 		LF = DEFLOGF;
94412111Sralph 	if ((SD = pgetstr("sd", &bp)) == NULL)
94512111Sralph 		SD = DEFSPOOL;
94612111Sralph 	if ((DU = pgetnum("du")) < 0)
94712111Sralph 		DU = DEFUID;
94812111Sralph 	if ((FF = pgetstr("ff", &bp)) == NULL)
94912111Sralph 		FF = DEFFF;
95012111Sralph 	if ((PW = pgetnum("pw")) < 0)
95112111Sralph 		PW = DEFWIDTH;
95212111Sralph 	sprintf(&width[2], "%d", PW);
95312111Sralph 	if ((PL = pgetnum("pl")) < 0)
95412111Sralph 		PL = DEFLENGTH;
95512111Sralph 	sprintf(&length[2], "%d", PL);
95612463Sralph 	if ((PX = pgetnum("px")) < 0)
95712463Sralph 		PX = 0;
95812463Sralph 	sprintf(&pxwidth[2], "%d", PX);
95912463Sralph 	if ((PY = pgetnum("py")) < 0)
96012463Sralph 		PY = 0;
96112463Sralph 	sprintf(&pxlength[2], "%d", PY);
96212111Sralph 	RM = pgetstr("rm", &bp);
96312111Sralph 	AF = pgetstr("af", &bp);
96412111Sralph 	OF = pgetstr("of", &bp);
96512111Sralph 	IF = pgetstr("if", &bp);
96612463Sralph 	RF = pgetstr("rf", &bp);
96712111Sralph 	TF = pgetstr("tf", &bp);
96813233Sralph 	NF = pgetstr("nf", &bp);
96912111Sralph 	DF = pgetstr("df", &bp);
97012111Sralph 	GF = pgetstr("gf", &bp);
97112111Sralph 	VF = pgetstr("vf", &bp);
97212111Sralph 	CF = pgetstr("cf", &bp);
97312111Sralph 	TR = pgetstr("tr", &bp);
97412463Sralph 	RS = pgetflag("rs");
97512111Sralph 	SF = pgetflag("sf");
97612111Sralph 	SH = pgetflag("sh");
97712111Sralph 	SB = pgetflag("sb");
97812111Sralph 	RW = pgetflag("rw");
97912111Sralph 	BR = pgetnum("br");
98012111Sralph 	if ((FC = pgetnum("fc")) < 0)
98112111Sralph 		FC = 0;
98212111Sralph 	if ((FS = pgetnum("fs")) < 0)
98312111Sralph 		FS = 0;
98412111Sralph 	if ((XC = pgetnum("xc")) < 0)
98512111Sralph 		XC = 0;
98612111Sralph 	if ((XS = pgetnum("xs")) < 0)
98712111Sralph 		XS = 0;
98812581Sralph 	tof = !pgetflag("fo");
98912111Sralph }
99012111Sralph 
99112463Sralph /*
99212463Sralph  * Acquire line printer or remote connection.
99312463Sralph  */
99412877Sralph static
99512463Sralph openpr()
99612463Sralph {
99712463Sralph 	register int i, n;
99812463Sralph 
99912463Sralph 	if (*LP) {
100012463Sralph 		for (i = 1; ; i = i < 32 ? i << 1 : i) {
100113148Ssam 			pfd = open(LP, RW ? O_RDWR : O_WRONLY);
100212463Sralph 			if (pfd >= 0)
100312463Sralph 				break;
100412463Sralph 			if (errno == ENOENT) {
100512463Sralph 				log("cannot open %s", LP);
100612463Sralph 				exit(1);
100712463Sralph 			}
100812463Sralph 			if (i == 1)
100912463Sralph 				status("waiting for %s to become ready (offline ?)", printer);
101012463Sralph 			sleep(i);
101112463Sralph 		}
101212463Sralph 		if (isatty(pfd))
101312463Sralph 			setty();
101412463Sralph 		status("%s is ready and printing", printer);
101512463Sralph 	} else if (RM != NULL) {
101612463Sralph 		for (i = 1; ; i = i < 512 ? i << 1 : i) {
101712528Sralph 			pfd = getport(RM);
101812463Sralph 			if (pfd >= 0) {
101912463Sralph 				(void) sprintf(line, "\2%s\n", RP);
102012463Sralph 				n = strlen(line);
102112463Sralph 				if (write(pfd, line, n) != n)
102212463Sralph 					break;
102312463Sralph 				if (noresponse())
102412463Sralph 					(void) close(pfd);
102512463Sralph 				else
102612463Sralph 					break;
102712463Sralph 			}
102812463Sralph 			if (i == 1)
102912463Sralph 				status("waiting for %s to come up", RM);
103012463Sralph 			sleep(i);
103112463Sralph 		}
103212463Sralph 		status("sending to %s", RM);
103312463Sralph 		remote = 1;
103412463Sralph 	} else {
103512463Sralph 		log("no line printer device or remote machine name");
103612463Sralph 		exit(1);
103712463Sralph 	}
103812463Sralph 	/*
103912463Sralph 	 * Start up an output filter, if needed.
104012463Sralph 	 */
104112463Sralph 	if (OF) {
104212463Sralph 		int p[2];
104312463Sralph 		char *cp;
104412463Sralph 
104512463Sralph 		pipe(p);
104612463Sralph 		if ((ofilter = dofork(DOABORT)) == 0) {	/* child */
104712463Sralph 			dup2(p[0], 0);		/* pipe is std in */
104812463Sralph 			dup2(pfd, 1);		/* printer is std out */
104912463Sralph 			for (i = 3; i < NOFILE; i++)
105012463Sralph 				(void) close(i);
105112463Sralph 			if ((cp = rindex(OF, '/')) == NULL)
105212463Sralph 				cp = OF;
105312463Sralph 			else
105412463Sralph 				cp++;
105512463Sralph 			execl(OF, cp, width, length, 0);
105612463Sralph 			log("can't execl output filter %s", OF);
105712463Sralph 			exit(1);
105812463Sralph 		}
105912463Sralph 		(void) close(p[0]);		/* close input side */
106012463Sralph 		ofd = p[1];			/* use pipe for output */
106112463Sralph 	} else {
106212463Sralph 		ofd = pfd;
106312463Sralph 		ofilter = 0;
106412463Sralph 	}
106512463Sralph }
106612463Sralph 
106712111Sralph struct bauds {
106812111Sralph 	int	baud;
106912111Sralph 	int	speed;
107012111Sralph } bauds[] = {
107112111Sralph 	50,	B50,
107212111Sralph 	75,	B75,
107312111Sralph 	110,	B110,
107412111Sralph 	134,	B134,
107512111Sralph 	150,	B150,
107612111Sralph 	200,	B200,
107712111Sralph 	300,	B300,
107812111Sralph 	600,	B600,
107912111Sralph 	1200,	B1200,
108012111Sralph 	1800,	B1800,
108112111Sralph 	2400,	B2400,
108212111Sralph 	4800,	B4800,
108312111Sralph 	9600,	B9600,
108412111Sralph 	19200,	EXTA,
108512111Sralph 	38400,	EXTB,
108612111Sralph 	0,	0
108712111Sralph };
108812111Sralph 
108912111Sralph /*
109012111Sralph  * setup tty lines.
109112111Sralph  */
109212877Sralph static
109312111Sralph setty()
109412111Sralph {
109512111Sralph 	struct sgttyb ttybuf;
109612111Sralph 	register struct bauds *bp;
109712111Sralph 
109812111Sralph 	if (ioctl(pfd, TIOCEXCL, (char *)0) < 0) {
109912111Sralph 		log("cannot set exclusive-use");
110012111Sralph 		exit(1);
110112111Sralph 	}
110212111Sralph 	if (ioctl(pfd, TIOCGETP, (char *)&ttybuf) < 0) {
110312111Sralph 		log("cannot get tty parameters");
110412111Sralph 		exit(1);
110512111Sralph 	}
110612111Sralph 	if (BR > 0) {
110712111Sralph 		for (bp = bauds; bp->baud; bp++)
110812111Sralph 			if (BR == bp->baud)
110912111Sralph 				break;
111012111Sralph 		if (!bp->baud) {
111112111Sralph 			log("illegal baud rate %d", BR);
111212111Sralph 			exit(1);
111312111Sralph 		}
111412111Sralph 		ttybuf.sg_ispeed = ttybuf.sg_ospeed = bp->speed;
111512111Sralph 	}
111613169Sralph 	ttybuf.sg_flags &= ~FC;
111713169Sralph 	ttybuf.sg_flags |= FS;
111812111Sralph 	if (ioctl(pfd, TIOCSETP, (char *)&ttybuf) < 0) {
111912111Sralph 		log("cannot set tty parameters");
112012111Sralph 		exit(1);
112112111Sralph 	}
112212111Sralph 	if (XC) {
112312111Sralph 		if (ioctl(pfd, TIOCLBIC, &XC) < 0) {
112412111Sralph 			log("cannot set local tty parameters");
112512111Sralph 			exit(1);
112612111Sralph 		}
112712111Sralph 	}
112812111Sralph 	if (XS) {
112912111Sralph 		if (ioctl(pfd, TIOCLBIS, &XS) < 0) {
113012111Sralph 			log("cannot set local tty parameters");
113112111Sralph 			exit(1);
113212111Sralph 		}
113312111Sralph 	}
113412111Sralph }
113512463Sralph 
113612463Sralph /*VARARGS1*/
113712463Sralph static
113812463Sralph status(msg, a1, a2, a3)
113912463Sralph 	char *msg;
114012463Sralph {
114112463Sralph 	register int fd;
114212463Sralph 	char buf[BUFSIZ];
114312463Sralph 
114412463Sralph 	umask(0);
114513148Ssam 	fd = open(ST, O_WRONLY|O_CREAT, 0664);
114613148Ssam 	if (fd < 0 || flock(fd, LOCK_EX) < 0)
114712463Sralph 		fatal("cannot create status file");
114813148Ssam 	ftruncate(fd, 0);
114912463Sralph 	sprintf(buf, msg, a1, a2, a3);
115012463Sralph 	strcat(buf, "\n");
115112463Sralph 	(void) write(fd, buf, strlen(buf));
115212463Sralph 	(void) close(fd);
115312463Sralph }
1154