xref: /csrg-svn/usr.sbin/lpr/lpd/printjob.c (revision 54520)
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*54520Sbostic static char sccsid[] = "@(#)printjob.c	5.14 (Berkeley) 06/27/92";
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;
6946912Sbostic 	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] != '/')
514*54520Sbostic 					(void) write(fo, _PATH_VFONT,
515*54520Sbostic 					    sizeof(_PATH_VFONT) - 1);
51612111Sralph 				(void) write(fo, fonts[n], strlen(fonts[n]));
51712111Sralph 				(void) write(fo, "\n", 1);
51812111Sralph 			}
51912111Sralph 			(void) close(fo);
52012111Sralph 		}
52113233Sralph 		prog = (format == 't') ? TF : (format == 'n') ? NF : DF;
52212463Sralph 		av[1] = pxwidth;
52312463Sralph 		av[2] = pxlength;
52412463Sralph 		n = 3;
52512111Sralph 		break;
52612111Sralph 	case 'c':	/* print cifplot output */
52712111Sralph 		prog = CF;
52812463Sralph 		av[1] = pxwidth;
52912463Sralph 		av[2] = pxlength;
53012463Sralph 		n = 3;
53112111Sralph 		break;
53212111Sralph 	case 'g':	/* print plot(1G) output */
53312111Sralph 		prog = GF;
53412463Sralph 		av[1] = pxwidth;
53512463Sralph 		av[2] = pxlength;
53612463Sralph 		n = 3;
53712111Sralph 		break;
53812111Sralph 	case 'v':	/* print raster output */
53912111Sralph 		prog = VF;
54012463Sralph 		av[1] = pxwidth;
54112463Sralph 		av[2] = pxlength;
54212463Sralph 		n = 3;
54312111Sralph 		break;
54412111Sralph 	default:
54512111Sralph 		(void) close(fi);
54616762Sralph 		syslog(LOG_ERR, "%s: illegal format character '%c'",
54716762Sralph 			printer, format);
54817463Sralph 		return(ERROR);
54912111Sralph 	}
55012111Sralph 	if ((av[0] = rindex(prog, '/')) != NULL)
55112111Sralph 		av[0]++;
55212111Sralph 	else
55312111Sralph 		av[0] = prog;
55412111Sralph 	av[n++] = "-n";
55512111Sralph 	av[n++] = logname;
55612111Sralph 	av[n++] = "-h";
55714150Sralph 	av[n++] = fromhost;
55812111Sralph 	av[n++] = AF;
55912111Sralph 	av[n] = 0;
56012111Sralph 	fo = pfd;
56112111Sralph 	if (ofilter > 0) {		/* stop output filter */
56212111Sralph 		write(ofd, "\031\1", 2);
56346912Sbostic 		while ((pid =
56446912Sbostic 		    wait3((int *)&status, WUNTRACED, 0)) > 0 && pid != ofilter)
56512111Sralph 			;
56612111Sralph 		if (status.w_stopval != WSTOPPED) {
56712111Sralph 			(void) close(fi);
56816762Sralph 			syslog(LOG_WARNING, "%s: output filter died (%d)",
56916762Sralph 				printer, status.w_retcode);
57017463Sralph 			return(REPRINT);
57112111Sralph 		}
57212111Sralph 		stopped++;
57312111Sralph 	}
57412111Sralph start:
57512111Sralph 	if ((child = dofork(DORETURN)) == 0) {	/* child */
57612111Sralph 		dup2(fi, 0);
57712111Sralph 		dup2(fo, 1);
57839954Smckusick 		n = open(tempfile, O_WRONLY|O_CREAT|O_TRUNC, 0664);
57915811Sralph 		if (n >= 0)
58015811Sralph 			dup2(n, 2);
58112111Sralph 		for (n = 3; n < NOFILE; n++)
58212111Sralph 			(void) close(n);
58312111Sralph 		execv(prog, av);
58416762Sralph 		syslog(LOG_ERR, "cannot execv %s", prog);
58512111Sralph 		exit(2);
58612111Sralph 	}
58712111Sralph 	(void) close(fi);
58812111Sralph 	if (child < 0)
58912111Sralph 		status.w_retcode = 100;
59012111Sralph 	else
59146912Sbostic 		while ((pid = wait((int *)&status)) > 0 && pid != child)
59212111Sralph 			;
59312111Sralph 	child = 0;
59412111Sralph 	prchild = 0;
59512111Sralph 	if (stopped) {		/* restart output filter */
59612111Sralph 		if (kill(ofilter, SIGCONT) < 0) {
59716762Sralph 			syslog(LOG_ERR, "cannot restart output filter");
59812111Sralph 			exit(1);
59912111Sralph 		}
60012111Sralph 	}
60112111Sralph 	tof = 0;
60239954Smckusick 
60339954Smckusick 	/* Copy filter output to "lf" logfile */
60439954Smckusick 	if (fp = fopen(tempfile, "r")) {
60539954Smckusick 		char tbuf[512];
60639954Smckusick 
60739954Smckusick 		while (fgets(buf, sizeof(buf), fp))
60839954Smckusick 			fputs(buf, stderr);
60939954Smckusick 		close(fp);
61039954Smckusick 	}
61139954Smckusick 
61215811Sralph 	if (!WIFEXITED(status)) {
61316762Sralph 		syslog(LOG_WARNING, "%s: Daemon filter '%c' terminated (%d)",
61416762Sralph 			printer, format, status.w_termsig);
61517463Sralph 		return(ERROR);
61617463Sralph 	}
61717463Sralph 	switch (status.w_retcode) {
61817463Sralph 	case 0:
61917463Sralph 		tof = 1;
62017463Sralph 		return(OK);
62117463Sralph 	case 1:
62217463Sralph 		return(REPRINT);
62317463Sralph 	default:
62416762Sralph 		syslog(LOG_WARNING, "%s: Daemon filter '%c' exited (%d)",
62516762Sralph 			printer, format, status.w_retcode);
62617463Sralph 	case 2:
62717463Sralph 		return(ERROR);
62817463Sralph 	}
62912111Sralph }
63012111Sralph 
63112111Sralph /*
63212111Sralph  * Send the daemon control file (cf) and any data files.
63312111Sralph  * Return -1 if a non-recoverable error occured, 1 if a recoverable error and
63412111Sralph  * 0 if all is well.
63512111Sralph  */
63612111Sralph sendit(file)
63712111Sralph 	char *file;
63812111Sralph {
63917463Sralph 	register int i, err = OK;
64017463Sralph 	char *cp, last[BUFSIZ];
64112111Sralph 
64212111Sralph 	/*
64312111Sralph 	 * open control file
64412111Sralph 	 */
64516762Sralph 	if ((cfp = fopen(file, "r")) == NULL)
64617463Sralph 		return(OK);
64712111Sralph 	/*
64812111Sralph 	 *      read the control file for work to do
64912111Sralph 	 *
65012111Sralph 	 *      file format -- first character in the line is a command
65112111Sralph 	 *      rest of the line is the argument.
65212111Sralph 	 *      commands of interest are:
65312111Sralph 	 *
65412111Sralph 	 *            a-z -- "file name" name of file to print
65512111Sralph 	 *              U -- "unlink" name of file to remove
65612111Sralph 	 *                    (after we print it. (Pass 2 only)).
65712111Sralph 	 */
65812111Sralph 
65912111Sralph 	/*
66012111Sralph 	 * pass 1
66112111Sralph 	 */
66212111Sralph 	while (getline(cfp)) {
66312111Sralph 	again:
66417463Sralph 		if (line[0] == 'S') {
66517463Sralph 			cp = line+1;
66617463Sralph 			i = 0;
66717463Sralph 			while (*cp >= '0' && *cp <= '9')
66817463Sralph 				i = i * 10 + (*cp++ - '0');
66917463Sralph 			fdev = i;
67017463Sralph 			cp++;
67117463Sralph 			i = 0;
67217463Sralph 			while (*cp >= '0' && *cp <= '9')
67317463Sralph 				i = i * 10 + (*cp++ - '0');
67417463Sralph 			fino = i;
67517463Sralph 			continue;
67617463Sralph 		}
67712111Sralph 		if (line[0] >= 'a' && line[0] <= 'z') {
67812111Sralph 			strcpy(last, line);
67917463Sralph 			while (i = getline(cfp))
68012111Sralph 				if (strcmp(last, line))
68112111Sralph 					break;
68217463Sralph 			switch (sendfile('\3', last+1)) {
68317463Sralph 			case OK:
68417463Sralph 				if (i)
68517463Sralph 					goto again;
68617463Sralph 				break;
68717463Sralph 			case REPRINT:
68812111Sralph 				(void) fclose(cfp);
68917463Sralph 				return(REPRINT);
69017463Sralph 			case ACCESS:
69117463Sralph 				sendmail(logname, ACCESS);
69217463Sralph 			case ERROR:
69317463Sralph 				err = ERROR;
69417463Sralph 			}
69512111Sralph 			break;
69612111Sralph 		}
69712111Sralph 	}
69817463Sralph 	if (err == OK && sendfile('\2', file) > 0) {
69912111Sralph 		(void) fclose(cfp);
70017463Sralph 		return(REPRINT);
70112111Sralph 	}
70212111Sralph 	/*
70312111Sralph 	 * pass 2
70412111Sralph 	 */
70512111Sralph 	fseek(cfp, 0L, 0);
70612111Sralph 	while (getline(cfp))
70712111Sralph 		if (line[0] == 'U')
70812111Sralph 			(void) unlink(line+1);
70912111Sralph 	/*
71017463Sralph 	 * clean-up in case another control file exists
71112111Sralph 	 */
71212111Sralph 	(void) fclose(cfp);
71312111Sralph 	(void) unlink(file);
71417463Sralph 	return(err);
71512111Sralph }
71612111Sralph 
71712111Sralph /*
71812111Sralph  * Send a data file to the remote machine and spool it.
71912111Sralph  * Return positive if we should try resending.
72012111Sralph  */
72112111Sralph sendfile(type, file)
72212111Sralph 	char type, *file;
72312111Sralph {
72412111Sralph 	register int f, i, amt;
72512111Sralph 	struct stat stb;
72612111Sralph 	char buf[BUFSIZ];
72716762Sralph 	int sizerr, resp;
72812111Sralph 
72917463Sralph 	if (lstat(file, &stb) < 0 || (f = open(file, O_RDONLY)) < 0)
73017463Sralph 		return(ERROR);
73117463Sralph 	/*
73217463Sralph 	 * Check to see if data file is a symbolic link. If so, it should
73317463Sralph 	 * still point to the same file or someone is trying to print something
73417463Sralph 	 * he shouldn't.
73517463Sralph 	 */
73617463Sralph 	if ((stb.st_mode & S_IFMT) == S_IFLNK && fstat(f, &stb) == 0 &&
73717463Sralph 	    (stb.st_dev != fdev || stb.st_ino != fino))
73817463Sralph 		return(ACCESS);
73912111Sralph 	(void) sprintf(buf, "%c%d %s\n", type, stb.st_size, file);
74012111Sralph 	amt = strlen(buf);
74116762Sralph 	for (i = 0;  ; i++) {
74216762Sralph 		if (write(pfd, buf, amt) != amt ||
74316762Sralph 		    (resp = response()) < 0 || resp == '\1') {
74416762Sralph 			(void) close(f);
74517463Sralph 			return(REPRINT);
74616762Sralph 		} else if (resp == '\0')
74716762Sralph 			break;
74816762Sralph 		if (i == 0)
74916762Sralph 			status("no space on remote; waiting for queue to drain");
75016762Sralph 		if (i == 10)
75124861Seric 			syslog(LOG_ALERT, "%s: can't send to %s; queue full",
75216762Sralph 				printer, RM);
75316762Sralph 		sleep(5 * 60);
75412692Sralph 	}
75516762Sralph 	if (i)
75616762Sralph 		status("sending to %s", RM);
75712111Sralph 	sizerr = 0;
75812111Sralph 	for (i = 0; i < stb.st_size; i += BUFSIZ) {
75912111Sralph 		amt = BUFSIZ;
76012111Sralph 		if (i + amt > stb.st_size)
76112111Sralph 			amt = stb.st_size - i;
76212111Sralph 		if (sizerr == 0 && read(f, buf, amt) != amt)
76312111Sralph 			sizerr = 1;
76412692Sralph 		if (write(pfd, buf, amt) != amt) {
76512692Sralph 			(void) close(f);
76617463Sralph 			return(REPRINT);
76712692Sralph 		}
76812111Sralph 	}
76912111Sralph 	(void) close(f);
77012111Sralph 	if (sizerr) {
77116762Sralph 		syslog(LOG_INFO, "%s: %s: changed size", printer, file);
77217463Sralph 		/* tell recvjob to ignore this file */
77317463Sralph 		(void) write(pfd, "\1", 1);
77417463Sralph 		return(ERROR);
77517463Sralph 	}
77617463Sralph 	if (write(pfd, "", 1) != 1 || response())
77717463Sralph 		return(REPRINT);
77817463Sralph 	return(OK);
77912111Sralph }
78012111Sralph 
78112111Sralph /*
78212111Sralph  * Check to make sure there have been no errors and that both programs
78312111Sralph  * are in sync with eachother.
78412111Sralph  * Return non-zero if the connection was lost.
78512111Sralph  */
78616762Sralph response()
78712111Sralph {
78812111Sralph 	char resp;
78912111Sralph 
79016762Sralph 	if (read(pfd, &resp, 1) != 1) {
79116762Sralph 		syslog(LOG_INFO, "%s: lost connection", printer);
79216762Sralph 		return(-1);
79312111Sralph 	}
79416762Sralph 	return(resp);
79512111Sralph }
79612111Sralph 
79712111Sralph /*
79812111Sralph  * Banner printing stuff
79912111Sralph  */
80012111Sralph banner(name1, name2)
80112111Sralph 	char *name1, *name2;
80212111Sralph {
80312111Sralph 	time_t tvec;
80412111Sralph 	extern char *ctime();
80512111Sralph 
80612111Sralph 	time(&tvec);
80712111Sralph 	if (!SF && !tof)
80812111Sralph 		(void) write(ofd, FF, strlen(FF));
80912111Sralph 	if (SB) {	/* short banner only */
81012111Sralph 		if (class[0]) {
81112111Sralph 			(void) write(ofd, class, strlen(class));
81212111Sralph 			(void) write(ofd, ":", 1);
81312111Sralph 		}
81412111Sralph 		(void) write(ofd, name1, strlen(name1));
81512111Sralph 		(void) write(ofd, "  Job: ", 7);
81612111Sralph 		(void) write(ofd, name2, strlen(name2));
81712111Sralph 		(void) write(ofd, "  Date: ", 8);
81812111Sralph 		(void) write(ofd, ctime(&tvec), 24);
81912111Sralph 		(void) write(ofd, "\n", 1);
82012111Sralph 	} else {	/* normal banner */
82112111Sralph 		(void) write(ofd, "\n\n\n", 3);
82212111Sralph 		scan_out(ofd, name1, '\0');
82312111Sralph 		(void) write(ofd, "\n\n", 2);
82412111Sralph 		scan_out(ofd, name2, '\0');
82512111Sralph 		if (class[0]) {
82612111Sralph 			(void) write(ofd,"\n\n\n",3);
82712111Sralph 			scan_out(ofd, class, '\0');
82812111Sralph 		}
82912111Sralph 		(void) write(ofd, "\n\n\n\n\t\t\t\t\tJob:  ", 15);
83012111Sralph 		(void) write(ofd, name2, strlen(name2));
83112111Sralph 		(void) write(ofd, "\n\t\t\t\t\tDate: ", 12);
83212111Sralph 		(void) write(ofd, ctime(&tvec), 24);
83312111Sralph 		(void) write(ofd, "\n", 1);
83412111Sralph 	}
83512111Sralph 	if (!SF)
83612111Sralph 		(void) write(ofd, FF, strlen(FF));
83712111Sralph 	tof = 1;
83812111Sralph }
83912111Sralph 
84016762Sralph char *
84112111Sralph scnline(key, p, c)
84212111Sralph 	register char key, *p;
84312111Sralph 	char c;
84412111Sralph {
84512111Sralph 	register scnwidth;
84612111Sralph 
84712111Sralph 	for (scnwidth = WIDTH; --scnwidth;) {
84812111Sralph 		key <<= 1;
84912111Sralph 		*p++ = key & 0200 ? c : BACKGND;
85012111Sralph 	}
85112111Sralph 	return (p);
85212111Sralph }
85312111Sralph 
85412111Sralph #define TRC(q)	(((q)-' ')&0177)
85512111Sralph 
85612111Sralph scan_out(scfd, scsp, dlm)
85712111Sralph 	int scfd;
85812111Sralph 	char *scsp, dlm;
85912111Sralph {
86012111Sralph 	register char *strp;
86112111Sralph 	register nchrs, j;
86212111Sralph 	char outbuf[LINELEN+1], *sp, c, cc;
86312111Sralph 	int d, scnhgt;
86412111Sralph 	extern char scnkey[][HEIGHT];	/* in lpdchar.c */
86512111Sralph 
86612111Sralph 	for (scnhgt = 0; scnhgt++ < HEIGHT+DROP; ) {
86712111Sralph 		strp = &outbuf[0];
86812111Sralph 		sp = scsp;
86912111Sralph 		for (nchrs = 0; ; ) {
87012111Sralph 			d = dropit(c = TRC(cc = *sp++));
87112111Sralph 			if ((!d && scnhgt > HEIGHT) || (scnhgt <= DROP && d))
87212111Sralph 				for (j = WIDTH; --j;)
87312111Sralph 					*strp++ = BACKGND;
87412111Sralph 			else
87512111Sralph 				strp = scnline(scnkey[c][scnhgt-1-d], strp, cc);
87612111Sralph 			if (*sp == dlm || *sp == '\0' || nchrs++ >= PW/(WIDTH+1)-1)
87712111Sralph 				break;
87812111Sralph 			*strp++ = BACKGND;
87912111Sralph 			*strp++ = BACKGND;
88012111Sralph 		}
88112111Sralph 		while (*--strp == BACKGND && strp >= outbuf)
88212111Sralph 			;
88312111Sralph 		strp++;
88412111Sralph 		*strp++ = '\n';
88512111Sralph 		(void) write(scfd, outbuf, strp-outbuf);
88612111Sralph 	}
88712111Sralph }
88812111Sralph 
88912111Sralph dropit(c)
89012111Sralph 	char c;
89112111Sralph {
89212111Sralph 	switch(c) {
89312111Sralph 
89412111Sralph 	case TRC('_'):
89512111Sralph 	case TRC(';'):
89612111Sralph 	case TRC(','):
89712111Sralph 	case TRC('g'):
89812111Sralph 	case TRC('j'):
89912111Sralph 	case TRC('p'):
90012111Sralph 	case TRC('q'):
90112111Sralph 	case TRC('y'):
90212111Sralph 		return (DROP);
90312111Sralph 
90412111Sralph 	default:
90512111Sralph 		return (0);
90612111Sralph 	}
90712111Sralph }
90812111Sralph 
90912111Sralph /*
91012111Sralph  * sendmail ---
91112111Sralph  *   tell people about job completion
91212111Sralph  */
91315811Sralph sendmail(user, bombed)
91415811Sralph 	char *user;
91512111Sralph 	int bombed;
91612111Sralph {
91712111Sralph 	register int i;
91815811Sralph 	int p[2], s;
91912111Sralph 	register char *cp;
92012111Sralph 	char buf[100];
92115811Sralph 	struct stat stb;
92215811Sralph 	FILE *fp;
92312111Sralph 
92412111Sralph 	pipe(p);
92515811Sralph 	if ((s = dofork(DORETURN)) == 0) {		/* child */
92612111Sralph 		dup2(p[0], 0);
92712111Sralph 		for (i = 3; i < NOFILE; i++)
92812111Sralph 			(void) close(i);
92937968Sbostic 		if ((cp = rindex(_PATH_SENDMAIL, '/')) != NULL)
93012111Sralph 			cp++;
93112111Sralph 		else
93237968Sbostic 			cp = _PATH_SENDMAIL;
93315811Sralph 		sprintf(buf, "%s@%s", user, fromhost);
93437968Sbostic 		execl(_PATH_SENDMAIL, cp, buf, 0);
93512111Sralph 		exit(0);
93615811Sralph 	} else if (s > 0) {				/* parent */
93712111Sralph 		dup2(p[1], 1);
93815811Sralph 		printf("To: %s@%s\n", user, fromhost);
93912111Sralph 		printf("Subject: printer job\n\n");
94012111Sralph 		printf("Your printer job ");
94112111Sralph 		if (*jobname)
94212111Sralph 			printf("(%s) ", jobname);
94312463Sralph 		switch (bombed) {
94417463Sralph 		case OK:
94512463Sralph 			printf("\ncompleted successfully\n");
94612463Sralph 			break;
94712463Sralph 		default:
94817463Sralph 		case FATALERR:
94912463Sralph 			printf("\ncould not be printed\n");
95012463Sralph 			break;
95117463Sralph 		case NOACCT:
95212463Sralph 			printf("\ncould not be printed without an account on %s\n", host);
95312463Sralph 			break;
95417463Sralph 		case FILTERERR:
95539954Smckusick 			if (stat(tempfile, &stb) < 0 || stb.st_size == 0 ||
95639954Smckusick 			    (fp = fopen(tempfile, "r")) == NULL) {
95715811Sralph 				printf("\nwas printed but had some errors\n");
95815811Sralph 				break;
95915811Sralph 			}
96015811Sralph 			printf("\nwas printed but had the following errors:\n");
96115811Sralph 			while ((i = getc(fp)) != EOF)
96215811Sralph 				putchar(i);
96315811Sralph 			(void) fclose(fp);
96417463Sralph 			break;
96517463Sralph 		case ACCESS:
96617463Sralph 			printf("\nwas not printed because it was not linked to the original file\n");
96712463Sralph 		}
96812111Sralph 		fflush(stdout);
96912111Sralph 		(void) close(1);
97012111Sralph 	}
97112111Sralph 	(void) close(p[0]);
97212111Sralph 	(void) close(p[1]);
97315811Sralph 	wait(&s);
97412111Sralph }
97512111Sralph 
97612111Sralph /*
97712111Sralph  * dofork - fork with retries on failure
97812111Sralph  */
97912111Sralph dofork(action)
98012111Sralph 	int action;
98112111Sralph {
98212111Sralph 	register int i, pid;
98312111Sralph 
98412111Sralph 	for (i = 0; i < 20; i++) {
98512463Sralph 		if ((pid = fork()) < 0) {
98612111Sralph 			sleep((unsigned)(i*i));
98712463Sralph 			continue;
98812463Sralph 		}
98912463Sralph 		/*
99012463Sralph 		 * Child should run as daemon instead of root
99112463Sralph 		 */
99212463Sralph 		if (pid == 0)
99312463Sralph 			setuid(DU);
99412463Sralph 		return(pid);
99512111Sralph 	}
99616762Sralph 	syslog(LOG_ERR, "can't fork");
99712111Sralph 
99812111Sralph 	switch (action) {
99912111Sralph 	case DORETURN:
100012111Sralph 		return (-1);
100112111Sralph 	default:
100216762Sralph 		syslog(LOG_ERR, "bad action (%d) to dofork", action);
100312111Sralph 		/*FALL THRU*/
100412111Sralph 	case DOABORT:
100512111Sralph 		exit(1);
100612111Sralph 	}
100712111Sralph 	/*NOTREACHED*/
100812111Sralph }
100912111Sralph 
101012111Sralph /*
101116762Sralph  * Kill child processes to abort current job.
101212111Sralph  */
101346912Sbostic void
101416762Sralph abortpr()
101512111Sralph {
101639954Smckusick 	(void) unlink(tempfile);
101712111Sralph 	kill(0, SIGINT);
101812111Sralph 	if (ofilter > 0)
101912111Sralph 		kill(ofilter, SIGCONT);
102046912Sbostic 	while (wait(NULL) > 0)
102112111Sralph 		;
102212111Sralph 	exit(0);
102312111Sralph }
102412111Sralph 
102512111Sralph init()
102612111Sralph {
102712111Sralph 	int status;
102838736Stef 	char *s;
102912111Sralph 
103025468Stef 	if ((status = pgetent(line, printer)) < 0) {
103125468Stef 		syslog(LOG_ERR, "can't open printer description file");
103225468Stef 		exit(1);
103325468Stef 	} else if (status == 0) {
103425468Stef 		syslog(LOG_ERR, "unknown printer: %s", printer);
103525468Stef 		exit(1);
103625468Stef 	}
103712111Sralph 	if ((LP = pgetstr("lp", &bp)) == NULL)
103837968Sbostic 		LP = _PATH_DEFDEVLP;
103912111Sralph 	if ((RP = pgetstr("rp", &bp)) == NULL)
104012463Sralph 		RP = DEFLP;
104112111Sralph 	if ((LO = pgetstr("lo", &bp)) == NULL)
104212111Sralph 		LO = DEFLOCK;
104312111Sralph 	if ((ST = pgetstr("st", &bp)) == NULL)
104412111Sralph 		ST = DEFSTAT;
104512111Sralph 	if ((LF = pgetstr("lf", &bp)) == NULL)
104637968Sbostic 		LF = _PATH_CONSOLE;
104712111Sralph 	if ((SD = pgetstr("sd", &bp)) == NULL)
104837968Sbostic 		SD = _PATH_DEFSPOOL;
104912111Sralph 	if ((DU = pgetnum("du")) < 0)
105012111Sralph 		DU = DEFUID;
105112111Sralph 	if ((FF = pgetstr("ff", &bp)) == NULL)
105212111Sralph 		FF = DEFFF;
105312111Sralph 	if ((PW = pgetnum("pw")) < 0)
105412111Sralph 		PW = DEFWIDTH;
105512111Sralph 	sprintf(&width[2], "%d", PW);
105612111Sralph 	if ((PL = pgetnum("pl")) < 0)
105712111Sralph 		PL = DEFLENGTH;
105812111Sralph 	sprintf(&length[2], "%d", PL);
105912463Sralph 	if ((PX = pgetnum("px")) < 0)
106012463Sralph 		PX = 0;
106112463Sralph 	sprintf(&pxwidth[2], "%d", PX);
106212463Sralph 	if ((PY = pgetnum("py")) < 0)
106312463Sralph 		PY = 0;
106412463Sralph 	sprintf(&pxlength[2], "%d", PY);
106512111Sralph 	RM = pgetstr("rm", &bp);
106638736Stef 	if (s = checkremote())
106738736Stef 		syslog(LOG_WARNING, s);
106825468Stef 
106912111Sralph 	AF = pgetstr("af", &bp);
107012111Sralph 	OF = pgetstr("of", &bp);
107112111Sralph 	IF = pgetstr("if", &bp);
107212463Sralph 	RF = pgetstr("rf", &bp);
107312111Sralph 	TF = pgetstr("tf", &bp);
107413233Sralph 	NF = pgetstr("nf", &bp);
107512111Sralph 	DF = pgetstr("df", &bp);
107612111Sralph 	GF = pgetstr("gf", &bp);
107712111Sralph 	VF = pgetstr("vf", &bp);
107812111Sralph 	CF = pgetstr("cf", &bp);
107912111Sralph 	TR = pgetstr("tr", &bp);
108012463Sralph 	RS = pgetflag("rs");
108112111Sralph 	SF = pgetflag("sf");
108212111Sralph 	SH = pgetflag("sh");
108312111Sralph 	SB = pgetflag("sb");
108418127Sralph 	HL = pgetflag("hl");
108512111Sralph 	RW = pgetflag("rw");
108612111Sralph 	BR = pgetnum("br");
108712111Sralph 	if ((FC = pgetnum("fc")) < 0)
108812111Sralph 		FC = 0;
108912111Sralph 	if ((FS = pgetnum("fs")) < 0)
109012111Sralph 		FS = 0;
109112111Sralph 	if ((XC = pgetnum("xc")) < 0)
109212111Sralph 		XC = 0;
109312111Sralph 	if ((XS = pgetnum("xs")) < 0)
109412111Sralph 		XS = 0;
109512581Sralph 	tof = !pgetflag("fo");
109612111Sralph }
109712111Sralph 
109812463Sralph /*
109912463Sralph  * Acquire line printer or remote connection.
110012463Sralph  */
110112463Sralph openpr()
110212463Sralph {
110312463Sralph 	register int i, n;
110416762Sralph 	int resp;
110512463Sralph 
110638736Stef 	if (!sendtorem && *LP) {
110712463Sralph 		for (i = 1; ; i = i < 32 ? i << 1 : i) {
110813148Ssam 			pfd = open(LP, RW ? O_RDWR : O_WRONLY);
110912463Sralph 			if (pfd >= 0)
111012463Sralph 				break;
111112463Sralph 			if (errno == ENOENT) {
111216762Sralph 				syslog(LOG_ERR, "%s: %m", LP);
111312463Sralph 				exit(1);
111412463Sralph 			}
111512463Sralph 			if (i == 1)
111612463Sralph 				status("waiting for %s to become ready (offline ?)", printer);
111712463Sralph 			sleep(i);
111812463Sralph 		}
111912463Sralph 		if (isatty(pfd))
112012463Sralph 			setty();
112112463Sralph 		status("%s is ready and printing", printer);
112212463Sralph 	} else if (RM != NULL) {
112316762Sralph 		for (i = 1; ; i = i < 256 ? i << 1 : i) {
112416762Sralph 			resp = -1;
112512528Sralph 			pfd = getport(RM);
112612463Sralph 			if (pfd >= 0) {
112712463Sralph 				(void) sprintf(line, "\2%s\n", RP);
112812463Sralph 				n = strlen(line);
112916762Sralph 				if (write(pfd, line, n) == n &&
113016762Sralph 				    (resp = response()) == '\0')
113112463Sralph 					break;
113216031Sralph 				(void) close(pfd);
113312463Sralph 			}
113416031Sralph 			if (i == 1) {
113516762Sralph 				if (resp < 0)
113616031Sralph 					status("waiting for %s to come up", RM);
113716762Sralph 				else {
113816031Sralph 					status("waiting for queue to be enabled on %s", RM);
113916762Sralph 					i = 256;
114016762Sralph 				}
114116031Sralph 			}
114212463Sralph 			sleep(i);
114312463Sralph 		}
114412463Sralph 		status("sending to %s", RM);
114512463Sralph 		remote = 1;
114612463Sralph 	} else {
114716762Sralph 		syslog(LOG_ERR, "%s: no line printer device or host name",
114816762Sralph 			printer);
114912463Sralph 		exit(1);
115012463Sralph 	}
115112463Sralph 	/*
115212463Sralph 	 * Start up an output filter, if needed.
115312463Sralph 	 */
115440049Stef 	if (!remote && OF) {
115512463Sralph 		int p[2];
115612463Sralph 		char *cp;
115712463Sralph 
115812463Sralph 		pipe(p);
115912463Sralph 		if ((ofilter = dofork(DOABORT)) == 0) {	/* child */
116012463Sralph 			dup2(p[0], 0);		/* pipe is std in */
116112463Sralph 			dup2(pfd, 1);		/* printer is std out */
116212463Sralph 			for (i = 3; i < NOFILE; i++)
116312463Sralph 				(void) close(i);
116412463Sralph 			if ((cp = rindex(OF, '/')) == NULL)
116512463Sralph 				cp = OF;
116612463Sralph 			else
116712463Sralph 				cp++;
116812463Sralph 			execl(OF, cp, width, length, 0);
116916762Sralph 			syslog(LOG_ERR, "%s: %s: %m", printer, OF);
117012463Sralph 			exit(1);
117112463Sralph 		}
117212463Sralph 		(void) close(p[0]);		/* close input side */
117312463Sralph 		ofd = p[1];			/* use pipe for output */
117412463Sralph 	} else {
117512463Sralph 		ofd = pfd;
117612463Sralph 		ofilter = 0;
117712463Sralph 	}
117812463Sralph }
117912463Sralph 
118012111Sralph struct bauds {
118112111Sralph 	int	baud;
118212111Sralph 	int	speed;
118312111Sralph } bauds[] = {
118412111Sralph 	50,	B50,
118512111Sralph 	75,	B75,
118612111Sralph 	110,	B110,
118712111Sralph 	134,	B134,
118812111Sralph 	150,	B150,
118912111Sralph 	200,	B200,
119012111Sralph 	300,	B300,
119112111Sralph 	600,	B600,
119212111Sralph 	1200,	B1200,
119312111Sralph 	1800,	B1800,
119412111Sralph 	2400,	B2400,
119512111Sralph 	4800,	B4800,
119612111Sralph 	9600,	B9600,
119712111Sralph 	19200,	EXTA,
119812111Sralph 	38400,	EXTB,
119912111Sralph 	0,	0
120012111Sralph };
120112111Sralph 
120212111Sralph /*
120312111Sralph  * setup tty lines.
120412111Sralph  */
120512111Sralph setty()
120612111Sralph {
120712111Sralph 	struct sgttyb ttybuf;
120812111Sralph 	register struct bauds *bp;
120912111Sralph 
121012111Sralph 	if (ioctl(pfd, TIOCEXCL, (char *)0) < 0) {
121116762Sralph 		syslog(LOG_ERR, "%s: ioctl(TIOCEXCL): %m", printer);
121212111Sralph 		exit(1);
121312111Sralph 	}
121412111Sralph 	if (ioctl(pfd, TIOCGETP, (char *)&ttybuf) < 0) {
121516762Sralph 		syslog(LOG_ERR, "%s: ioctl(TIOCGETP): %m", printer);
121612111Sralph 		exit(1);
121712111Sralph 	}
121812111Sralph 	if (BR > 0) {
121912111Sralph 		for (bp = bauds; bp->baud; bp++)
122012111Sralph 			if (BR == bp->baud)
122112111Sralph 				break;
122212111Sralph 		if (!bp->baud) {
122316762Sralph 			syslog(LOG_ERR, "%s: illegal baud rate %d", printer, BR);
122412111Sralph 			exit(1);
122512111Sralph 		}
122612111Sralph 		ttybuf.sg_ispeed = ttybuf.sg_ospeed = bp->speed;
122712111Sralph 	}
122813169Sralph 	ttybuf.sg_flags &= ~FC;
122913169Sralph 	ttybuf.sg_flags |= FS;
123012111Sralph 	if (ioctl(pfd, TIOCSETP, (char *)&ttybuf) < 0) {
123116762Sralph 		syslog(LOG_ERR, "%s: ioctl(TIOCSETP): %m", printer);
123212111Sralph 		exit(1);
123312111Sralph 	}
123412111Sralph 	if (XC) {
123512111Sralph 		if (ioctl(pfd, TIOCLBIC, &XC) < 0) {
123616762Sralph 			syslog(LOG_ERR, "%s: ioctl(TIOCLBIC): %m", printer);
123712111Sralph 			exit(1);
123812111Sralph 		}
123912111Sralph 	}
124012111Sralph 	if (XS) {
124112111Sralph 		if (ioctl(pfd, TIOCLBIS, &XS) < 0) {
124216762Sralph 			syslog(LOG_ERR, "%s: ioctl(TIOCLBIS): %m", printer);
124312111Sralph 			exit(1);
124412111Sralph 		}
124512111Sralph 	}
124612111Sralph }
124712463Sralph 
124812463Sralph /*VARARGS1*/
124912463Sralph status(msg, a1, a2, a3)
125012463Sralph 	char *msg;
125112463Sralph {
125212463Sralph 	register int fd;
125312463Sralph 	char buf[BUFSIZ];
125412463Sralph 
125512463Sralph 	umask(0);
125613148Ssam 	fd = open(ST, O_WRONLY|O_CREAT, 0664);
125716762Sralph 	if (fd < 0 || flock(fd, LOCK_EX) < 0) {
125816762Sralph 		syslog(LOG_ERR, "%s: %s: %m", printer, ST);
125916762Sralph 		exit(1);
126016762Sralph 	}
126113148Ssam 	ftruncate(fd, 0);
126212463Sralph 	sprintf(buf, msg, a1, a2, a3);
126312463Sralph 	strcat(buf, "\n");
126412463Sralph 	(void) write(fd, buf, strlen(buf));
126512463Sralph 	(void) close(fd);
126612463Sralph }
1267