xref: /csrg-svn/usr.sbin/lpr/lpd/printjob.c (revision 17302)
113954Ssam #ifndef lint
2*17302Sralph static char sccsid[] = "@(#)printjob.c	4.20 (Berkeley) 10/23/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 
1416762Sralph #define DORETURN	0	/* absorb fork error */
1516762Sralph #define DOABORT		1	/* abort if dofork fails */
1612111Sralph 
1716762Sralph char	title[80];		/* ``pr'' title */
1816762Sralph FILE	*cfp;			/* control file */
1916762Sralph int	pfd;			/* printer file descriptor */
2016762Sralph int	ofd;			/* output filter file descriptor */
2116762Sralph int	lfd;			/* lock file descriptor */
2216762Sralph int	pid;			/* pid of lpd process */
2316762Sralph int	prchild;		/* id of pr process */
2416762Sralph int	child;			/* id of any filters */
2516762Sralph int	ofilter;		/* id of output filter, if any */
2616762Sralph int	tof;			/* true if at top of form */
2716762Sralph int	remote;			/* true if sending files to remote */
2812111Sralph 
2916762Sralph char	fromhost[32];		/* user's host machine */
3016762Sralph char	logname[32];		/* user's login name */
3116762Sralph char	jobname[100];		/* job or file name */
3216762Sralph char	class[32];		/* classification field */
3316762Sralph char	width[10] = "-w";	/* page width in characters */
3416762Sralph char	length[10] = "-l";	/* page length in lines */
3516762Sralph char	pxwidth[10] = "-x";	/* page width in pixels */
3616762Sralph char	pxlength[10] = "-y";	/* page length in pixels */
3716762Sralph char	indent[10] = "-i0";	/* indentation size in characters */
3816762Sralph char	tmpfile[] = "errsXXXXXX"; /* file name for filter output */
3912111Sralph 
4012111Sralph printjob()
4112111Sralph {
4212111Sralph 	struct stat stb;
4312111Sralph 	register struct queue *q, **qp;
4412111Sralph 	struct queue **queue;
4512111Sralph 	register int i, nitems;
4612111Sralph 	long pidoff;
4716762Sralph 	int count = 0;
4816762Sralph 	extern int abortpr();
4912111Sralph 
5012111Sralph 	init();					/* set up capabilities */
5113442Sralph 	(void) write(1, "", 1);			/* ack that daemon is started */
5216762Sralph 	setgid(getegid());
5312463Sralph 	pid = getpid();				/* for use with lprm */
5412111Sralph 	setpgrp(0, pid);
5516762Sralph 	signal(SIGHUP, abortpr);
5616762Sralph 	signal(SIGINT, abortpr);
5716762Sralph 	signal(SIGQUIT, abortpr);
5816762Sralph 	signal(SIGTERM, abortpr);
5912111Sralph 
6015811Sralph 	(void) mktemp(tmpfile);
6115811Sralph 
6212111Sralph 	/*
6312111Sralph 	 * uses short form file names
6412111Sralph 	 */
6512111Sralph 	if (chdir(SD) < 0) {
6616762Sralph 		syslog(LOG_ERR, "%s: %m", SD);
6712111Sralph 		exit(1);
6812111Sralph 	}
6912463Sralph 	if (stat(LO, &stb) == 0 && (stb.st_mode & 0100))
7012463Sralph 		exit(0);		/* printing disabled */
7114150Sralph 	lfd = open(LO, O_WRONLY|O_CREAT, 0644);
7213169Sralph 	if (lfd < 0) {
7316762Sralph 		syslog(LOG_ERR, "%s: %s: %m", printer, LO);
7413169Sralph 		exit(1);
7513169Sralph 	}
7613169Sralph 	if (flock(lfd, LOCK_EX|LOCK_NB) < 0) {
7712111Sralph 		if (errno == EWOULDBLOCK)	/* active deamon present */
7812111Sralph 			exit(0);
7916762Sralph 		syslog(LOG_ERR, "%s: %s: %m", printer, LO);
8012111Sralph 		exit(1);
8112111Sralph 	}
8213148Ssam 	ftruncate(lfd, 0);
8312111Sralph 	/*
8412111Sralph 	 * write process id for others to know
8512111Sralph 	 */
8612111Sralph 	sprintf(line, "%u\n", pid);
8712111Sralph 	pidoff = i = strlen(line);
8812463Sralph 	if (write(lfd, line, i) != i) {
8916762Sralph 		syslog(LOG_ERR, "%s: %s: %m", printer, LO);
9012111Sralph 		exit(1);
9112111Sralph 	}
9212111Sralph 	/*
9312111Sralph 	 * search the spool directory for work and sort by queue order.
9412111Sralph 	 */
9512111Sralph 	if ((nitems = getq(&queue)) < 0) {
9616762Sralph 		syslog(LOG_ERR, "%s: can't scan %s", printer, SD);
9712111Sralph 		exit(1);
9812111Sralph 	}
9912463Sralph 	if (nitems == 0)		/* no work to do */
10012111Sralph 		exit(0);
10113169Sralph 	if (stb.st_mode & 01) {		/* reset queue flag */
10213169Sralph 		if (fchmod(lfd, stb.st_mode & 0776) < 0)
10316762Sralph 			syslog(LOG_ERR, "%s: %s: %m", printer, LO);
10413169Sralph 	}
10512463Sralph 	openpr();			/* open printer or remote */
10612463Sralph again:
10712111Sralph 	/*
10812111Sralph 	 * we found something to do now do it --
10912111Sralph 	 *    write the name of the current control file into the lock file
11012111Sralph 	 *    so the spool queue program can tell what we're working on
11112111Sralph 	 */
11212111Sralph 	for (qp = queue; nitems--; free((char *) q)) {
11312111Sralph 		q = *qp++;
11412111Sralph 		if (stat(q->q_name, &stb) < 0)
11512111Sralph 			continue;
11612463Sralph 	restart:
11712111Sralph 		(void) lseek(lfd, pidoff, 0);
11812111Sralph 		(void) sprintf(line, "%s\n", q->q_name);
11912111Sralph 		i = strlen(line);
12012111Sralph 		if (write(lfd, line, i) != i)
12116762Sralph 			syslog(LOG_ERR, "%s: %s: %m", printer, LO);
12212111Sralph 		if (!remote)
12312111Sralph 			i = printit(q->q_name);
12412111Sralph 		else
12512111Sralph 			i = sendit(q->q_name);
12612463Sralph 		/*
12713169Sralph 		 * Check to see if we are supposed to stop printing or
12813169Sralph 		 * if we are to rebuild the queue.
12912463Sralph 		 */
13013169Sralph 		if (fstat(lfd, &stb) == 0) {
13116762Sralph 			/* stop printing before starting next job? */
13213169Sralph 			if (stb.st_mode & 0100)
13313169Sralph 				goto done;
13416762Sralph 			/* rebuild queue (after lpc topq) */
13513169Sralph 			if (stb.st_mode & 01) {
13613169Sralph 				for (free((char *) q); nitems--; free((char *) q))
13713169Sralph 					q = *qp++;
13813169Sralph 				if (fchmod(lfd, stb.st_mode & 0776) < 0)
13916762Sralph 					syslog(LOG_WARNING, "%s: %s: %m",
14016762Sralph 						printer, LO);
14113169Sralph 				break;
14213169Sralph 			}
14313169Sralph 		}
14414150Sralph 		if (i == 0)		/* file ok and printed */
14514150Sralph 			count++;
14614150Sralph 		else if (i > 0) {	/* try reprinting the job */
14716762Sralph 			syslog(LOG_INFO, "restarting %s", printer);
14812111Sralph 			if (ofilter > 0) {
14912111Sralph 				kill(ofilter, SIGCONT);	/* to be sure */
15012111Sralph 				(void) close(ofd);
15112111Sralph 				while ((i = wait(0)) > 0 && i != ofilter)
15212111Sralph 					;
15312111Sralph 				ofilter = 0;
15412111Sralph 			}
15512463Sralph 			(void) close(pfd);	/* close printer */
15615811Sralph 			if (ftruncate(lfd, pidoff) < 0)
15716762Sralph 				syslog(LOG_WARNING, "%s: %s: %m", printer, LO);
15812463Sralph 			openpr();		/* try to reopen printer */
15912111Sralph 			goto restart;
16012111Sralph 		}
16112111Sralph 	}
16212111Sralph 	free((char *) queue);
16312463Sralph 	/*
16412463Sralph 	 * search the spool directory for more work.
16512463Sralph 	 */
16612463Sralph 	if ((nitems = getq(&queue)) < 0) {
16716762Sralph 		syslog(LOG_ERR, "%s: can't scan %s", printer, SD);
16812463Sralph 		exit(1);
16912463Sralph 	}
17012463Sralph 	if (nitems == 0) {		/* no more work to do */
17112463Sralph 	done:
17214150Sralph 		if (count > 0) {	/* Files actually printed */
17314150Sralph 			if (!SF && !tof)
17414150Sralph 				(void) write(ofd, FF, strlen(FF));
17514150Sralph 			if (TR != NULL)		/* output trailer */
17614150Sralph 				(void) write(ofd, TR, strlen(TR));
17714150Sralph 		}
17815811Sralph 		(void) unlink(tmpfile);
17912463Sralph 		exit(0);
18012463Sralph 	}
18112111Sralph 	goto again;
18212111Sralph }
18312111Sralph 
18412111Sralph char	fonts[4][50];	/* fonts for troff */
18512111Sralph 
18616762Sralph char ifonts[4][18] = {
18712111Sralph 	"/usr/lib/vfont/R",
18812111Sralph 	"/usr/lib/vfont/I",
18912111Sralph 	"/usr/lib/vfont/B",
19012111Sralph 	"/usr/lib/vfont/S"
19112111Sralph };
19212111Sralph 
19312111Sralph /*
19412111Sralph  * The remaining part is the reading of the control file (cf)
19512111Sralph  * and performing the various actions.
19612111Sralph  * Returns 0 if everthing was OK, 1 if we should try to reprint the job and
19712111Sralph  * -1 if a non-recoverable error occured.
19812111Sralph  */
19912111Sralph printit(file)
20012111Sralph 	char *file;
20112111Sralph {
20212111Sralph 	register int i;
20312111Sralph 	int bombed = 0;
20412111Sralph 
20512111Sralph 	/*
20612111Sralph 	 * open control file
20712111Sralph 	 */
20812111Sralph 	if ((cfp = fopen(file, "r")) == NULL) {
20916762Sralph 		syslog(LOG_INFO, "%s: %s: %m", printer, file);
21012111Sralph 		return(0);
21112111Sralph 	}
21212111Sralph 	/*
21312111Sralph 	 * Reset troff fonts.
21412111Sralph 	 */
21512111Sralph 	for (i = 0; i < 4; i++)
21612111Sralph 		strcpy(fonts[i], ifonts[i]);
217*17302Sralph 	strcpy(indent+2, "0");
21812111Sralph 
21912111Sralph 	/*
22012111Sralph 	 *      read the control file for work to do
22112111Sralph 	 *
22212111Sralph 	 *      file format -- first character in the line is a command
22312111Sralph 	 *      rest of the line is the argument.
22412111Sralph 	 *      valid commands are:
22512111Sralph 	 *
22612111Sralph 	 *		J -- "job name" on banner page
22712111Sralph 	 *		C -- "class name" on banner page
22812111Sralph 	 *              L -- "literal" user's name to print on banner
22912111Sralph 	 *		T -- "title" for pr
23012111Sralph 	 *		H -- "host name" of machine where lpr was done
23112111Sralph 	 *              P -- "person" user's login name
23212581Sralph 	 *              I -- "indent" amount to indent output
23312111Sralph 	 *              f -- "file name" name of text file to print
23412111Sralph 	 *		l -- "file name" text file with control chars
23512111Sralph 	 *		p -- "file name" text file to print with pr(1)
23612111Sralph 	 *		t -- "file name" troff(1) file to print
23713233Sralph 	 *		n -- "file name" ditroff(1) file to print
23812111Sralph 	 *		d -- "file name" dvi file to print
23912111Sralph 	 *		g -- "file name" plot(1G) file to print
24012111Sralph 	 *		v -- "file name" plain raster file to print
24112111Sralph 	 *		c -- "file name" cifplot file to print
24212111Sralph 	 *		1 -- "R font file" for troff
24312111Sralph 	 *		2 -- "I font file" for troff
24412111Sralph 	 *		3 -- "B font file" for troff
24512111Sralph 	 *		4 -- "S font file" for troff
24612111Sralph 	 *		N -- "name" of file (used by lpq)
24712111Sralph 	 *              U -- "unlink" name of file to remove
24812111Sralph 	 *                    (after we print it. (Pass 2 only)).
24912111Sralph 	 *		M -- "mail" to user when done printing
25012111Sralph 	 *
25112111Sralph 	 *      getline reads a line and expands tabs to blanks
25212111Sralph 	 */
25312111Sralph 
25412111Sralph 	/* pass 1 */
25512111Sralph 
25612111Sralph 	while (getline(cfp))
25712111Sralph 		switch (line[0]) {
25812111Sralph 		case 'H':
25914150Sralph 			strcpy(fromhost, line+1);
26012111Sralph 			if (class[0] == '\0')
26115552Sralph 				strncpy(class, line+1, sizeof(class)-1);
26212111Sralph 			continue;
26312111Sralph 
26412111Sralph 		case 'P':
26515552Sralph 			strncpy(logname, line+1, sizeof(logname)-1);
26612463Sralph 			if (RS) {			/* restricted */
26712463Sralph 				if (getpwnam(logname) == (struct passwd *)0) {
26812463Sralph 					bombed = 2;
26915811Sralph 					sendmail(line+1, bombed);
27012463Sralph 					goto pass2;
27112463Sralph 				}
27212463Sralph 			}
27312111Sralph 			continue;
27412111Sralph 
27512111Sralph 		case 'J':
27612111Sralph 			if (line[1] != '\0')
27715552Sralph 				strncpy(jobname, line+1, sizeof(jobname)-1);
27812111Sralph 			else
27912111Sralph 				strcpy(jobname, " ");
28012111Sralph 			continue;
28112111Sralph 
28212111Sralph 		case 'C':
28312111Sralph 			if (line[1] != '\0')
28415552Sralph 				strncpy(class, line+1, sizeof(class)-1);
28512111Sralph 			else if (class[0] == '\0')
28615811Sralph 				gethostname(class, sizeof(class));
28712111Sralph 			continue;
28812111Sralph 
28912111Sralph 		case 'T':	/* header title for pr */
29015552Sralph 			strncpy(title, line+1, sizeof(title)-1);
29112111Sralph 			continue;
29212111Sralph 
29312111Sralph 		case 'L':	/* identification line */
29412111Sralph 			if (!SH)
29512111Sralph 				banner(line+1, jobname);
29612111Sralph 			continue;
29712111Sralph 
29812111Sralph 		case '1':	/* troff fonts */
29912111Sralph 		case '2':
30012111Sralph 		case '3':
30112111Sralph 		case '4':
30212111Sralph 			if (line[1] != '\0')
30312111Sralph 				strcpy(fonts[line[0]-'1'], line+1);
30412111Sralph 			continue;
30512111Sralph 
30612111Sralph 		case 'W':	/* page width */
30715552Sralph 			strncpy(width+2, line+1, sizeof(width)-3);
30812111Sralph 			continue;
30912111Sralph 
31012581Sralph 		case 'I':	/* indent amount */
31115552Sralph 			strncpy(indent+2, line+1, sizeof(indent)-3);
31212581Sralph 			continue;
31312581Sralph 
31412111Sralph 		default:	/* some file to print */
31515811Sralph 			switch (i = print(line[0], line+1)) {
31615811Sralph 			case -1:
31715811Sralph 				if (!bombed)
31815811Sralph 					bombed = 1;
31915811Sralph 				break;
32015811Sralph 			case 1:
32112111Sralph 				(void) fclose(cfp);
32212111Sralph 				return(1);
32315811Sralph 			case 2:
32415811Sralph 				bombed = 3;
32515811Sralph 				sendmail(logname, bombed);
32615811Sralph 			}
32712111Sralph 			title[0] = '\0';
32812111Sralph 			continue;
32912111Sralph 
33012111Sralph 		case 'N':
33112111Sralph 		case 'U':
33212111Sralph 		case 'M':
33312111Sralph 			continue;
33412111Sralph 		}
33512111Sralph 
33612111Sralph 	/* pass 2 */
33712111Sralph 
33812463Sralph pass2:
33912111Sralph 	fseek(cfp, 0L, 0);
34012111Sralph 	while (getline(cfp))
34112111Sralph 		switch (line[0]) {
34212111Sralph 		case 'M':
34315811Sralph 			if (bombed < 2)		/* already sent if >= 2 */
34415811Sralph 				sendmail(line+1, bombed);
34512111Sralph 			continue;
34612111Sralph 
34712111Sralph 		case 'U':
34812111Sralph 			(void) unlink(line+1);
34912111Sralph 		}
35012111Sralph 	/*
35115811Sralph 	 * clean-up in case another control file exists
35212111Sralph 	 */
35312111Sralph 	(void) fclose(cfp);
35412111Sralph 	(void) unlink(file);
35514150Sralph 	return(bombed ? -1 : 0);
35612111Sralph }
35712111Sralph 
35812111Sralph /*
35912111Sralph  * Print a file.
36013233Sralph  * Set up the chain [ PR [ | {IF, OF} ] ] or {IF, RF, TF, NF, DF, CF, VF}.
36115811Sralph  * Return -1 if a non-recoverable error occured,
36215811Sralph  * 2 if the filter detected some errors (but printed the job anyway),
36315811Sralph  * 1 if we should try to reprint this job and
36412111Sralph  * 0 if all is well.
36512111Sralph  * Note: all filters take stdin as the file, stdout as the printer,
36612111Sralph  * stderr as the log file, and must not ignore SIGINT.
36712111Sralph  */
36812111Sralph print(format, file)
36912111Sralph 	int format;
37012111Sralph 	char *file;
37112111Sralph {
37215811Sralph 	register int n;
37312111Sralph 	register char *prog;
37415811Sralph 	int fi, fo;
37512111Sralph 	char *av[15], buf[BUFSIZ];
37612111Sralph 	int pid, p[2], stopped = 0;
37712111Sralph 	union wait status;
37812111Sralph 
37916762Sralph 	if ((fi = open(file, O_RDONLY)) < 0)
38012111Sralph 		return(-1);
38112111Sralph 	if (!SF && !tof) {		/* start on a fresh page */
38212111Sralph 		(void) write(ofd, FF, strlen(FF));
38312111Sralph 		tof = 1;
38412111Sralph 	}
38512111Sralph 	if (IF == NULL && (format == 'f' || format == 'l')) {
38612111Sralph 		tof = 0;
38712111Sralph 		while ((n = read(fi, buf, BUFSIZ)) > 0)
38812111Sralph 			if (write(ofd, buf, n) != n) {
38912111Sralph 				(void) close(fi);
39012111Sralph 				return(1);
39112111Sralph 			}
39212111Sralph 		(void) close(fi);
39312111Sralph 		return(0);
39412111Sralph 	}
39512111Sralph 	switch (format) {
39612111Sralph 	case 'p':	/* print file using 'pr' */
39712111Sralph 		if (IF == NULL) {	/* use output filter */
39812111Sralph 			prog = PR;
39912111Sralph 			av[0] = "pr";
40012111Sralph 			av[1] = width;
40112111Sralph 			av[2] = length;
40212111Sralph 			av[3] = "-h";
40312111Sralph 			av[4] = *title ? title : " ";
40412111Sralph 			av[5] = 0;
40512111Sralph 			fo = ofd;
40612111Sralph 			goto start;
40712111Sralph 		}
40812111Sralph 		pipe(p);
40912111Sralph 		if ((prchild = dofork(DORETURN)) == 0) {	/* child */
41012111Sralph 			dup2(fi, 0);		/* file is stdin */
41112111Sralph 			dup2(p[1], 1);		/* pipe is stdout */
41212111Sralph 			for (n = 3; n < NOFILE; n++)
41312111Sralph 				(void) close(n);
41412111Sralph 			execl(PR, "pr", width, length, "-h", *title ? title : " ", 0);
41516762Sralph 			syslog(LOG_ERR, "cannot execl %s", PR);
41612111Sralph 			exit(2);
41712111Sralph 		}
41812111Sralph 		(void) close(p[1]);		/* close output side */
41912111Sralph 		(void) close(fi);
42012111Sralph 		if (prchild < 0) {
42112111Sralph 			prchild = 0;
42212111Sralph 			(void) close(p[0]);
42312111Sralph 			return(-1);
42412111Sralph 		}
42512111Sralph 		fi = p[0];			/* use pipe for input */
42612111Sralph 	case 'f':	/* print plain text file */
42712111Sralph 		prog = IF;
42812111Sralph 		av[1] = width;
42912111Sralph 		av[2] = length;
43012581Sralph 		av[3] = indent;
43112581Sralph 		n = 4;
43212111Sralph 		break;
43312111Sralph 	case 'l':	/* like 'f' but pass control characters */
43412111Sralph 		prog = IF;
43514325Sralph 		av[1] = "-c";
43612111Sralph 		av[2] = width;
43712111Sralph 		av[3] = length;
43812581Sralph 		av[4] = indent;
43912581Sralph 		n = 5;
44012111Sralph 		break;
44112463Sralph 	case 'r':	/* print a fortran text file */
44212463Sralph 		prog = RF;
44312463Sralph 		av[1] = width;
44412463Sralph 		av[2] = length;
44512463Sralph 		n = 3;
44612463Sralph 		break;
44712111Sralph 	case 't':	/* print troff output */
44813233Sralph 	case 'n':	/* print ditroff output */
44912463Sralph 	case 'd':	/* print tex output */
45012111Sralph 		(void) unlink(".railmag");
45112463Sralph 		if ((fo = creat(".railmag", FILMOD)) < 0) {
45216762Sralph 			syslog(LOG_ERR, "%s: cannot create .railmag", printer);
45312111Sralph 			(void) unlink(".railmag");
45412111Sralph 		} else {
45512111Sralph 			for (n = 0; n < 4; n++) {
45612111Sralph 				if (fonts[n][0] != '/')
45712111Sralph 					(void) write(fo, "/usr/lib/vfont/", 15);
45812111Sralph 				(void) write(fo, fonts[n], strlen(fonts[n]));
45912111Sralph 				(void) write(fo, "\n", 1);
46012111Sralph 			}
46112111Sralph 			(void) close(fo);
46212111Sralph 		}
46313233Sralph 		prog = (format == 't') ? TF : (format == 'n') ? NF : DF;
46412463Sralph 		av[1] = pxwidth;
46512463Sralph 		av[2] = pxlength;
46612463Sralph 		n = 3;
46712111Sralph 		break;
46812111Sralph 	case 'c':	/* print cifplot output */
46912111Sralph 		prog = CF;
47012463Sralph 		av[1] = pxwidth;
47112463Sralph 		av[2] = pxlength;
47212463Sralph 		n = 3;
47312111Sralph 		break;
47412111Sralph 	case 'g':	/* print plot(1G) output */
47512111Sralph 		prog = GF;
47612463Sralph 		av[1] = pxwidth;
47712463Sralph 		av[2] = pxlength;
47812463Sralph 		n = 3;
47912111Sralph 		break;
48012111Sralph 	case 'v':	/* print raster output */
48112111Sralph 		prog = VF;
48212463Sralph 		av[1] = pxwidth;
48312463Sralph 		av[2] = pxlength;
48412463Sralph 		n = 3;
48512111Sralph 		break;
48612111Sralph 	default:
48712111Sralph 		(void) close(fi);
48816762Sralph 		syslog(LOG_ERR, "%s: illegal format character '%c'",
48916762Sralph 			printer, format);
49012111Sralph 		return(-1);
49112111Sralph 	}
49212111Sralph 	if ((av[0] = rindex(prog, '/')) != NULL)
49312111Sralph 		av[0]++;
49412111Sralph 	else
49512111Sralph 		av[0] = prog;
49612111Sralph 	av[n++] = "-n";
49712111Sralph 	av[n++] = logname;
49812111Sralph 	av[n++] = "-h";
49914150Sralph 	av[n++] = fromhost;
50012111Sralph 	av[n++] = AF;
50112111Sralph 	av[n] = 0;
50212111Sralph 	fo = pfd;
50312111Sralph 	if (ofilter > 0) {		/* stop output filter */
50412111Sralph 		write(ofd, "\031\1", 2);
50512111Sralph 		while ((pid = wait3(&status, WUNTRACED, 0)) > 0 && pid != ofilter)
50612111Sralph 			;
50712111Sralph 		if (status.w_stopval != WSTOPPED) {
50812111Sralph 			(void) close(fi);
50916762Sralph 			syslog(LOG_WARNING, "%s: output filter died (%d)",
51016762Sralph 				printer, status.w_retcode);
51112111Sralph 			return(1);
51212111Sralph 		}
51312111Sralph 		stopped++;
51412111Sralph 	}
51512111Sralph start:
51612111Sralph 	if ((child = dofork(DORETURN)) == 0) {	/* child */
51712111Sralph 		dup2(fi, 0);
51812111Sralph 		dup2(fo, 1);
51915811Sralph 		n = open(tmpfile, O_WRONLY|O_CREAT, 0664);
52015811Sralph 		if (n >= 0)
52115811Sralph 			dup2(n, 2);
52212111Sralph 		for (n = 3; n < NOFILE; n++)
52312111Sralph 			(void) close(n);
52412111Sralph 		execv(prog, av);
52516762Sralph 		syslog(LOG_ERR, "cannot execv %s", prog);
52612111Sralph 		exit(2);
52712111Sralph 	}
52812111Sralph 	(void) close(fi);
52912111Sralph 	if (child < 0)
53012111Sralph 		status.w_retcode = 100;
53112111Sralph 	else
53212111Sralph 		while ((pid = wait(&status)) > 0 && pid != child)
53312111Sralph 			;
53412111Sralph 	child = 0;
53512111Sralph 	prchild = 0;
53612111Sralph 	if (stopped) {		/* restart output filter */
53712111Sralph 		if (kill(ofilter, SIGCONT) < 0) {
53816762Sralph 			syslog(LOG_ERR, "cannot restart output filter");
53912111Sralph 			exit(1);
54012111Sralph 		}
54112111Sralph 	}
54212111Sralph 	tof = 0;
54315811Sralph 	if (!WIFEXITED(status)) {
54416762Sralph 		syslog(LOG_WARNING, "%s: Daemon filter '%c' terminated (%d)",
54516762Sralph 			printer, format, status.w_termsig);
54612111Sralph 		return(-1);
54715811Sralph 	} else if (status.w_retcode > 2) {
54816762Sralph 		syslog(LOG_WARNING, "%s: Daemon filter '%c' exited (%d)",
54916762Sralph 			printer, format, status.w_retcode);
55015811Sralph 		return(-1);
55115811Sralph 	} else if (status.w_retcode == 0)
55215811Sralph 		tof = 1;
55315811Sralph 	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  */
56112111Sralph sendit(file)
56212111Sralph 	char *file;
56312111Sralph {
56412111Sralph 	register int linelen, err = 0;
56512111Sralph 	char last[132];
56612111Sralph 
56712111Sralph 	/*
56812111Sralph 	 * open control file
56912111Sralph 	 */
57016762Sralph 	if ((cfp = fopen(file, "r")) == NULL)
57112111Sralph 		return(0);
57212111Sralph 	/*
57312111Sralph 	 *      read the control file for work to do
57412111Sralph 	 *
57512111Sralph 	 *      file format -- first character in the line is a command
57612111Sralph 	 *      rest of the line is the argument.
57712111Sralph 	 *      commands of interest are:
57812111Sralph 	 *
57912111Sralph 	 *            a-z -- "file name" name of file to print
58012111Sralph 	 *              U -- "unlink" name of file to remove
58112111Sralph 	 *                    (after we print it. (Pass 2 only)).
58212111Sralph 	 */
58312111Sralph 
58412111Sralph 	/*
58512111Sralph 	 * pass 1
58612111Sralph 	 */
58712111Sralph 	while (getline(cfp)) {
58812111Sralph 	again:
58912111Sralph 		if (line[0] >= 'a' && line[0] <= 'z') {
59012111Sralph 			strcpy(last, line);
59112111Sralph 			while (linelen = getline(cfp))
59212111Sralph 				if (strcmp(last, line))
59312111Sralph 					break;
59412111Sralph 			if ((err = sendfile('\3', last+1)) > 0) {
59512111Sralph 				(void) fclose(cfp);
59612111Sralph 				return(1);
59712111Sralph 			} else if (err)
59812111Sralph 				break;
59912111Sralph 			if (linelen)
60012111Sralph 				goto again;
60112111Sralph 			break;
60212111Sralph 		}
60312111Sralph 	}
60412111Sralph 	if (!err && sendfile('\2', file) > 0) {
60512111Sralph 		(void) fclose(cfp);
60612111Sralph 		return(1);
60712111Sralph 	}
60812111Sralph 	/*
60912111Sralph 	 * pass 2
61012111Sralph 	 */
61112111Sralph 	fseek(cfp, 0L, 0);
61212111Sralph 	while (getline(cfp))
61312111Sralph 		if (line[0] == 'U')
61412111Sralph 			(void) unlink(line+1);
61512111Sralph 	/*
61612111Sralph 	 * clean-up incase another control file exists
61712111Sralph 	 */
61812111Sralph 	(void) fclose(cfp);
61912111Sralph 	(void) unlink(file);
62012111Sralph 	return(0);
62112111Sralph }
62212111Sralph 
62312111Sralph /*
62412111Sralph  * Send a data file to the remote machine and spool it.
62512111Sralph  * Return positive if we should try resending.
62612111Sralph  */
62712111Sralph sendfile(type, file)
62812111Sralph 	char type, *file;
62912111Sralph {
63012111Sralph 	register int f, i, amt;
63112111Sralph 	struct stat stb;
63212111Sralph 	char buf[BUFSIZ];
63316762Sralph 	int sizerr, resp;
63412111Sralph 
63516762Sralph 	if ((f = open(file, O_RDONLY)) < 0 || fstat(f, &stb) < 0)
63612111Sralph 		return(-1);
63712111Sralph 	(void) sprintf(buf, "%c%d %s\n", type, stb.st_size, file);
63812111Sralph 	amt = strlen(buf);
63916762Sralph 	for (i = 0;  ; i++) {
64016762Sralph 		if (write(pfd, buf, amt) != amt ||
64116762Sralph 		    (resp = response()) < 0 || resp == '\1') {
64216762Sralph 			(void) close(f);
64316762Sralph 			return(1);
64416762Sralph 		} else if (resp == '\0')
64516762Sralph 			break;
64616762Sralph 		if (i == 0)
64716762Sralph 			status("no space on remote; waiting for queue to drain");
64816762Sralph 		if (i == 10)
64916762Sralph 			syslog(LOG_SALERT, "%s: can't send to %s; queue full",
65016762Sralph 				printer, RM);
65116762Sralph 		sleep(5 * 60);
65212692Sralph 	}
65316762Sralph 	if (i)
65416762Sralph 		status("sending to %s", RM);
65512111Sralph 	sizerr = 0;
65612111Sralph 	for (i = 0; i < stb.st_size; i += BUFSIZ) {
65712111Sralph 		amt = BUFSIZ;
65812111Sralph 		if (i + amt > stb.st_size)
65912111Sralph 			amt = stb.st_size - i;
66012111Sralph 		if (sizerr == 0 && read(f, buf, amt) != amt)
66112111Sralph 			sizerr = 1;
66212692Sralph 		if (write(pfd, buf, amt) != amt) {
66312692Sralph 			(void) close(f);
66412111Sralph 			return(1);
66512692Sralph 		}
66612111Sralph 	}
66712111Sralph 	(void) close(f);
66812111Sralph 	if (sizerr) {
66916762Sralph 		syslog(LOG_INFO, "%s: %s: changed size", printer, file);
67012111Sralph 		(void) write(pfd, "\1", 1);  /* tell recvjob to ignore this file */
67116762Sralph 		i = -1;
67216762Sralph 	} else if (write(pfd, "", 1) != 1)
67316762Sralph 		i = 1;
67416762Sralph 	else if (response())
67516762Sralph 		i = 1;
67616762Sralph 	else
67716762Sralph 		i = 0;
67816762Sralph 	return(i);
67912111Sralph }
68012111Sralph 
68112111Sralph /*
68212111Sralph  * Check to make sure there have been no errors and that both programs
68312111Sralph  * are in sync with eachother.
68412111Sralph  * Return non-zero if the connection was lost.
68512111Sralph  */
68616762Sralph response()
68712111Sralph {
68812111Sralph 	char resp;
68912111Sralph 
69016762Sralph 	if (read(pfd, &resp, 1) != 1) {
69116762Sralph 		syslog(LOG_INFO, "%s: lost connection", printer);
69216762Sralph 		return(-1);
69312111Sralph 	}
69416762Sralph 	return(resp);
69512111Sralph }
69612111Sralph 
69712111Sralph /*
69812111Sralph  * Banner printing stuff
69912111Sralph  */
70012111Sralph banner(name1, name2)
70112111Sralph 	char *name1, *name2;
70212111Sralph {
70312111Sralph 	time_t tvec;
70412111Sralph 	extern char *ctime();
70512111Sralph 
70612111Sralph 	time(&tvec);
70712111Sralph 	if (!SF && !tof)
70812111Sralph 		(void) write(ofd, FF, strlen(FF));
70912111Sralph 	if (SB) {	/* short banner only */
71012111Sralph 		if (class[0]) {
71112111Sralph 			(void) write(ofd, class, strlen(class));
71212111Sralph 			(void) write(ofd, ":", 1);
71312111Sralph 		}
71412111Sralph 		(void) write(ofd, name1, strlen(name1));
71512111Sralph 		(void) write(ofd, "  Job: ", 7);
71612111Sralph 		(void) write(ofd, name2, strlen(name2));
71712111Sralph 		(void) write(ofd, "  Date: ", 8);
71812111Sralph 		(void) write(ofd, ctime(&tvec), 24);
71912111Sralph 		(void) write(ofd, "\n", 1);
72012111Sralph 	} else {	/* normal banner */
72112111Sralph 		(void) write(ofd, "\n\n\n", 3);
72212111Sralph 		scan_out(ofd, name1, '\0');
72312111Sralph 		(void) write(ofd, "\n\n", 2);
72412111Sralph 		scan_out(ofd, name2, '\0');
72512111Sralph 		if (class[0]) {
72612111Sralph 			(void) write(ofd,"\n\n\n",3);
72712111Sralph 			scan_out(ofd, class, '\0');
72812111Sralph 		}
72912111Sralph 		(void) write(ofd, "\n\n\n\n\t\t\t\t\tJob:  ", 15);
73012111Sralph 		(void) write(ofd, name2, strlen(name2));
73112111Sralph 		(void) write(ofd, "\n\t\t\t\t\tDate: ", 12);
73212111Sralph 		(void) write(ofd, ctime(&tvec), 24);
73312111Sralph 		(void) write(ofd, "\n", 1);
73412111Sralph 	}
73512111Sralph 	if (!SF)
73612111Sralph 		(void) write(ofd, FF, strlen(FF));
73712111Sralph 	tof = 1;
73812111Sralph }
73912111Sralph 
74016762Sralph char *
74112111Sralph scnline(key, p, c)
74212111Sralph 	register char key, *p;
74312111Sralph 	char c;
74412111Sralph {
74512111Sralph 	register scnwidth;
74612111Sralph 
74712111Sralph 	for (scnwidth = WIDTH; --scnwidth;) {
74812111Sralph 		key <<= 1;
74912111Sralph 		*p++ = key & 0200 ? c : BACKGND;
75012111Sralph 	}
75112111Sralph 	return (p);
75212111Sralph }
75312111Sralph 
75412111Sralph #define TRC(q)	(((q)-' ')&0177)
75512111Sralph 
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 
78912111Sralph dropit(c)
79012111Sralph 	char c;
79112111Sralph {
79212111Sralph 	switch(c) {
79312111Sralph 
79412111Sralph 	case TRC('_'):
79512111Sralph 	case TRC(';'):
79612111Sralph 	case TRC(','):
79712111Sralph 	case TRC('g'):
79812111Sralph 	case TRC('j'):
79912111Sralph 	case TRC('p'):
80012111Sralph 	case TRC('q'):
80112111Sralph 	case TRC('y'):
80212111Sralph 		return (DROP);
80312111Sralph 
80412111Sralph 	default:
80512111Sralph 		return (0);
80612111Sralph 	}
80712111Sralph }
80812111Sralph 
80912111Sralph /*
81012111Sralph  * sendmail ---
81112111Sralph  *   tell people about job completion
81212111Sralph  */
81315811Sralph sendmail(user, bombed)
81415811Sralph 	char *user;
81512111Sralph 	int bombed;
81612111Sralph {
81712111Sralph 	register int i;
81815811Sralph 	int p[2], s;
81912111Sralph 	register char *cp;
82012111Sralph 	char buf[100];
82115811Sralph 	struct stat stb;
82215811Sralph 	FILE *fp;
82312111Sralph 
82412111Sralph 	pipe(p);
82515811Sralph 	if ((s = dofork(DORETURN)) == 0) {		/* child */
82612111Sralph 		dup2(p[0], 0);
82712111Sralph 		for (i = 3; i < NOFILE; i++)
82812111Sralph 			(void) close(i);
82912111Sralph 		if ((cp = rindex(MAIL, '/')) != NULL)
83012111Sralph 			cp++;
83112111Sralph 		else
83212111Sralph 			cp = MAIL;
83315811Sralph 		sprintf(buf, "%s@%s", user, fromhost);
83412111Sralph 		execl(MAIL, cp, buf, 0);
83512111Sralph 		exit(0);
83615811Sralph 	} else if (s > 0) {				/* parent */
83712111Sralph 		dup2(p[1], 1);
83815811Sralph 		printf("To: %s@%s\n", user, fromhost);
83912111Sralph 		printf("Subject: printer job\n\n");
84012111Sralph 		printf("Your printer job ");
84112111Sralph 		if (*jobname)
84212111Sralph 			printf("(%s) ", jobname);
84312463Sralph 		switch (bombed) {
84412463Sralph 		case 0:
84512463Sralph 			printf("\ncompleted successfully\n");
84612463Sralph 			break;
84712463Sralph 		default:
84812463Sralph 		case 1:
84912463Sralph 			printf("\ncould not be printed\n");
85012463Sralph 			break;
85112463Sralph 		case 2:
85212463Sralph 			printf("\ncould not be printed without an account on %s\n", host);
85312463Sralph 			break;
85415811Sralph 		case 3:
85515811Sralph 			if (stat(tmpfile, &stb) < 0 || stb.st_size == 0 ||
85615811Sralph 			    (fp = fopen(tmpfile, "r")) == NULL) {
85715811Sralph 				printf("\nwas printed but had some errors\n");
85815811Sralph 				break;
85915811Sralph 			}
86015811Sralph 			printf("\nwas printed but had the following errors:\n");
86115811Sralph 			while ((i = getc(fp)) != EOF)
86215811Sralph 				putchar(i);
86315811Sralph 			(void) fclose(fp);
86412463Sralph 		}
86512111Sralph 		fflush(stdout);
86612111Sralph 		(void) close(1);
86712111Sralph 	}
86812111Sralph 	(void) close(p[0]);
86912111Sralph 	(void) close(p[1]);
87015811Sralph 	wait(&s);
87112111Sralph }
87212111Sralph 
87312111Sralph /*
87412111Sralph  * dofork - fork with retries on failure
87512111Sralph  */
87612111Sralph dofork(action)
87712111Sralph 	int action;
87812111Sralph {
87912111Sralph 	register int i, pid;
88012111Sralph 
88112111Sralph 	for (i = 0; i < 20; i++) {
88212463Sralph 		if ((pid = fork()) < 0) {
88312111Sralph 			sleep((unsigned)(i*i));
88412463Sralph 			continue;
88512463Sralph 		}
88612463Sralph 		/*
88712463Sralph 		 * Child should run as daemon instead of root
88812463Sralph 		 */
88912463Sralph 		if (pid == 0)
89012463Sralph 			setuid(DU);
89112463Sralph 		return(pid);
89212111Sralph 	}
89316762Sralph 	syslog(LOG_ERR, "can't fork");
89412111Sralph 
89512111Sralph 	switch (action) {
89612111Sralph 	case DORETURN:
89712111Sralph 		return (-1);
89812111Sralph 	default:
89916762Sralph 		syslog(LOG_ERR, "bad action (%d) to dofork", action);
90012111Sralph 		/*FALL THRU*/
90112111Sralph 	case DOABORT:
90212111Sralph 		exit(1);
90312111Sralph 	}
90412111Sralph 	/*NOTREACHED*/
90512111Sralph }
90612111Sralph 
90712111Sralph /*
90816762Sralph  * Kill child processes to abort current job.
90912111Sralph  */
91016762Sralph abortpr()
91112111Sralph {
91215811Sralph 	(void) unlink(tmpfile);
91312111Sralph 	kill(0, SIGINT);
91412111Sralph 	if (ofilter > 0)
91512111Sralph 		kill(ofilter, SIGCONT);
91612111Sralph 	while (wait(0) > 0)
91712111Sralph 		;
91812111Sralph 	exit(0);
91912111Sralph }
92012111Sralph 
92112111Sralph init()
92212111Sralph {
92312111Sralph 	int status;
92412111Sralph 
92513169Sralph 	if ((status = pgetent(line, printer)) < 0)
92613169Sralph 		fatal("can't open printer description file");
92713169Sralph 	else if (status == 0)
92813169Sralph 		fatal("unknown printer");
92912111Sralph 	if ((LP = pgetstr("lp", &bp)) == NULL)
93012111Sralph 		LP = DEFDEVLP;
93112111Sralph 	if ((RP = pgetstr("rp", &bp)) == NULL)
93212463Sralph 		RP = DEFLP;
93312111Sralph 	if ((LO = pgetstr("lo", &bp)) == NULL)
93412111Sralph 		LO = DEFLOCK;
93512111Sralph 	if ((ST = pgetstr("st", &bp)) == NULL)
93612111Sralph 		ST = DEFSTAT;
93712111Sralph 	if ((LF = pgetstr("lf", &bp)) == NULL)
93812111Sralph 		LF = DEFLOGF;
93912111Sralph 	if ((SD = pgetstr("sd", &bp)) == NULL)
94012111Sralph 		SD = DEFSPOOL;
94112111Sralph 	if ((DU = pgetnum("du")) < 0)
94212111Sralph 		DU = DEFUID;
94312111Sralph 	if ((FF = pgetstr("ff", &bp)) == NULL)
94412111Sralph 		FF = DEFFF;
94512111Sralph 	if ((PW = pgetnum("pw")) < 0)
94612111Sralph 		PW = DEFWIDTH;
94712111Sralph 	sprintf(&width[2], "%d", PW);
94812111Sralph 	if ((PL = pgetnum("pl")) < 0)
94912111Sralph 		PL = DEFLENGTH;
95012111Sralph 	sprintf(&length[2], "%d", PL);
95112463Sralph 	if ((PX = pgetnum("px")) < 0)
95212463Sralph 		PX = 0;
95312463Sralph 	sprintf(&pxwidth[2], "%d", PX);
95412463Sralph 	if ((PY = pgetnum("py")) < 0)
95512463Sralph 		PY = 0;
95612463Sralph 	sprintf(&pxlength[2], "%d", PY);
95712111Sralph 	RM = pgetstr("rm", &bp);
95812111Sralph 	AF = pgetstr("af", &bp);
95912111Sralph 	OF = pgetstr("of", &bp);
96012111Sralph 	IF = pgetstr("if", &bp);
96112463Sralph 	RF = pgetstr("rf", &bp);
96212111Sralph 	TF = pgetstr("tf", &bp);
96313233Sralph 	NF = pgetstr("nf", &bp);
96412111Sralph 	DF = pgetstr("df", &bp);
96512111Sralph 	GF = pgetstr("gf", &bp);
96612111Sralph 	VF = pgetstr("vf", &bp);
96712111Sralph 	CF = pgetstr("cf", &bp);
96812111Sralph 	TR = pgetstr("tr", &bp);
96912463Sralph 	RS = pgetflag("rs");
97012111Sralph 	SF = pgetflag("sf");
97112111Sralph 	SH = pgetflag("sh");
97212111Sralph 	SB = pgetflag("sb");
97312111Sralph 	RW = pgetflag("rw");
97412111Sralph 	BR = pgetnum("br");
97512111Sralph 	if ((FC = pgetnum("fc")) < 0)
97612111Sralph 		FC = 0;
97712111Sralph 	if ((FS = pgetnum("fs")) < 0)
97812111Sralph 		FS = 0;
97912111Sralph 	if ((XC = pgetnum("xc")) < 0)
98012111Sralph 		XC = 0;
98112111Sralph 	if ((XS = pgetnum("xs")) < 0)
98212111Sralph 		XS = 0;
98312581Sralph 	tof = !pgetflag("fo");
98412111Sralph }
98512111Sralph 
98612463Sralph /*
98712463Sralph  * Acquire line printer or remote connection.
98812463Sralph  */
98912463Sralph openpr()
99012463Sralph {
99112463Sralph 	register int i, n;
99216762Sralph 	int resp;
99312463Sralph 
99412463Sralph 	if (*LP) {
99512463Sralph 		for (i = 1; ; i = i < 32 ? i << 1 : i) {
99613148Ssam 			pfd = open(LP, RW ? O_RDWR : O_WRONLY);
99712463Sralph 			if (pfd >= 0)
99812463Sralph 				break;
99912463Sralph 			if (errno == ENOENT) {
100016762Sralph 				syslog(LOG_ERR, "%s: %m", LP);
100112463Sralph 				exit(1);
100212463Sralph 			}
100312463Sralph 			if (i == 1)
100412463Sralph 				status("waiting for %s to become ready (offline ?)", printer);
100512463Sralph 			sleep(i);
100612463Sralph 		}
100712463Sralph 		if (isatty(pfd))
100812463Sralph 			setty();
100912463Sralph 		status("%s is ready and printing", printer);
101012463Sralph 	} else if (RM != NULL) {
101116762Sralph 		for (i = 1; ; i = i < 256 ? i << 1 : i) {
101216762Sralph 			resp = -1;
101312528Sralph 			pfd = getport(RM);
101412463Sralph 			if (pfd >= 0) {
101512463Sralph 				(void) sprintf(line, "\2%s\n", RP);
101612463Sralph 				n = strlen(line);
101716762Sralph 				if (write(pfd, line, n) == n &&
101816762Sralph 				    (resp = response()) == '\0')
101912463Sralph 					break;
102016031Sralph 				(void) close(pfd);
102112463Sralph 			}
102216031Sralph 			if (i == 1) {
102316762Sralph 				if (resp < 0)
102416031Sralph 					status("waiting for %s to come up", RM);
102516762Sralph 				else {
102616031Sralph 					status("waiting for queue to be enabled on %s", RM);
102716762Sralph 					i = 256;
102816762Sralph 				}
102916031Sralph 			}
103012463Sralph 			sleep(i);
103112463Sralph 		}
103212463Sralph 		status("sending to %s", RM);
103312463Sralph 		remote = 1;
103412463Sralph 	} else {
103516762Sralph 		syslog(LOG_ERR, "%s: no line printer device or host name",
103616762Sralph 			printer);
103712463Sralph 		exit(1);
103812463Sralph 	}
103912463Sralph 	/*
104012463Sralph 	 * Start up an output filter, if needed.
104112463Sralph 	 */
104212463Sralph 	if (OF) {
104312463Sralph 		int p[2];
104412463Sralph 		char *cp;
104512463Sralph 
104612463Sralph 		pipe(p);
104712463Sralph 		if ((ofilter = dofork(DOABORT)) == 0) {	/* child */
104812463Sralph 			dup2(p[0], 0);		/* pipe is std in */
104912463Sralph 			dup2(pfd, 1);		/* printer is std out */
105012463Sralph 			for (i = 3; i < NOFILE; i++)
105112463Sralph 				(void) close(i);
105212463Sralph 			if ((cp = rindex(OF, '/')) == NULL)
105312463Sralph 				cp = OF;
105412463Sralph 			else
105512463Sralph 				cp++;
105612463Sralph 			execl(OF, cp, width, length, 0);
105716762Sralph 			syslog(LOG_ERR, "%s: %s: %m", printer, OF);
105812463Sralph 			exit(1);
105912463Sralph 		}
106012463Sralph 		(void) close(p[0]);		/* close input side */
106112463Sralph 		ofd = p[1];			/* use pipe for output */
106212463Sralph 	} else {
106312463Sralph 		ofd = pfd;
106412463Sralph 		ofilter = 0;
106512463Sralph 	}
106612463Sralph }
106712463Sralph 
106812111Sralph struct bauds {
106912111Sralph 	int	baud;
107012111Sralph 	int	speed;
107112111Sralph } bauds[] = {
107212111Sralph 	50,	B50,
107312111Sralph 	75,	B75,
107412111Sralph 	110,	B110,
107512111Sralph 	134,	B134,
107612111Sralph 	150,	B150,
107712111Sralph 	200,	B200,
107812111Sralph 	300,	B300,
107912111Sralph 	600,	B600,
108012111Sralph 	1200,	B1200,
108112111Sralph 	1800,	B1800,
108212111Sralph 	2400,	B2400,
108312111Sralph 	4800,	B4800,
108412111Sralph 	9600,	B9600,
108512111Sralph 	19200,	EXTA,
108612111Sralph 	38400,	EXTB,
108712111Sralph 	0,	0
108812111Sralph };
108912111Sralph 
109012111Sralph /*
109112111Sralph  * setup tty lines.
109212111Sralph  */
109312111Sralph setty()
109412111Sralph {
109512111Sralph 	struct sgttyb ttybuf;
109612111Sralph 	register struct bauds *bp;
109712111Sralph 
109812111Sralph 	if (ioctl(pfd, TIOCEXCL, (char *)0) < 0) {
109916762Sralph 		syslog(LOG_ERR, "%s: ioctl(TIOCEXCL): %m", printer);
110012111Sralph 		exit(1);
110112111Sralph 	}
110212111Sralph 	if (ioctl(pfd, TIOCGETP, (char *)&ttybuf) < 0) {
110316762Sralph 		syslog(LOG_ERR, "%s: ioctl(TIOCGETP): %m", printer);
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) {
111116762Sralph 			syslog(LOG_ERR, "%s: illegal baud rate %d", printer, 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) {
111916762Sralph 		syslog(LOG_ERR, "%s: ioctl(TIOCSETP): %m", printer);
112012111Sralph 		exit(1);
112112111Sralph 	}
112217168Sralph 	if (XC || XS) {
112317168Sralph 		int ldisc = NTTYDISC;
112417168Sralph 
112517168Sralph 		if (ioctl(pfd, TIOCSETD, &ldisc) < 0) {
112617168Sralph 			syslog(LOG_ERR, "%s: ioctl(TIOCSETD): %m", printer);
112717168Sralph 			exit(1);
112817168Sralph 		}
112917168Sralph 	}
113012111Sralph 	if (XC) {
113112111Sralph 		if (ioctl(pfd, TIOCLBIC, &XC) < 0) {
113216762Sralph 			syslog(LOG_ERR, "%s: ioctl(TIOCLBIC): %m", printer);
113312111Sralph 			exit(1);
113412111Sralph 		}
113512111Sralph 	}
113612111Sralph 	if (XS) {
113712111Sralph 		if (ioctl(pfd, TIOCLBIS, &XS) < 0) {
113816762Sralph 			syslog(LOG_ERR, "%s: ioctl(TIOCLBIS): %m", printer);
113912111Sralph 			exit(1);
114012111Sralph 		}
114112111Sralph 	}
114212111Sralph }
114312463Sralph 
114412463Sralph /*VARARGS1*/
114512463Sralph status(msg, a1, a2, a3)
114612463Sralph 	char *msg;
114712463Sralph {
114812463Sralph 	register int fd;
114912463Sralph 	char buf[BUFSIZ];
115012463Sralph 
115112463Sralph 	umask(0);
115213148Ssam 	fd = open(ST, O_WRONLY|O_CREAT, 0664);
115316762Sralph 	if (fd < 0 || flock(fd, LOCK_EX) < 0) {
115416762Sralph 		syslog(LOG_ERR, "%s: %s: %m", printer, ST);
115516762Sralph 		exit(1);
115616762Sralph 	}
115713148Ssam 	ftruncate(fd, 0);
115812463Sralph 	sprintf(buf, msg, a1, a2, a3);
115912463Sralph 	strcat(buf, "\n");
116012463Sralph 	(void) write(fd, buf, strlen(buf));
116112463Sralph 	(void) close(fd);
116212463Sralph }
1163