xref: /csrg-svn/usr.sbin/lpr/lpd/printjob.c (revision 46912)
122437Sdist /*
222437Sdist  * Copyright (c) 1983 Regents of the University of California.
334203Sbostic  * All rights reserved.
434203Sbostic  *
542802Sbostic  * %sccs.include.redist.c%
622437Sdist  */
722437Sdist 
813954Ssam #ifndef lint
9*46912Sbostic static char sccsid[] = "@(#)printjob.c	5.13 (Berkeley) 03/02/91";
1034203Sbostic #endif /* not lint */
1113954Ssam 
1212111Sralph /*
1312111Sralph  * printjob -- print jobs in the queue.
1412111Sralph  *
1512111Sralph  *	NOTE: the lock file is used to pass information to lpq and lprm.
1612111Sralph  *	it does not need to be removed because file locks are dynamic.
1712111Sralph  */
1812111Sralph 
1912111Sralph #include "lp.h"
2037968Sbostic #include "pathnames.h"
2112111Sralph 
2216762Sralph #define DORETURN	0	/* absorb fork error */
2316762Sralph #define DOABORT		1	/* abort if dofork fails */
2412111Sralph 
2517463Sralph /*
2617463Sralph  * Error tokens
2717463Sralph  */
2817463Sralph #define REPRINT		-2
2917463Sralph #define ERROR		-1
3017463Sralph #define	OK		0
3117463Sralph #define	FATALERR	1
3217463Sralph #define	NOACCT		2
3317463Sralph #define	FILTERERR	3
3417463Sralph #define	ACCESS		4
3517463Sralph 
3616762Sralph char	title[80];		/* ``pr'' title */
3716762Sralph FILE	*cfp;			/* control file */
3816762Sralph int	pfd;			/* printer file descriptor */
3916762Sralph int	ofd;			/* output filter file descriptor */
4016762Sralph int	lfd;			/* lock file descriptor */
4116762Sralph int	pid;			/* pid of lpd process */
4216762Sralph int	prchild;		/* id of pr process */
4316762Sralph int	child;			/* id of any filters */
4416762Sralph int	ofilter;		/* id of output filter, if any */
4516762Sralph int	tof;			/* true if at top of form */
4616762Sralph int	remote;			/* true if sending files to remote */
4717463Sralph dev_t	fdev;			/* device of file pointed to by symlink */
4817463Sralph ino_t	fino;			/* inode of file pointed to by symlink */
4912111Sralph 
5016762Sralph char	fromhost[32];		/* user's host machine */
5116762Sralph char	logname[32];		/* user's login name */
5216762Sralph char	jobname[100];		/* job or file name */
5316762Sralph char	class[32];		/* classification field */
5416762Sralph char	width[10] = "-w";	/* page width in characters */
5516762Sralph char	length[10] = "-l";	/* page length in lines */
5616762Sralph char	pxwidth[10] = "-x";	/* page width in pixels */
5716762Sralph char	pxlength[10] = "-y";	/* page length in pixels */
5816762Sralph char	indent[10] = "-i0";	/* indentation size in characters */
5939954Smckusick char	tempfile[] = "errsXXXXXX"; /* file name for filter output */
6012111Sralph 
6112111Sralph printjob()
6212111Sralph {
6312111Sralph 	struct stat stb;
6412111Sralph 	register struct queue *q, **qp;
6512111Sralph 	struct queue **queue;
6612111Sralph 	register int i, nitems;
6712111Sralph 	long pidoff;
6816762Sralph 	int count = 0;
69*46912Sbostic 	void abortpr();
7012111Sralph 
7112111Sralph 	init();					/* set up capabilities */
7213442Sralph 	(void) write(1, "", 1);			/* ack that daemon is started */
7325496Seric 	(void) close(2);			/* set up log file */
7425496Seric 	if (open(LF, O_WRONLY|O_APPEND, 0664) < 0) {
7525496Seric 		syslog(LOG_ERR, "%s: %m", LF);
7637968Sbostic 		(void) open(_PATH_DEVNULL, O_WRONLY);
7725496Seric 	}
7816762Sralph 	setgid(getegid());
7912463Sralph 	pid = getpid();				/* for use with lprm */
8012111Sralph 	setpgrp(0, pid);
8116762Sralph 	signal(SIGHUP, abortpr);
8216762Sralph 	signal(SIGINT, abortpr);
8316762Sralph 	signal(SIGQUIT, abortpr);
8416762Sralph 	signal(SIGTERM, abortpr);
8512111Sralph 
8639954Smckusick 	(void) mktemp(tempfile);
8715811Sralph 
8812111Sralph 	/*
8912111Sralph 	 * uses short form file names
9012111Sralph 	 */
9112111Sralph 	if (chdir(SD) < 0) {
9216762Sralph 		syslog(LOG_ERR, "%s: %m", SD);
9312111Sralph 		exit(1);
9412111Sralph 	}
9512463Sralph 	if (stat(LO, &stb) == 0 && (stb.st_mode & 0100))
9612463Sralph 		exit(0);		/* printing disabled */
9714150Sralph 	lfd = open(LO, O_WRONLY|O_CREAT, 0644);
9813169Sralph 	if (lfd < 0) {
9916762Sralph 		syslog(LOG_ERR, "%s: %s: %m", printer, LO);
10013169Sralph 		exit(1);
10113169Sralph 	}
10213169Sralph 	if (flock(lfd, LOCK_EX|LOCK_NB) < 0) {
10312111Sralph 		if (errno == EWOULDBLOCK)	/* active deamon present */
10412111Sralph 			exit(0);
10516762Sralph 		syslog(LOG_ERR, "%s: %s: %m", printer, LO);
10612111Sralph 		exit(1);
10712111Sralph 	}
10813148Ssam 	ftruncate(lfd, 0);
10912111Sralph 	/*
11012111Sralph 	 * write process id for others to know
11112111Sralph 	 */
11212111Sralph 	sprintf(line, "%u\n", pid);
11312111Sralph 	pidoff = i = strlen(line);
11412463Sralph 	if (write(lfd, line, i) != i) {
11516762Sralph 		syslog(LOG_ERR, "%s: %s: %m", printer, LO);
11612111Sralph 		exit(1);
11712111Sralph 	}
11812111Sralph 	/*
11912111Sralph 	 * search the spool directory for work and sort by queue order.
12012111Sralph 	 */
12112111Sralph 	if ((nitems = getq(&queue)) < 0) {
12216762Sralph 		syslog(LOG_ERR, "%s: can't scan %s", printer, SD);
12312111Sralph 		exit(1);
12412111Sralph 	}
12512463Sralph 	if (nitems == 0)		/* no work to do */
12612111Sralph 		exit(0);
12713169Sralph 	if (stb.st_mode & 01) {		/* reset queue flag */
12813169Sralph 		if (fchmod(lfd, stb.st_mode & 0776) < 0)
12916762Sralph 			syslog(LOG_ERR, "%s: %s: %m", printer, LO);
13013169Sralph 	}
13112463Sralph 	openpr();			/* open printer or remote */
13212463Sralph again:
13312111Sralph 	/*
13412111Sralph 	 * we found something to do now do it --
13512111Sralph 	 *    write the name of the current control file into the lock file
13612111Sralph 	 *    so the spool queue program can tell what we're working on
13712111Sralph 	 */
13812111Sralph 	for (qp = queue; nitems--; free((char *) q)) {
13912111Sralph 		q = *qp++;
14012111Sralph 		if (stat(q->q_name, &stb) < 0)
14112111Sralph 			continue;
14212463Sralph 	restart:
14312111Sralph 		(void) lseek(lfd, pidoff, 0);
14412111Sralph 		(void) sprintf(line, "%s\n", q->q_name);
14512111Sralph 		i = strlen(line);
14612111Sralph 		if (write(lfd, line, i) != i)
14716762Sralph 			syslog(LOG_ERR, "%s: %s: %m", printer, LO);
14812111Sralph 		if (!remote)
14912111Sralph 			i = printit(q->q_name);
15012111Sralph 		else
15112111Sralph 			i = sendit(q->q_name);
15212463Sralph 		/*
15313169Sralph 		 * Check to see if we are supposed to stop printing or
15413169Sralph 		 * if we are to rebuild the queue.
15512463Sralph 		 */
15613169Sralph 		if (fstat(lfd, &stb) == 0) {
15716762Sralph 			/* stop printing before starting next job? */
15813169Sralph 			if (stb.st_mode & 0100)
15913169Sralph 				goto done;
16016762Sralph 			/* rebuild queue (after lpc topq) */
16113169Sralph 			if (stb.st_mode & 01) {
16213169Sralph 				for (free((char *) q); nitems--; free((char *) q))
16313169Sralph 					q = *qp++;
16413169Sralph 				if (fchmod(lfd, stb.st_mode & 0776) < 0)
16516762Sralph 					syslog(LOG_WARNING, "%s: %s: %m",
16616762Sralph 						printer, LO);
16713169Sralph 				break;
16813169Sralph 			}
16913169Sralph 		}
17017463Sralph 		if (i == OK)		/* file ok and printed */
17114150Sralph 			count++;
17217463Sralph 		else if (i == REPRINT) { /* try reprinting the job */
17316762Sralph 			syslog(LOG_INFO, "restarting %s", printer);
17412111Sralph 			if (ofilter > 0) {
17512111Sralph 				kill(ofilter, SIGCONT);	/* to be sure */
17612111Sralph 				(void) close(ofd);
17712111Sralph 				while ((i = wait(0)) > 0 && i != ofilter)
17812111Sralph 					;
17912111Sralph 				ofilter = 0;
18012111Sralph 			}
18112463Sralph 			(void) close(pfd);	/* close printer */
18215811Sralph 			if (ftruncate(lfd, pidoff) < 0)
18316762Sralph 				syslog(LOG_WARNING, "%s: %s: %m", printer, LO);
18412463Sralph 			openpr();		/* try to reopen printer */
18512111Sralph 			goto restart;
18612111Sralph 		}
18712111Sralph 	}
18812111Sralph 	free((char *) queue);
18912463Sralph 	/*
19012463Sralph 	 * search the spool directory for more work.
19112463Sralph 	 */
19212463Sralph 	if ((nitems = getq(&queue)) < 0) {
19316762Sralph 		syslog(LOG_ERR, "%s: can't scan %s", printer, SD);
19412463Sralph 		exit(1);
19512463Sralph 	}
19612463Sralph 	if (nitems == 0) {		/* no more work to do */
19712463Sralph 	done:
19814150Sralph 		if (count > 0) {	/* Files actually printed */
19914150Sralph 			if (!SF && !tof)
20014150Sralph 				(void) write(ofd, FF, strlen(FF));
20114150Sralph 			if (TR != NULL)		/* output trailer */
20214150Sralph 				(void) write(ofd, TR, strlen(TR));
20314150Sralph 		}
20439954Smckusick 		(void) unlink(tempfile);
20512463Sralph 		exit(0);
20612463Sralph 	}
20712111Sralph 	goto again;
20812111Sralph }
20912111Sralph 
21012111Sralph char	fonts[4][50];	/* fonts for troff */
21112111Sralph 
21237968Sbostic char ifonts[4][40] = {
21337968Sbostic 	_PATH_VFONTR,
21437968Sbostic 	_PATH_VFONTI,
21537968Sbostic 	_PATH_VFONTB,
21637968Sbostic 	_PATH_VFONTS,
21712111Sralph };
21812111Sralph 
21912111Sralph /*
22012111Sralph  * The remaining part is the reading of the control file (cf)
22112111Sralph  * and performing the various actions.
22212111Sralph  */
22312111Sralph printit(file)
22412111Sralph 	char *file;
22512111Sralph {
22612111Sralph 	register int i;
22717463Sralph 	char *cp;
22817463Sralph 	int bombed = OK;
22912111Sralph 
23012111Sralph 	/*
23117463Sralph 	 * open control file; ignore if no longer there.
23212111Sralph 	 */
23312111Sralph 	if ((cfp = fopen(file, "r")) == NULL) {
23416762Sralph 		syslog(LOG_INFO, "%s: %s: %m", printer, file);
23517463Sralph 		return(OK);
23612111Sralph 	}
23712111Sralph 	/*
23812111Sralph 	 * Reset troff fonts.
23912111Sralph 	 */
24012111Sralph 	for (i = 0; i < 4; i++)
24112111Sralph 		strcpy(fonts[i], ifonts[i]);
24217339Sralph 	strcpy(width+2, "0");
24317302Sralph 	strcpy(indent+2, "0");
24412111Sralph 
24512111Sralph 	/*
24612111Sralph 	 *      read the control file for work to do
24712111Sralph 	 *
24812111Sralph 	 *      file format -- first character in the line is a command
24912111Sralph 	 *      rest of the line is the argument.
25012111Sralph 	 *      valid commands are:
25112111Sralph 	 *
25217463Sralph 	 *		S -- "stat info" for symbolic link protection
25312111Sralph 	 *		J -- "job name" on banner page
25412111Sralph 	 *		C -- "class name" on banner page
25512111Sralph 	 *              L -- "literal" user's name to print on banner
25612111Sralph 	 *		T -- "title" for pr
25712111Sralph 	 *		H -- "host name" of machine where lpr was done
25812111Sralph 	 *              P -- "person" user's login name
25912581Sralph 	 *              I -- "indent" amount to indent output
26012111Sralph 	 *              f -- "file name" name of text file to print
26112111Sralph 	 *		l -- "file name" text file with control chars
26212111Sralph 	 *		p -- "file name" text file to print with pr(1)
26312111Sralph 	 *		t -- "file name" troff(1) file to print
26413233Sralph 	 *		n -- "file name" ditroff(1) file to print
26512111Sralph 	 *		d -- "file name" dvi file to print
26612111Sralph 	 *		g -- "file name" plot(1G) file to print
26712111Sralph 	 *		v -- "file name" plain raster file to print
26812111Sralph 	 *		c -- "file name" cifplot file to print
26912111Sralph 	 *		1 -- "R font file" for troff
27012111Sralph 	 *		2 -- "I font file" for troff
27112111Sralph 	 *		3 -- "B font file" for troff
27212111Sralph 	 *		4 -- "S font file" for troff
27312111Sralph 	 *		N -- "name" of file (used by lpq)
27412111Sralph 	 *              U -- "unlink" name of file to remove
27512111Sralph 	 *                    (after we print it. (Pass 2 only)).
27612111Sralph 	 *		M -- "mail" to user when done printing
27712111Sralph 	 *
27812111Sralph 	 *      getline reads a line and expands tabs to blanks
27912111Sralph 	 */
28012111Sralph 
28112111Sralph 	/* pass 1 */
28212111Sralph 
28312111Sralph 	while (getline(cfp))
28412111Sralph 		switch (line[0]) {
28512111Sralph 		case 'H':
28614150Sralph 			strcpy(fromhost, line+1);
28712111Sralph 			if (class[0] == '\0')
28815552Sralph 				strncpy(class, line+1, sizeof(class)-1);
28912111Sralph 			continue;
29012111Sralph 
29112111Sralph 		case 'P':
29215552Sralph 			strncpy(logname, line+1, sizeof(logname)-1);
29312463Sralph 			if (RS) {			/* restricted */
29412463Sralph 				if (getpwnam(logname) == (struct passwd *)0) {
29517463Sralph 					bombed = NOACCT;
29615811Sralph 					sendmail(line+1, bombed);
29712463Sralph 					goto pass2;
29812463Sralph 				}
29912463Sralph 			}
30012111Sralph 			continue;
30112111Sralph 
30217463Sralph 		case 'S':
30317463Sralph 			cp = line+1;
30417463Sralph 			i = 0;
30517463Sralph 			while (*cp >= '0' && *cp <= '9')
30617463Sralph 				i = i * 10 + (*cp++ - '0');
30717463Sralph 			fdev = i;
30817463Sralph 			cp++;
30917463Sralph 			i = 0;
31017463Sralph 			while (*cp >= '0' && *cp <= '9')
31117463Sralph 				i = i * 10 + (*cp++ - '0');
31217463Sralph 			fino = i;
31317463Sralph 			continue;
31417463Sralph 
31512111Sralph 		case 'J':
31612111Sralph 			if (line[1] != '\0')
31715552Sralph 				strncpy(jobname, line+1, sizeof(jobname)-1);
31812111Sralph 			else
31912111Sralph 				strcpy(jobname, " ");
32012111Sralph 			continue;
32112111Sralph 
32212111Sralph 		case 'C':
32312111Sralph 			if (line[1] != '\0')
32415552Sralph 				strncpy(class, line+1, sizeof(class)-1);
32512111Sralph 			else if (class[0] == '\0')
32615811Sralph 				gethostname(class, sizeof(class));
32712111Sralph 			continue;
32812111Sralph 
32912111Sralph 		case 'T':	/* header title for pr */
33015552Sralph 			strncpy(title, line+1, sizeof(title)-1);
33112111Sralph 			continue;
33212111Sralph 
33312111Sralph 		case 'L':	/* identification line */
33418127Sralph 			if (!SH && !HL)
33512111Sralph 				banner(line+1, jobname);
33612111Sralph 			continue;
33712111Sralph 
33812111Sralph 		case '1':	/* troff fonts */
33912111Sralph 		case '2':
34012111Sralph 		case '3':
34112111Sralph 		case '4':
34212111Sralph 			if (line[1] != '\0')
34312111Sralph 				strcpy(fonts[line[0]-'1'], line+1);
34412111Sralph 			continue;
34512111Sralph 
34612111Sralph 		case 'W':	/* page width */
34715552Sralph 			strncpy(width+2, line+1, sizeof(width)-3);
34812111Sralph 			continue;
34912111Sralph 
35012581Sralph 		case 'I':	/* indent amount */
35115552Sralph 			strncpy(indent+2, line+1, sizeof(indent)-3);
35212581Sralph 			continue;
35312581Sralph 
35412111Sralph 		default:	/* some file to print */
35515811Sralph 			switch (i = print(line[0], line+1)) {
35617463Sralph 			case ERROR:
35717463Sralph 				if (bombed == OK)
35817463Sralph 					bombed = FATALERR;
35915811Sralph 				break;
36017463Sralph 			case REPRINT:
36112111Sralph 				(void) fclose(cfp);
36217463Sralph 				return(REPRINT);
36317463Sralph 			case FILTERERR:
36417463Sralph 			case ACCESS:
36517463Sralph 				bombed = i;
36615811Sralph 				sendmail(logname, bombed);
36715811Sralph 			}
36812111Sralph 			title[0] = '\0';
36912111Sralph 			continue;
37012111Sralph 
37112111Sralph 		case 'N':
37212111Sralph 		case 'U':
37312111Sralph 		case 'M':
37412111Sralph 			continue;
37512111Sralph 		}
37612111Sralph 
37712111Sralph 	/* pass 2 */
37812111Sralph 
37912463Sralph pass2:
38012111Sralph 	fseek(cfp, 0L, 0);
38112111Sralph 	while (getline(cfp))
38212111Sralph 		switch (line[0]) {
38318127Sralph 		case 'L':	/* identification line */
38418127Sralph 			if (!SH && HL)
38518127Sralph 				banner(line+1, jobname);
38618127Sralph 			continue;
38718127Sralph 
38812111Sralph 		case 'M':
38917463Sralph 			if (bombed < NOACCT)	/* already sent if >= NOACCT */
39015811Sralph 				sendmail(line+1, bombed);
39112111Sralph 			continue;
39212111Sralph 
39312111Sralph 		case 'U':
39412111Sralph 			(void) unlink(line+1);
39512111Sralph 		}
39612111Sralph 	/*
39715811Sralph 	 * clean-up in case another control file exists
39812111Sralph 	 */
39912111Sralph 	(void) fclose(cfp);
40012111Sralph 	(void) unlink(file);
40117463Sralph 	return(bombed == OK ? OK : ERROR);
40212111Sralph }
40312111Sralph 
40412111Sralph /*
40512111Sralph  * Print a file.
40613233Sralph  * Set up the chain [ PR [ | {IF, OF} ] ] or {IF, RF, TF, NF, DF, CF, VF}.
40715811Sralph  * Return -1 if a non-recoverable error occured,
40815811Sralph  * 2 if the filter detected some errors (but printed the job anyway),
40915811Sralph  * 1 if we should try to reprint this job and
41012111Sralph  * 0 if all is well.
41112111Sralph  * Note: all filters take stdin as the file, stdout as the printer,
41212111Sralph  * stderr as the log file, and must not ignore SIGINT.
41312111Sralph  */
41412111Sralph print(format, file)
41512111Sralph 	int format;
41612111Sralph 	char *file;
41712111Sralph {
41815811Sralph 	register int n;
41912111Sralph 	register char *prog;
42015811Sralph 	int fi, fo;
42139954Smckusick 	FILE *fp;
42212111Sralph 	char *av[15], buf[BUFSIZ];
42312111Sralph 	int pid, p[2], stopped = 0;
42412111Sralph 	union wait status;
42517463Sralph 	struct stat stb;
42612111Sralph 
42717463Sralph 	if (lstat(file, &stb) < 0 || (fi = open(file, O_RDONLY)) < 0)
42817463Sralph 		return(ERROR);
42917463Sralph 	/*
43017463Sralph 	 * Check to see if data file is a symbolic link. If so, it should
43117463Sralph 	 * still point to the same file or someone is trying to print
43217463Sralph 	 * something he shouldn't.
43317463Sralph 	 */
43417463Sralph 	if ((stb.st_mode & S_IFMT) == S_IFLNK && fstat(fi, &stb) == 0 &&
43517463Sralph 	    (stb.st_dev != fdev || stb.st_ino != fino))
43617463Sralph 		return(ACCESS);
43712111Sralph 	if (!SF && !tof) {		/* start on a fresh page */
43812111Sralph 		(void) write(ofd, FF, strlen(FF));
43912111Sralph 		tof = 1;
44012111Sralph 	}
44112111Sralph 	if (IF == NULL && (format == 'f' || format == 'l')) {
44212111Sralph 		tof = 0;
44312111Sralph 		while ((n = read(fi, buf, BUFSIZ)) > 0)
44412111Sralph 			if (write(ofd, buf, n) != n) {
44512111Sralph 				(void) close(fi);
44617463Sralph 				return(REPRINT);
44712111Sralph 			}
44812111Sralph 		(void) close(fi);
44917463Sralph 		return(OK);
45012111Sralph 	}
45112111Sralph 	switch (format) {
45212111Sralph 	case 'p':	/* print file using 'pr' */
45312111Sralph 		if (IF == NULL) {	/* use output filter */
45437968Sbostic 			prog = _PATH_PR;
45512111Sralph 			av[0] = "pr";
45612111Sralph 			av[1] = width;
45712111Sralph 			av[2] = length;
45812111Sralph 			av[3] = "-h";
45912111Sralph 			av[4] = *title ? title : " ";
46012111Sralph 			av[5] = 0;
46112111Sralph 			fo = ofd;
46212111Sralph 			goto start;
46312111Sralph 		}
46412111Sralph 		pipe(p);
46512111Sralph 		if ((prchild = dofork(DORETURN)) == 0) {	/* child */
46612111Sralph 			dup2(fi, 0);		/* file is stdin */
46712111Sralph 			dup2(p[1], 1);		/* pipe is stdout */
46812111Sralph 			for (n = 3; n < NOFILE; n++)
46912111Sralph 				(void) close(n);
47037968Sbostic 			execl(_PATH_PR, "pr", width, length,
47137968Sbostic 			    "-h", *title ? title : " ", 0);
47237968Sbostic 			syslog(LOG_ERR, "cannot execl %s", _PATH_PR);
47312111Sralph 			exit(2);
47412111Sralph 		}
47512111Sralph 		(void) close(p[1]);		/* close output side */
47612111Sralph 		(void) close(fi);
47712111Sralph 		if (prchild < 0) {
47812111Sralph 			prchild = 0;
47912111Sralph 			(void) close(p[0]);
48017463Sralph 			return(ERROR);
48112111Sralph 		}
48212111Sralph 		fi = p[0];			/* use pipe for input */
48312111Sralph 	case 'f':	/* print plain text file */
48412111Sralph 		prog = IF;
48512111Sralph 		av[1] = width;
48612111Sralph 		av[2] = length;
48712581Sralph 		av[3] = indent;
48812581Sralph 		n = 4;
48912111Sralph 		break;
49012111Sralph 	case 'l':	/* like 'f' but pass control characters */
49112111Sralph 		prog = IF;
49214325Sralph 		av[1] = "-c";
49312111Sralph 		av[2] = width;
49412111Sralph 		av[3] = length;
49512581Sralph 		av[4] = indent;
49612581Sralph 		n = 5;
49712111Sralph 		break;
49812463Sralph 	case 'r':	/* print a fortran text file */
49912463Sralph 		prog = RF;
50012463Sralph 		av[1] = width;
50112463Sralph 		av[2] = length;
50212463Sralph 		n = 3;
50312463Sralph 		break;
50412111Sralph 	case 't':	/* print troff output */
50513233Sralph 	case 'n':	/* print ditroff output */
50612463Sralph 	case 'd':	/* print tex output */
50712111Sralph 		(void) unlink(".railmag");
50812463Sralph 		if ((fo = creat(".railmag", FILMOD)) < 0) {
50916762Sralph 			syslog(LOG_ERR, "%s: cannot create .railmag", printer);
51012111Sralph 			(void) unlink(".railmag");
51112111Sralph 		} else {
51212111Sralph 			for (n = 0; n < 4; n++) {
51312111Sralph 				if (fonts[n][0] != '/')
51437968Sbostic 					(void) write(fo, _PATH_VFONT, 15);
51512111Sralph 				(void) write(fo, fonts[n], strlen(fonts[n]));
51612111Sralph 				(void) write(fo, "\n", 1);
51712111Sralph 			}
51812111Sralph 			(void) close(fo);
51912111Sralph 		}
52013233Sralph 		prog = (format == 't') ? TF : (format == 'n') ? NF : DF;
52112463Sralph 		av[1] = pxwidth;
52212463Sralph 		av[2] = pxlength;
52312463Sralph 		n = 3;
52412111Sralph 		break;
52512111Sralph 	case 'c':	/* print cifplot output */
52612111Sralph 		prog = CF;
52712463Sralph 		av[1] = pxwidth;
52812463Sralph 		av[2] = pxlength;
52912463Sralph 		n = 3;
53012111Sralph 		break;
53112111Sralph 	case 'g':	/* print plot(1G) output */
53212111Sralph 		prog = GF;
53312463Sralph 		av[1] = pxwidth;
53412463Sralph 		av[2] = pxlength;
53512463Sralph 		n = 3;
53612111Sralph 		break;
53712111Sralph 	case 'v':	/* print raster output */
53812111Sralph 		prog = VF;
53912463Sralph 		av[1] = pxwidth;
54012463Sralph 		av[2] = pxlength;
54112463Sralph 		n = 3;
54212111Sralph 		break;
54312111Sralph 	default:
54412111Sralph 		(void) close(fi);
54516762Sralph 		syslog(LOG_ERR, "%s: illegal format character '%c'",
54616762Sralph 			printer, format);
54717463Sralph 		return(ERROR);
54812111Sralph 	}
54912111Sralph 	if ((av[0] = rindex(prog, '/')) != NULL)
55012111Sralph 		av[0]++;
55112111Sralph 	else
55212111Sralph 		av[0] = prog;
55312111Sralph 	av[n++] = "-n";
55412111Sralph 	av[n++] = logname;
55512111Sralph 	av[n++] = "-h";
55614150Sralph 	av[n++] = fromhost;
55712111Sralph 	av[n++] = AF;
55812111Sralph 	av[n] = 0;
55912111Sralph 	fo = pfd;
56012111Sralph 	if (ofilter > 0) {		/* stop output filter */
56112111Sralph 		write(ofd, "\031\1", 2);
562*46912Sbostic 		while ((pid =
563*46912Sbostic 		    wait3((int *)&status, WUNTRACED, 0)) > 0 && pid != ofilter)
56412111Sralph 			;
56512111Sralph 		if (status.w_stopval != WSTOPPED) {
56612111Sralph 			(void) close(fi);
56716762Sralph 			syslog(LOG_WARNING, "%s: output filter died (%d)",
56816762Sralph 				printer, status.w_retcode);
56917463Sralph 			return(REPRINT);
57012111Sralph 		}
57112111Sralph 		stopped++;
57212111Sralph 	}
57312111Sralph start:
57412111Sralph 	if ((child = dofork(DORETURN)) == 0) {	/* child */
57512111Sralph 		dup2(fi, 0);
57612111Sralph 		dup2(fo, 1);
57739954Smckusick 		n = open(tempfile, O_WRONLY|O_CREAT|O_TRUNC, 0664);
57815811Sralph 		if (n >= 0)
57915811Sralph 			dup2(n, 2);
58012111Sralph 		for (n = 3; n < NOFILE; n++)
58112111Sralph 			(void) close(n);
58212111Sralph 		execv(prog, av);
58316762Sralph 		syslog(LOG_ERR, "cannot execv %s", prog);
58412111Sralph 		exit(2);
58512111Sralph 	}
58612111Sralph 	(void) close(fi);
58712111Sralph 	if (child < 0)
58812111Sralph 		status.w_retcode = 100;
58912111Sralph 	else
590*46912Sbostic 		while ((pid = wait((int *)&status)) > 0 && pid != child)
59112111Sralph 			;
59212111Sralph 	child = 0;
59312111Sralph 	prchild = 0;
59412111Sralph 	if (stopped) {		/* restart output filter */
59512111Sralph 		if (kill(ofilter, SIGCONT) < 0) {
59616762Sralph 			syslog(LOG_ERR, "cannot restart output filter");
59712111Sralph 			exit(1);
59812111Sralph 		}
59912111Sralph 	}
60012111Sralph 	tof = 0;
60139954Smckusick 
60239954Smckusick 	/* Copy filter output to "lf" logfile */
60339954Smckusick 	if (fp = fopen(tempfile, "r")) {
60439954Smckusick 		char tbuf[512];
60539954Smckusick 
60639954Smckusick 		while (fgets(buf, sizeof(buf), fp))
60739954Smckusick 			fputs(buf, stderr);
60839954Smckusick 		close(fp);
60939954Smckusick 	}
61039954Smckusick 
61115811Sralph 	if (!WIFEXITED(status)) {
61216762Sralph 		syslog(LOG_WARNING, "%s: Daemon filter '%c' terminated (%d)",
61316762Sralph 			printer, format, status.w_termsig);
61417463Sralph 		return(ERROR);
61517463Sralph 	}
61617463Sralph 	switch (status.w_retcode) {
61717463Sralph 	case 0:
61817463Sralph 		tof = 1;
61917463Sralph 		return(OK);
62017463Sralph 	case 1:
62117463Sralph 		return(REPRINT);
62217463Sralph 	default:
62316762Sralph 		syslog(LOG_WARNING, "%s: Daemon filter '%c' exited (%d)",
62416762Sralph 			printer, format, status.w_retcode);
62517463Sralph 	case 2:
62617463Sralph 		return(ERROR);
62717463Sralph 	}
62812111Sralph }
62912111Sralph 
63012111Sralph /*
63112111Sralph  * Send the daemon control file (cf) and any data files.
63212111Sralph  * Return -1 if a non-recoverable error occured, 1 if a recoverable error and
63312111Sralph  * 0 if all is well.
63412111Sralph  */
63512111Sralph sendit(file)
63612111Sralph 	char *file;
63712111Sralph {
63817463Sralph 	register int i, err = OK;
63917463Sralph 	char *cp, last[BUFSIZ];
64012111Sralph 
64112111Sralph 	/*
64212111Sralph 	 * open control file
64312111Sralph 	 */
64416762Sralph 	if ((cfp = fopen(file, "r")) == NULL)
64517463Sralph 		return(OK);
64612111Sralph 	/*
64712111Sralph 	 *      read the control file for work to do
64812111Sralph 	 *
64912111Sralph 	 *      file format -- first character in the line is a command
65012111Sralph 	 *      rest of the line is the argument.
65112111Sralph 	 *      commands of interest are:
65212111Sralph 	 *
65312111Sralph 	 *            a-z -- "file name" name of file to print
65412111Sralph 	 *              U -- "unlink" name of file to remove
65512111Sralph 	 *                    (after we print it. (Pass 2 only)).
65612111Sralph 	 */
65712111Sralph 
65812111Sralph 	/*
65912111Sralph 	 * pass 1
66012111Sralph 	 */
66112111Sralph 	while (getline(cfp)) {
66212111Sralph 	again:
66317463Sralph 		if (line[0] == 'S') {
66417463Sralph 			cp = line+1;
66517463Sralph 			i = 0;
66617463Sralph 			while (*cp >= '0' && *cp <= '9')
66717463Sralph 				i = i * 10 + (*cp++ - '0');
66817463Sralph 			fdev = i;
66917463Sralph 			cp++;
67017463Sralph 			i = 0;
67117463Sralph 			while (*cp >= '0' && *cp <= '9')
67217463Sralph 				i = i * 10 + (*cp++ - '0');
67317463Sralph 			fino = i;
67417463Sralph 			continue;
67517463Sralph 		}
67612111Sralph 		if (line[0] >= 'a' && line[0] <= 'z') {
67712111Sralph 			strcpy(last, line);
67817463Sralph 			while (i = getline(cfp))
67912111Sralph 				if (strcmp(last, line))
68012111Sralph 					break;
68117463Sralph 			switch (sendfile('\3', last+1)) {
68217463Sralph 			case OK:
68317463Sralph 				if (i)
68417463Sralph 					goto again;
68517463Sralph 				break;
68617463Sralph 			case REPRINT:
68712111Sralph 				(void) fclose(cfp);
68817463Sralph 				return(REPRINT);
68917463Sralph 			case ACCESS:
69017463Sralph 				sendmail(logname, ACCESS);
69117463Sralph 			case ERROR:
69217463Sralph 				err = ERROR;
69317463Sralph 			}
69412111Sralph 			break;
69512111Sralph 		}
69612111Sralph 	}
69717463Sralph 	if (err == OK && sendfile('\2', file) > 0) {
69812111Sralph 		(void) fclose(cfp);
69917463Sralph 		return(REPRINT);
70012111Sralph 	}
70112111Sralph 	/*
70212111Sralph 	 * pass 2
70312111Sralph 	 */
70412111Sralph 	fseek(cfp, 0L, 0);
70512111Sralph 	while (getline(cfp))
70612111Sralph 		if (line[0] == 'U')
70712111Sralph 			(void) unlink(line+1);
70812111Sralph 	/*
70917463Sralph 	 * clean-up in case another control file exists
71012111Sralph 	 */
71112111Sralph 	(void) fclose(cfp);
71212111Sralph 	(void) unlink(file);
71317463Sralph 	return(err);
71412111Sralph }
71512111Sralph 
71612111Sralph /*
71712111Sralph  * Send a data file to the remote machine and spool it.
71812111Sralph  * Return positive if we should try resending.
71912111Sralph  */
72012111Sralph sendfile(type, file)
72112111Sralph 	char type, *file;
72212111Sralph {
72312111Sralph 	register int f, i, amt;
72412111Sralph 	struct stat stb;
72512111Sralph 	char buf[BUFSIZ];
72616762Sralph 	int sizerr, resp;
72712111Sralph 
72817463Sralph 	if (lstat(file, &stb) < 0 || (f = open(file, O_RDONLY)) < 0)
72917463Sralph 		return(ERROR);
73017463Sralph 	/*
73117463Sralph 	 * Check to see if data file is a symbolic link. If so, it should
73217463Sralph 	 * still point to the same file or someone is trying to print something
73317463Sralph 	 * he shouldn't.
73417463Sralph 	 */
73517463Sralph 	if ((stb.st_mode & S_IFMT) == S_IFLNK && fstat(f, &stb) == 0 &&
73617463Sralph 	    (stb.st_dev != fdev || stb.st_ino != fino))
73717463Sralph 		return(ACCESS);
73812111Sralph 	(void) sprintf(buf, "%c%d %s\n", type, stb.st_size, file);
73912111Sralph 	amt = strlen(buf);
74016762Sralph 	for (i = 0;  ; i++) {
74116762Sralph 		if (write(pfd, buf, amt) != amt ||
74216762Sralph 		    (resp = response()) < 0 || resp == '\1') {
74316762Sralph 			(void) close(f);
74417463Sralph 			return(REPRINT);
74516762Sralph 		} else if (resp == '\0')
74616762Sralph 			break;
74716762Sralph 		if (i == 0)
74816762Sralph 			status("no space on remote; waiting for queue to drain");
74916762Sralph 		if (i == 10)
75024861Seric 			syslog(LOG_ALERT, "%s: can't send to %s; queue full",
75116762Sralph 				printer, RM);
75216762Sralph 		sleep(5 * 60);
75312692Sralph 	}
75416762Sralph 	if (i)
75516762Sralph 		status("sending to %s", RM);
75612111Sralph 	sizerr = 0;
75712111Sralph 	for (i = 0; i < stb.st_size; i += BUFSIZ) {
75812111Sralph 		amt = BUFSIZ;
75912111Sralph 		if (i + amt > stb.st_size)
76012111Sralph 			amt = stb.st_size - i;
76112111Sralph 		if (sizerr == 0 && read(f, buf, amt) != amt)
76212111Sralph 			sizerr = 1;
76312692Sralph 		if (write(pfd, buf, amt) != amt) {
76412692Sralph 			(void) close(f);
76517463Sralph 			return(REPRINT);
76612692Sralph 		}
76712111Sralph 	}
76812111Sralph 	(void) close(f);
76912111Sralph 	if (sizerr) {
77016762Sralph 		syslog(LOG_INFO, "%s: %s: changed size", printer, file);
77117463Sralph 		/* tell recvjob to ignore this file */
77217463Sralph 		(void) write(pfd, "\1", 1);
77317463Sralph 		return(ERROR);
77417463Sralph 	}
77517463Sralph 	if (write(pfd, "", 1) != 1 || response())
77617463Sralph 		return(REPRINT);
77717463Sralph 	return(OK);
77812111Sralph }
77912111Sralph 
78012111Sralph /*
78112111Sralph  * Check to make sure there have been no errors and that both programs
78212111Sralph  * are in sync with eachother.
78312111Sralph  * Return non-zero if the connection was lost.
78412111Sralph  */
78516762Sralph response()
78612111Sralph {
78712111Sralph 	char resp;
78812111Sralph 
78916762Sralph 	if (read(pfd, &resp, 1) != 1) {
79016762Sralph 		syslog(LOG_INFO, "%s: lost connection", printer);
79116762Sralph 		return(-1);
79212111Sralph 	}
79316762Sralph 	return(resp);
79412111Sralph }
79512111Sralph 
79612111Sralph /*
79712111Sralph  * Banner printing stuff
79812111Sralph  */
79912111Sralph banner(name1, name2)
80012111Sralph 	char *name1, *name2;
80112111Sralph {
80212111Sralph 	time_t tvec;
80312111Sralph 	extern char *ctime();
80412111Sralph 
80512111Sralph 	time(&tvec);
80612111Sralph 	if (!SF && !tof)
80712111Sralph 		(void) write(ofd, FF, strlen(FF));
80812111Sralph 	if (SB) {	/* short banner only */
80912111Sralph 		if (class[0]) {
81012111Sralph 			(void) write(ofd, class, strlen(class));
81112111Sralph 			(void) write(ofd, ":", 1);
81212111Sralph 		}
81312111Sralph 		(void) write(ofd, name1, strlen(name1));
81412111Sralph 		(void) write(ofd, "  Job: ", 7);
81512111Sralph 		(void) write(ofd, name2, strlen(name2));
81612111Sralph 		(void) write(ofd, "  Date: ", 8);
81712111Sralph 		(void) write(ofd, ctime(&tvec), 24);
81812111Sralph 		(void) write(ofd, "\n", 1);
81912111Sralph 	} else {	/* normal banner */
82012111Sralph 		(void) write(ofd, "\n\n\n", 3);
82112111Sralph 		scan_out(ofd, name1, '\0');
82212111Sralph 		(void) write(ofd, "\n\n", 2);
82312111Sralph 		scan_out(ofd, name2, '\0');
82412111Sralph 		if (class[0]) {
82512111Sralph 			(void) write(ofd,"\n\n\n",3);
82612111Sralph 			scan_out(ofd, class, '\0');
82712111Sralph 		}
82812111Sralph 		(void) write(ofd, "\n\n\n\n\t\t\t\t\tJob:  ", 15);
82912111Sralph 		(void) write(ofd, name2, strlen(name2));
83012111Sralph 		(void) write(ofd, "\n\t\t\t\t\tDate: ", 12);
83112111Sralph 		(void) write(ofd, ctime(&tvec), 24);
83212111Sralph 		(void) write(ofd, "\n", 1);
83312111Sralph 	}
83412111Sralph 	if (!SF)
83512111Sralph 		(void) write(ofd, FF, strlen(FF));
83612111Sralph 	tof = 1;
83712111Sralph }
83812111Sralph 
83916762Sralph char *
84012111Sralph scnline(key, p, c)
84112111Sralph 	register char key, *p;
84212111Sralph 	char c;
84312111Sralph {
84412111Sralph 	register scnwidth;
84512111Sralph 
84612111Sralph 	for (scnwidth = WIDTH; --scnwidth;) {
84712111Sralph 		key <<= 1;
84812111Sralph 		*p++ = key & 0200 ? c : BACKGND;
84912111Sralph 	}
85012111Sralph 	return (p);
85112111Sralph }
85212111Sralph 
85312111Sralph #define TRC(q)	(((q)-' ')&0177)
85412111Sralph 
85512111Sralph scan_out(scfd, scsp, dlm)
85612111Sralph 	int scfd;
85712111Sralph 	char *scsp, dlm;
85812111Sralph {
85912111Sralph 	register char *strp;
86012111Sralph 	register nchrs, j;
86112111Sralph 	char outbuf[LINELEN+1], *sp, c, cc;
86212111Sralph 	int d, scnhgt;
86312111Sralph 	extern char scnkey[][HEIGHT];	/* in lpdchar.c */
86412111Sralph 
86512111Sralph 	for (scnhgt = 0; scnhgt++ < HEIGHT+DROP; ) {
86612111Sralph 		strp = &outbuf[0];
86712111Sralph 		sp = scsp;
86812111Sralph 		for (nchrs = 0; ; ) {
86912111Sralph 			d = dropit(c = TRC(cc = *sp++));
87012111Sralph 			if ((!d && scnhgt > HEIGHT) || (scnhgt <= DROP && d))
87112111Sralph 				for (j = WIDTH; --j;)
87212111Sralph 					*strp++ = BACKGND;
87312111Sralph 			else
87412111Sralph 				strp = scnline(scnkey[c][scnhgt-1-d], strp, cc);
87512111Sralph 			if (*sp == dlm || *sp == '\0' || nchrs++ >= PW/(WIDTH+1)-1)
87612111Sralph 				break;
87712111Sralph 			*strp++ = BACKGND;
87812111Sralph 			*strp++ = BACKGND;
87912111Sralph 		}
88012111Sralph 		while (*--strp == BACKGND && strp >= outbuf)
88112111Sralph 			;
88212111Sralph 		strp++;
88312111Sralph 		*strp++ = '\n';
88412111Sralph 		(void) write(scfd, outbuf, strp-outbuf);
88512111Sralph 	}
88612111Sralph }
88712111Sralph 
88812111Sralph dropit(c)
88912111Sralph 	char c;
89012111Sralph {
89112111Sralph 	switch(c) {
89212111Sralph 
89312111Sralph 	case TRC('_'):
89412111Sralph 	case TRC(';'):
89512111Sralph 	case TRC(','):
89612111Sralph 	case TRC('g'):
89712111Sralph 	case TRC('j'):
89812111Sralph 	case TRC('p'):
89912111Sralph 	case TRC('q'):
90012111Sralph 	case TRC('y'):
90112111Sralph 		return (DROP);
90212111Sralph 
90312111Sralph 	default:
90412111Sralph 		return (0);
90512111Sralph 	}
90612111Sralph }
90712111Sralph 
90812111Sralph /*
90912111Sralph  * sendmail ---
91012111Sralph  *   tell people about job completion
91112111Sralph  */
91215811Sralph sendmail(user, bombed)
91315811Sralph 	char *user;
91412111Sralph 	int bombed;
91512111Sralph {
91612111Sralph 	register int i;
91715811Sralph 	int p[2], s;
91812111Sralph 	register char *cp;
91912111Sralph 	char buf[100];
92015811Sralph 	struct stat stb;
92115811Sralph 	FILE *fp;
92212111Sralph 
92312111Sralph 	pipe(p);
92415811Sralph 	if ((s = dofork(DORETURN)) == 0) {		/* child */
92512111Sralph 		dup2(p[0], 0);
92612111Sralph 		for (i = 3; i < NOFILE; i++)
92712111Sralph 			(void) close(i);
92837968Sbostic 		if ((cp = rindex(_PATH_SENDMAIL, '/')) != NULL)
92912111Sralph 			cp++;
93012111Sralph 		else
93137968Sbostic 			cp = _PATH_SENDMAIL;
93215811Sralph 		sprintf(buf, "%s@%s", user, fromhost);
93337968Sbostic 		execl(_PATH_SENDMAIL, cp, buf, 0);
93412111Sralph 		exit(0);
93515811Sralph 	} else if (s > 0) {				/* parent */
93612111Sralph 		dup2(p[1], 1);
93715811Sralph 		printf("To: %s@%s\n", user, fromhost);
93812111Sralph 		printf("Subject: printer job\n\n");
93912111Sralph 		printf("Your printer job ");
94012111Sralph 		if (*jobname)
94112111Sralph 			printf("(%s) ", jobname);
94212463Sralph 		switch (bombed) {
94317463Sralph 		case OK:
94412463Sralph 			printf("\ncompleted successfully\n");
94512463Sralph 			break;
94612463Sralph 		default:
94717463Sralph 		case FATALERR:
94812463Sralph 			printf("\ncould not be printed\n");
94912463Sralph 			break;
95017463Sralph 		case NOACCT:
95112463Sralph 			printf("\ncould not be printed without an account on %s\n", host);
95212463Sralph 			break;
95317463Sralph 		case FILTERERR:
95439954Smckusick 			if (stat(tempfile, &stb) < 0 || stb.st_size == 0 ||
95539954Smckusick 			    (fp = fopen(tempfile, "r")) == NULL) {
95615811Sralph 				printf("\nwas printed but had some errors\n");
95715811Sralph 				break;
95815811Sralph 			}
95915811Sralph 			printf("\nwas printed but had the following errors:\n");
96015811Sralph 			while ((i = getc(fp)) != EOF)
96115811Sralph 				putchar(i);
96215811Sralph 			(void) fclose(fp);
96317463Sralph 			break;
96417463Sralph 		case ACCESS:
96517463Sralph 			printf("\nwas not printed because it was not linked to the original file\n");
96612463Sralph 		}
96712111Sralph 		fflush(stdout);
96812111Sralph 		(void) close(1);
96912111Sralph 	}
97012111Sralph 	(void) close(p[0]);
97112111Sralph 	(void) close(p[1]);
97215811Sralph 	wait(&s);
97312111Sralph }
97412111Sralph 
97512111Sralph /*
97612111Sralph  * dofork - fork with retries on failure
97712111Sralph  */
97812111Sralph dofork(action)
97912111Sralph 	int action;
98012111Sralph {
98112111Sralph 	register int i, pid;
98212111Sralph 
98312111Sralph 	for (i = 0; i < 20; i++) {
98412463Sralph 		if ((pid = fork()) < 0) {
98512111Sralph 			sleep((unsigned)(i*i));
98612463Sralph 			continue;
98712463Sralph 		}
98812463Sralph 		/*
98912463Sralph 		 * Child should run as daemon instead of root
99012463Sralph 		 */
99112463Sralph 		if (pid == 0)
99212463Sralph 			setuid(DU);
99312463Sralph 		return(pid);
99412111Sralph 	}
99516762Sralph 	syslog(LOG_ERR, "can't fork");
99612111Sralph 
99712111Sralph 	switch (action) {
99812111Sralph 	case DORETURN:
99912111Sralph 		return (-1);
100012111Sralph 	default:
100116762Sralph 		syslog(LOG_ERR, "bad action (%d) to dofork", action);
100212111Sralph 		/*FALL THRU*/
100312111Sralph 	case DOABORT:
100412111Sralph 		exit(1);
100512111Sralph 	}
100612111Sralph 	/*NOTREACHED*/
100712111Sralph }
100812111Sralph 
100912111Sralph /*
101016762Sralph  * Kill child processes to abort current job.
101112111Sralph  */
1012*46912Sbostic void
101316762Sralph abortpr()
101412111Sralph {
101539954Smckusick 	(void) unlink(tempfile);
101612111Sralph 	kill(0, SIGINT);
101712111Sralph 	if (ofilter > 0)
101812111Sralph 		kill(ofilter, SIGCONT);
1019*46912Sbostic 	while (wait(NULL) > 0)
102012111Sralph 		;
102112111Sralph 	exit(0);
102212111Sralph }
102312111Sralph 
102412111Sralph init()
102512111Sralph {
102612111Sralph 	int status;
102738736Stef 	char *s;
102812111Sralph 
102925468Stef 	if ((status = pgetent(line, printer)) < 0) {
103025468Stef 		syslog(LOG_ERR, "can't open printer description file");
103125468Stef 		exit(1);
103225468Stef 	} else if (status == 0) {
103325468Stef 		syslog(LOG_ERR, "unknown printer: %s", printer);
103425468Stef 		exit(1);
103525468Stef 	}
103612111Sralph 	if ((LP = pgetstr("lp", &bp)) == NULL)
103737968Sbostic 		LP = _PATH_DEFDEVLP;
103812111Sralph 	if ((RP = pgetstr("rp", &bp)) == NULL)
103912463Sralph 		RP = DEFLP;
104012111Sralph 	if ((LO = pgetstr("lo", &bp)) == NULL)
104112111Sralph 		LO = DEFLOCK;
104212111Sralph 	if ((ST = pgetstr("st", &bp)) == NULL)
104312111Sralph 		ST = DEFSTAT;
104412111Sralph 	if ((LF = pgetstr("lf", &bp)) == NULL)
104537968Sbostic 		LF = _PATH_CONSOLE;
104612111Sralph 	if ((SD = pgetstr("sd", &bp)) == NULL)
104737968Sbostic 		SD = _PATH_DEFSPOOL;
104812111Sralph 	if ((DU = pgetnum("du")) < 0)
104912111Sralph 		DU = DEFUID;
105012111Sralph 	if ((FF = pgetstr("ff", &bp)) == NULL)
105112111Sralph 		FF = DEFFF;
105212111Sralph 	if ((PW = pgetnum("pw")) < 0)
105312111Sralph 		PW = DEFWIDTH;
105412111Sralph 	sprintf(&width[2], "%d", PW);
105512111Sralph 	if ((PL = pgetnum("pl")) < 0)
105612111Sralph 		PL = DEFLENGTH;
105712111Sralph 	sprintf(&length[2], "%d", PL);
105812463Sralph 	if ((PX = pgetnum("px")) < 0)
105912463Sralph 		PX = 0;
106012463Sralph 	sprintf(&pxwidth[2], "%d", PX);
106112463Sralph 	if ((PY = pgetnum("py")) < 0)
106212463Sralph 		PY = 0;
106312463Sralph 	sprintf(&pxlength[2], "%d", PY);
106412111Sralph 	RM = pgetstr("rm", &bp);
106538736Stef 	if (s = checkremote())
106638736Stef 		syslog(LOG_WARNING, s);
106725468Stef 
106812111Sralph 	AF = pgetstr("af", &bp);
106912111Sralph 	OF = pgetstr("of", &bp);
107012111Sralph 	IF = pgetstr("if", &bp);
107112463Sralph 	RF = pgetstr("rf", &bp);
107212111Sralph 	TF = pgetstr("tf", &bp);
107313233Sralph 	NF = pgetstr("nf", &bp);
107412111Sralph 	DF = pgetstr("df", &bp);
107512111Sralph 	GF = pgetstr("gf", &bp);
107612111Sralph 	VF = pgetstr("vf", &bp);
107712111Sralph 	CF = pgetstr("cf", &bp);
107812111Sralph 	TR = pgetstr("tr", &bp);
107912463Sralph 	RS = pgetflag("rs");
108012111Sralph 	SF = pgetflag("sf");
108112111Sralph 	SH = pgetflag("sh");
108212111Sralph 	SB = pgetflag("sb");
108318127Sralph 	HL = pgetflag("hl");
108412111Sralph 	RW = pgetflag("rw");
108512111Sralph 	BR = pgetnum("br");
108612111Sralph 	if ((FC = pgetnum("fc")) < 0)
108712111Sralph 		FC = 0;
108812111Sralph 	if ((FS = pgetnum("fs")) < 0)
108912111Sralph 		FS = 0;
109012111Sralph 	if ((XC = pgetnum("xc")) < 0)
109112111Sralph 		XC = 0;
109212111Sralph 	if ((XS = pgetnum("xs")) < 0)
109312111Sralph 		XS = 0;
109412581Sralph 	tof = !pgetflag("fo");
109512111Sralph }
109612111Sralph 
109712463Sralph /*
109812463Sralph  * Acquire line printer or remote connection.
109912463Sralph  */
110012463Sralph openpr()
110112463Sralph {
110212463Sralph 	register int i, n;
110316762Sralph 	int resp;
110412463Sralph 
110538736Stef 	if (!sendtorem && *LP) {
110612463Sralph 		for (i = 1; ; i = i < 32 ? i << 1 : i) {
110713148Ssam 			pfd = open(LP, RW ? O_RDWR : O_WRONLY);
110812463Sralph 			if (pfd >= 0)
110912463Sralph 				break;
111012463Sralph 			if (errno == ENOENT) {
111116762Sralph 				syslog(LOG_ERR, "%s: %m", LP);
111212463Sralph 				exit(1);
111312463Sralph 			}
111412463Sralph 			if (i == 1)
111512463Sralph 				status("waiting for %s to become ready (offline ?)", printer);
111612463Sralph 			sleep(i);
111712463Sralph 		}
111812463Sralph 		if (isatty(pfd))
111912463Sralph 			setty();
112012463Sralph 		status("%s is ready and printing", printer);
112112463Sralph 	} else if (RM != NULL) {
112216762Sralph 		for (i = 1; ; i = i < 256 ? i << 1 : i) {
112316762Sralph 			resp = -1;
112412528Sralph 			pfd = getport(RM);
112512463Sralph 			if (pfd >= 0) {
112612463Sralph 				(void) sprintf(line, "\2%s\n", RP);
112712463Sralph 				n = strlen(line);
112816762Sralph 				if (write(pfd, line, n) == n &&
112916762Sralph 				    (resp = response()) == '\0')
113012463Sralph 					break;
113116031Sralph 				(void) close(pfd);
113212463Sralph 			}
113316031Sralph 			if (i == 1) {
113416762Sralph 				if (resp < 0)
113516031Sralph 					status("waiting for %s to come up", RM);
113616762Sralph 				else {
113716031Sralph 					status("waiting for queue to be enabled on %s", RM);
113816762Sralph 					i = 256;
113916762Sralph 				}
114016031Sralph 			}
114112463Sralph 			sleep(i);
114212463Sralph 		}
114312463Sralph 		status("sending to %s", RM);
114412463Sralph 		remote = 1;
114512463Sralph 	} else {
114616762Sralph 		syslog(LOG_ERR, "%s: no line printer device or host name",
114716762Sralph 			printer);
114812463Sralph 		exit(1);
114912463Sralph 	}
115012463Sralph 	/*
115112463Sralph 	 * Start up an output filter, if needed.
115212463Sralph 	 */
115340049Stef 	if (!remote && OF) {
115412463Sralph 		int p[2];
115512463Sralph 		char *cp;
115612463Sralph 
115712463Sralph 		pipe(p);
115812463Sralph 		if ((ofilter = dofork(DOABORT)) == 0) {	/* child */
115912463Sralph 			dup2(p[0], 0);		/* pipe is std in */
116012463Sralph 			dup2(pfd, 1);		/* printer is std out */
116112463Sralph 			for (i = 3; i < NOFILE; i++)
116212463Sralph 				(void) close(i);
116312463Sralph 			if ((cp = rindex(OF, '/')) == NULL)
116412463Sralph 				cp = OF;
116512463Sralph 			else
116612463Sralph 				cp++;
116712463Sralph 			execl(OF, cp, width, length, 0);
116816762Sralph 			syslog(LOG_ERR, "%s: %s: %m", printer, OF);
116912463Sralph 			exit(1);
117012463Sralph 		}
117112463Sralph 		(void) close(p[0]);		/* close input side */
117212463Sralph 		ofd = p[1];			/* use pipe for output */
117312463Sralph 	} else {
117412463Sralph 		ofd = pfd;
117512463Sralph 		ofilter = 0;
117612463Sralph 	}
117712463Sralph }
117812463Sralph 
117912111Sralph struct bauds {
118012111Sralph 	int	baud;
118112111Sralph 	int	speed;
118212111Sralph } bauds[] = {
118312111Sralph 	50,	B50,
118412111Sralph 	75,	B75,
118512111Sralph 	110,	B110,
118612111Sralph 	134,	B134,
118712111Sralph 	150,	B150,
118812111Sralph 	200,	B200,
118912111Sralph 	300,	B300,
119012111Sralph 	600,	B600,
119112111Sralph 	1200,	B1200,
119212111Sralph 	1800,	B1800,
119312111Sralph 	2400,	B2400,
119412111Sralph 	4800,	B4800,
119512111Sralph 	9600,	B9600,
119612111Sralph 	19200,	EXTA,
119712111Sralph 	38400,	EXTB,
119812111Sralph 	0,	0
119912111Sralph };
120012111Sralph 
120112111Sralph /*
120212111Sralph  * setup tty lines.
120312111Sralph  */
120412111Sralph setty()
120512111Sralph {
120612111Sralph 	struct sgttyb ttybuf;
120712111Sralph 	register struct bauds *bp;
120812111Sralph 
120912111Sralph 	if (ioctl(pfd, TIOCEXCL, (char *)0) < 0) {
121016762Sralph 		syslog(LOG_ERR, "%s: ioctl(TIOCEXCL): %m", printer);
121112111Sralph 		exit(1);
121212111Sralph 	}
121312111Sralph 	if (ioctl(pfd, TIOCGETP, (char *)&ttybuf) < 0) {
121416762Sralph 		syslog(LOG_ERR, "%s: ioctl(TIOCGETP): %m", printer);
121512111Sralph 		exit(1);
121612111Sralph 	}
121712111Sralph 	if (BR > 0) {
121812111Sralph 		for (bp = bauds; bp->baud; bp++)
121912111Sralph 			if (BR == bp->baud)
122012111Sralph 				break;
122112111Sralph 		if (!bp->baud) {
122216762Sralph 			syslog(LOG_ERR, "%s: illegal baud rate %d", printer, BR);
122312111Sralph 			exit(1);
122412111Sralph 		}
122512111Sralph 		ttybuf.sg_ispeed = ttybuf.sg_ospeed = bp->speed;
122612111Sralph 	}
122713169Sralph 	ttybuf.sg_flags &= ~FC;
122813169Sralph 	ttybuf.sg_flags |= FS;
122912111Sralph 	if (ioctl(pfd, TIOCSETP, (char *)&ttybuf) < 0) {
123016762Sralph 		syslog(LOG_ERR, "%s: ioctl(TIOCSETP): %m", printer);
123112111Sralph 		exit(1);
123212111Sralph 	}
123312111Sralph 	if (XC) {
123412111Sralph 		if (ioctl(pfd, TIOCLBIC, &XC) < 0) {
123516762Sralph 			syslog(LOG_ERR, "%s: ioctl(TIOCLBIC): %m", printer);
123612111Sralph 			exit(1);
123712111Sralph 		}
123812111Sralph 	}
123912111Sralph 	if (XS) {
124012111Sralph 		if (ioctl(pfd, TIOCLBIS, &XS) < 0) {
124116762Sralph 			syslog(LOG_ERR, "%s: ioctl(TIOCLBIS): %m", printer);
124212111Sralph 			exit(1);
124312111Sralph 		}
124412111Sralph 	}
124512111Sralph }
124612463Sralph 
124712463Sralph /*VARARGS1*/
124812463Sralph status(msg, a1, a2, a3)
124912463Sralph 	char *msg;
125012463Sralph {
125112463Sralph 	register int fd;
125212463Sralph 	char buf[BUFSIZ];
125312463Sralph 
125412463Sralph 	umask(0);
125513148Ssam 	fd = open(ST, O_WRONLY|O_CREAT, 0664);
125616762Sralph 	if (fd < 0 || flock(fd, LOCK_EX) < 0) {
125716762Sralph 		syslog(LOG_ERR, "%s: %s: %m", printer, ST);
125816762Sralph 		exit(1);
125916762Sralph 	}
126013148Ssam 	ftruncate(fd, 0);
126112463Sralph 	sprintf(buf, msg, a1, a2, a3);
126212463Sralph 	strcat(buf, "\n");
126312463Sralph 	(void) write(fd, buf, strlen(buf));
126412463Sralph 	(void) close(fd);
126512463Sralph }
1266