xref: /csrg-svn/usr.sbin/lpr/lpd/printjob.c (revision 42802)
122437Sdist /*
222437Sdist  * Copyright (c) 1983 Regents of the University of California.
334203Sbostic  * All rights reserved.
434203Sbostic  *
5*42802Sbostic  * %sccs.include.redist.c%
622437Sdist  */
722437Sdist 
813954Ssam #ifndef lint
9*42802Sbostic static char sccsid[] = "@(#)printjob.c	5.12 (Berkeley) 06/01/90";
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;
6916762Sralph 	extern int 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);
56212111Sralph 		while ((pid = wait3(&status, WUNTRACED, 0)) > 0 && pid != ofilter)
56312111Sralph 			;
56412111Sralph 		if (status.w_stopval != WSTOPPED) {
56512111Sralph 			(void) close(fi);
56616762Sralph 			syslog(LOG_WARNING, "%s: output filter died (%d)",
56716762Sralph 				printer, status.w_retcode);
56817463Sralph 			return(REPRINT);
56912111Sralph 		}
57012111Sralph 		stopped++;
57112111Sralph 	}
57212111Sralph start:
57312111Sralph 	if ((child = dofork(DORETURN)) == 0) {	/* child */
57412111Sralph 		dup2(fi, 0);
57512111Sralph 		dup2(fo, 1);
57639954Smckusick 		n = open(tempfile, O_WRONLY|O_CREAT|O_TRUNC, 0664);
57715811Sralph 		if (n >= 0)
57815811Sralph 			dup2(n, 2);
57912111Sralph 		for (n = 3; n < NOFILE; n++)
58012111Sralph 			(void) close(n);
58112111Sralph 		execv(prog, av);
58216762Sralph 		syslog(LOG_ERR, "cannot execv %s", prog);
58312111Sralph 		exit(2);
58412111Sralph 	}
58512111Sralph 	(void) close(fi);
58612111Sralph 	if (child < 0)
58712111Sralph 		status.w_retcode = 100;
58812111Sralph 	else
58912111Sralph 		while ((pid = wait(&status)) > 0 && pid != child)
59012111Sralph 			;
59112111Sralph 	child = 0;
59212111Sralph 	prchild = 0;
59312111Sralph 	if (stopped) {		/* restart output filter */
59412111Sralph 		if (kill(ofilter, SIGCONT) < 0) {
59516762Sralph 			syslog(LOG_ERR, "cannot restart output filter");
59612111Sralph 			exit(1);
59712111Sralph 		}
59812111Sralph 	}
59912111Sralph 	tof = 0;
60039954Smckusick 
60139954Smckusick 	/* Copy filter output to "lf" logfile */
60239954Smckusick 	if (fp = fopen(tempfile, "r")) {
60339954Smckusick 		char tbuf[512];
60439954Smckusick 
60539954Smckusick 		while (fgets(buf, sizeof(buf), fp))
60639954Smckusick 			fputs(buf, stderr);
60739954Smckusick 		close(fp);
60839954Smckusick 	}
60939954Smckusick 
61015811Sralph 	if (!WIFEXITED(status)) {
61116762Sralph 		syslog(LOG_WARNING, "%s: Daemon filter '%c' terminated (%d)",
61216762Sralph 			printer, format, status.w_termsig);
61317463Sralph 		return(ERROR);
61417463Sralph 	}
61517463Sralph 	switch (status.w_retcode) {
61617463Sralph 	case 0:
61717463Sralph 		tof = 1;
61817463Sralph 		return(OK);
61917463Sralph 	case 1:
62017463Sralph 		return(REPRINT);
62117463Sralph 	default:
62216762Sralph 		syslog(LOG_WARNING, "%s: Daemon filter '%c' exited (%d)",
62316762Sralph 			printer, format, status.w_retcode);
62417463Sralph 	case 2:
62517463Sralph 		return(ERROR);
62617463Sralph 	}
62712111Sralph }
62812111Sralph 
62912111Sralph /*
63012111Sralph  * Send the daemon control file (cf) and any data files.
63112111Sralph  * Return -1 if a non-recoverable error occured, 1 if a recoverable error and
63212111Sralph  * 0 if all is well.
63312111Sralph  */
63412111Sralph sendit(file)
63512111Sralph 	char *file;
63612111Sralph {
63717463Sralph 	register int i, err = OK;
63817463Sralph 	char *cp, last[BUFSIZ];
63912111Sralph 
64012111Sralph 	/*
64112111Sralph 	 * open control file
64212111Sralph 	 */
64316762Sralph 	if ((cfp = fopen(file, "r")) == NULL)
64417463Sralph 		return(OK);
64512111Sralph 	/*
64612111Sralph 	 *      read the control file for work to do
64712111Sralph 	 *
64812111Sralph 	 *      file format -- first character in the line is a command
64912111Sralph 	 *      rest of the line is the argument.
65012111Sralph 	 *      commands of interest are:
65112111Sralph 	 *
65212111Sralph 	 *            a-z -- "file name" name of file to print
65312111Sralph 	 *              U -- "unlink" name of file to remove
65412111Sralph 	 *                    (after we print it. (Pass 2 only)).
65512111Sralph 	 */
65612111Sralph 
65712111Sralph 	/*
65812111Sralph 	 * pass 1
65912111Sralph 	 */
66012111Sralph 	while (getline(cfp)) {
66112111Sralph 	again:
66217463Sralph 		if (line[0] == 'S') {
66317463Sralph 			cp = line+1;
66417463Sralph 			i = 0;
66517463Sralph 			while (*cp >= '0' && *cp <= '9')
66617463Sralph 				i = i * 10 + (*cp++ - '0');
66717463Sralph 			fdev = i;
66817463Sralph 			cp++;
66917463Sralph 			i = 0;
67017463Sralph 			while (*cp >= '0' && *cp <= '9')
67117463Sralph 				i = i * 10 + (*cp++ - '0');
67217463Sralph 			fino = i;
67317463Sralph 			continue;
67417463Sralph 		}
67512111Sralph 		if (line[0] >= 'a' && line[0] <= 'z') {
67612111Sralph 			strcpy(last, line);
67717463Sralph 			while (i = getline(cfp))
67812111Sralph 				if (strcmp(last, line))
67912111Sralph 					break;
68017463Sralph 			switch (sendfile('\3', last+1)) {
68117463Sralph 			case OK:
68217463Sralph 				if (i)
68317463Sralph 					goto again;
68417463Sralph 				break;
68517463Sralph 			case REPRINT:
68612111Sralph 				(void) fclose(cfp);
68717463Sralph 				return(REPRINT);
68817463Sralph 			case ACCESS:
68917463Sralph 				sendmail(logname, ACCESS);
69017463Sralph 			case ERROR:
69117463Sralph 				err = ERROR;
69217463Sralph 			}
69312111Sralph 			break;
69412111Sralph 		}
69512111Sralph 	}
69617463Sralph 	if (err == OK && sendfile('\2', file) > 0) {
69712111Sralph 		(void) fclose(cfp);
69817463Sralph 		return(REPRINT);
69912111Sralph 	}
70012111Sralph 	/*
70112111Sralph 	 * pass 2
70212111Sralph 	 */
70312111Sralph 	fseek(cfp, 0L, 0);
70412111Sralph 	while (getline(cfp))
70512111Sralph 		if (line[0] == 'U')
70612111Sralph 			(void) unlink(line+1);
70712111Sralph 	/*
70817463Sralph 	 * clean-up in case another control file exists
70912111Sralph 	 */
71012111Sralph 	(void) fclose(cfp);
71112111Sralph 	(void) unlink(file);
71217463Sralph 	return(err);
71312111Sralph }
71412111Sralph 
71512111Sralph /*
71612111Sralph  * Send a data file to the remote machine and spool it.
71712111Sralph  * Return positive if we should try resending.
71812111Sralph  */
71912111Sralph sendfile(type, file)
72012111Sralph 	char type, *file;
72112111Sralph {
72212111Sralph 	register int f, i, amt;
72312111Sralph 	struct stat stb;
72412111Sralph 	char buf[BUFSIZ];
72516762Sralph 	int sizerr, resp;
72612111Sralph 
72717463Sralph 	if (lstat(file, &stb) < 0 || (f = open(file, O_RDONLY)) < 0)
72817463Sralph 		return(ERROR);
72917463Sralph 	/*
73017463Sralph 	 * Check to see if data file is a symbolic link. If so, it should
73117463Sralph 	 * still point to the same file or someone is trying to print something
73217463Sralph 	 * he shouldn't.
73317463Sralph 	 */
73417463Sralph 	if ((stb.st_mode & S_IFMT) == S_IFLNK && fstat(f, &stb) == 0 &&
73517463Sralph 	    (stb.st_dev != fdev || stb.st_ino != fino))
73617463Sralph 		return(ACCESS);
73712111Sralph 	(void) sprintf(buf, "%c%d %s\n", type, stb.st_size, file);
73812111Sralph 	amt = strlen(buf);
73916762Sralph 	for (i = 0;  ; i++) {
74016762Sralph 		if (write(pfd, buf, amt) != amt ||
74116762Sralph 		    (resp = response()) < 0 || resp == '\1') {
74216762Sralph 			(void) close(f);
74317463Sralph 			return(REPRINT);
74416762Sralph 		} else if (resp == '\0')
74516762Sralph 			break;
74616762Sralph 		if (i == 0)
74716762Sralph 			status("no space on remote; waiting for queue to drain");
74816762Sralph 		if (i == 10)
74924861Seric 			syslog(LOG_ALERT, "%s: can't send to %s; queue full",
75016762Sralph 				printer, RM);
75116762Sralph 		sleep(5 * 60);
75212692Sralph 	}
75316762Sralph 	if (i)
75416762Sralph 		status("sending to %s", RM);
75512111Sralph 	sizerr = 0;
75612111Sralph 	for (i = 0; i < stb.st_size; i += BUFSIZ) {
75712111Sralph 		amt = BUFSIZ;
75812111Sralph 		if (i + amt > stb.st_size)
75912111Sralph 			amt = stb.st_size - i;
76012111Sralph 		if (sizerr == 0 && read(f, buf, amt) != amt)
76112111Sralph 			sizerr = 1;
76212692Sralph 		if (write(pfd, buf, amt) != amt) {
76312692Sralph 			(void) close(f);
76417463Sralph 			return(REPRINT);
76512692Sralph 		}
76612111Sralph 	}
76712111Sralph 	(void) close(f);
76812111Sralph 	if (sizerr) {
76916762Sralph 		syslog(LOG_INFO, "%s: %s: changed size", printer, file);
77017463Sralph 		/* tell recvjob to ignore this file */
77117463Sralph 		(void) write(pfd, "\1", 1);
77217463Sralph 		return(ERROR);
77317463Sralph 	}
77417463Sralph 	if (write(pfd, "", 1) != 1 || response())
77517463Sralph 		return(REPRINT);
77617463Sralph 	return(OK);
77712111Sralph }
77812111Sralph 
77912111Sralph /*
78012111Sralph  * Check to make sure there have been no errors and that both programs
78112111Sralph  * are in sync with eachother.
78212111Sralph  * Return non-zero if the connection was lost.
78312111Sralph  */
78416762Sralph response()
78512111Sralph {
78612111Sralph 	char resp;
78712111Sralph 
78816762Sralph 	if (read(pfd, &resp, 1) != 1) {
78916762Sralph 		syslog(LOG_INFO, "%s: lost connection", printer);
79016762Sralph 		return(-1);
79112111Sralph 	}
79216762Sralph 	return(resp);
79312111Sralph }
79412111Sralph 
79512111Sralph /*
79612111Sralph  * Banner printing stuff
79712111Sralph  */
79812111Sralph banner(name1, name2)
79912111Sralph 	char *name1, *name2;
80012111Sralph {
80112111Sralph 	time_t tvec;
80212111Sralph 	extern char *ctime();
80312111Sralph 
80412111Sralph 	time(&tvec);
80512111Sralph 	if (!SF && !tof)
80612111Sralph 		(void) write(ofd, FF, strlen(FF));
80712111Sralph 	if (SB) {	/* short banner only */
80812111Sralph 		if (class[0]) {
80912111Sralph 			(void) write(ofd, class, strlen(class));
81012111Sralph 			(void) write(ofd, ":", 1);
81112111Sralph 		}
81212111Sralph 		(void) write(ofd, name1, strlen(name1));
81312111Sralph 		(void) write(ofd, "  Job: ", 7);
81412111Sralph 		(void) write(ofd, name2, strlen(name2));
81512111Sralph 		(void) write(ofd, "  Date: ", 8);
81612111Sralph 		(void) write(ofd, ctime(&tvec), 24);
81712111Sralph 		(void) write(ofd, "\n", 1);
81812111Sralph 	} else {	/* normal banner */
81912111Sralph 		(void) write(ofd, "\n\n\n", 3);
82012111Sralph 		scan_out(ofd, name1, '\0');
82112111Sralph 		(void) write(ofd, "\n\n", 2);
82212111Sralph 		scan_out(ofd, name2, '\0');
82312111Sralph 		if (class[0]) {
82412111Sralph 			(void) write(ofd,"\n\n\n",3);
82512111Sralph 			scan_out(ofd, class, '\0');
82612111Sralph 		}
82712111Sralph 		(void) write(ofd, "\n\n\n\n\t\t\t\t\tJob:  ", 15);
82812111Sralph 		(void) write(ofd, name2, strlen(name2));
82912111Sralph 		(void) write(ofd, "\n\t\t\t\t\tDate: ", 12);
83012111Sralph 		(void) write(ofd, ctime(&tvec), 24);
83112111Sralph 		(void) write(ofd, "\n", 1);
83212111Sralph 	}
83312111Sralph 	if (!SF)
83412111Sralph 		(void) write(ofd, FF, strlen(FF));
83512111Sralph 	tof = 1;
83612111Sralph }
83712111Sralph 
83816762Sralph char *
83912111Sralph scnline(key, p, c)
84012111Sralph 	register char key, *p;
84112111Sralph 	char c;
84212111Sralph {
84312111Sralph 	register scnwidth;
84412111Sralph 
84512111Sralph 	for (scnwidth = WIDTH; --scnwidth;) {
84612111Sralph 		key <<= 1;
84712111Sralph 		*p++ = key & 0200 ? c : BACKGND;
84812111Sralph 	}
84912111Sralph 	return (p);
85012111Sralph }
85112111Sralph 
85212111Sralph #define TRC(q)	(((q)-' ')&0177)
85312111Sralph 
85412111Sralph scan_out(scfd, scsp, dlm)
85512111Sralph 	int scfd;
85612111Sralph 	char *scsp, dlm;
85712111Sralph {
85812111Sralph 	register char *strp;
85912111Sralph 	register nchrs, j;
86012111Sralph 	char outbuf[LINELEN+1], *sp, c, cc;
86112111Sralph 	int d, scnhgt;
86212111Sralph 	extern char scnkey[][HEIGHT];	/* in lpdchar.c */
86312111Sralph 
86412111Sralph 	for (scnhgt = 0; scnhgt++ < HEIGHT+DROP; ) {
86512111Sralph 		strp = &outbuf[0];
86612111Sralph 		sp = scsp;
86712111Sralph 		for (nchrs = 0; ; ) {
86812111Sralph 			d = dropit(c = TRC(cc = *sp++));
86912111Sralph 			if ((!d && scnhgt > HEIGHT) || (scnhgt <= DROP && d))
87012111Sralph 				for (j = WIDTH; --j;)
87112111Sralph 					*strp++ = BACKGND;
87212111Sralph 			else
87312111Sralph 				strp = scnline(scnkey[c][scnhgt-1-d], strp, cc);
87412111Sralph 			if (*sp == dlm || *sp == '\0' || nchrs++ >= PW/(WIDTH+1)-1)
87512111Sralph 				break;
87612111Sralph 			*strp++ = BACKGND;
87712111Sralph 			*strp++ = BACKGND;
87812111Sralph 		}
87912111Sralph 		while (*--strp == BACKGND && strp >= outbuf)
88012111Sralph 			;
88112111Sralph 		strp++;
88212111Sralph 		*strp++ = '\n';
88312111Sralph 		(void) write(scfd, outbuf, strp-outbuf);
88412111Sralph 	}
88512111Sralph }
88612111Sralph 
88712111Sralph dropit(c)
88812111Sralph 	char c;
88912111Sralph {
89012111Sralph 	switch(c) {
89112111Sralph 
89212111Sralph 	case TRC('_'):
89312111Sralph 	case TRC(';'):
89412111Sralph 	case TRC(','):
89512111Sralph 	case TRC('g'):
89612111Sralph 	case TRC('j'):
89712111Sralph 	case TRC('p'):
89812111Sralph 	case TRC('q'):
89912111Sralph 	case TRC('y'):
90012111Sralph 		return (DROP);
90112111Sralph 
90212111Sralph 	default:
90312111Sralph 		return (0);
90412111Sralph 	}
90512111Sralph }
90612111Sralph 
90712111Sralph /*
90812111Sralph  * sendmail ---
90912111Sralph  *   tell people about job completion
91012111Sralph  */
91115811Sralph sendmail(user, bombed)
91215811Sralph 	char *user;
91312111Sralph 	int bombed;
91412111Sralph {
91512111Sralph 	register int i;
91615811Sralph 	int p[2], s;
91712111Sralph 	register char *cp;
91812111Sralph 	char buf[100];
91915811Sralph 	struct stat stb;
92015811Sralph 	FILE *fp;
92112111Sralph 
92212111Sralph 	pipe(p);
92315811Sralph 	if ((s = dofork(DORETURN)) == 0) {		/* child */
92412111Sralph 		dup2(p[0], 0);
92512111Sralph 		for (i = 3; i < NOFILE; i++)
92612111Sralph 			(void) close(i);
92737968Sbostic 		if ((cp = rindex(_PATH_SENDMAIL, '/')) != NULL)
92812111Sralph 			cp++;
92912111Sralph 		else
93037968Sbostic 			cp = _PATH_SENDMAIL;
93115811Sralph 		sprintf(buf, "%s@%s", user, fromhost);
93237968Sbostic 		execl(_PATH_SENDMAIL, cp, buf, 0);
93312111Sralph 		exit(0);
93415811Sralph 	} else if (s > 0) {				/* parent */
93512111Sralph 		dup2(p[1], 1);
93615811Sralph 		printf("To: %s@%s\n", user, fromhost);
93712111Sralph 		printf("Subject: printer job\n\n");
93812111Sralph 		printf("Your printer job ");
93912111Sralph 		if (*jobname)
94012111Sralph 			printf("(%s) ", jobname);
94112463Sralph 		switch (bombed) {
94217463Sralph 		case OK:
94312463Sralph 			printf("\ncompleted successfully\n");
94412463Sralph 			break;
94512463Sralph 		default:
94617463Sralph 		case FATALERR:
94712463Sralph 			printf("\ncould not be printed\n");
94812463Sralph 			break;
94917463Sralph 		case NOACCT:
95012463Sralph 			printf("\ncould not be printed without an account on %s\n", host);
95112463Sralph 			break;
95217463Sralph 		case FILTERERR:
95339954Smckusick 			if (stat(tempfile, &stb) < 0 || stb.st_size == 0 ||
95439954Smckusick 			    (fp = fopen(tempfile, "r")) == NULL) {
95515811Sralph 				printf("\nwas printed but had some errors\n");
95615811Sralph 				break;
95715811Sralph 			}
95815811Sralph 			printf("\nwas printed but had the following errors:\n");
95915811Sralph 			while ((i = getc(fp)) != EOF)
96015811Sralph 				putchar(i);
96115811Sralph 			(void) fclose(fp);
96217463Sralph 			break;
96317463Sralph 		case ACCESS:
96417463Sralph 			printf("\nwas not printed because it was not linked to the original file\n");
96512463Sralph 		}
96612111Sralph 		fflush(stdout);
96712111Sralph 		(void) close(1);
96812111Sralph 	}
96912111Sralph 	(void) close(p[0]);
97012111Sralph 	(void) close(p[1]);
97115811Sralph 	wait(&s);
97212111Sralph }
97312111Sralph 
97412111Sralph /*
97512111Sralph  * dofork - fork with retries on failure
97612111Sralph  */
97712111Sralph dofork(action)
97812111Sralph 	int action;
97912111Sralph {
98012111Sralph 	register int i, pid;
98112111Sralph 
98212111Sralph 	for (i = 0; i < 20; i++) {
98312463Sralph 		if ((pid = fork()) < 0) {
98412111Sralph 			sleep((unsigned)(i*i));
98512463Sralph 			continue;
98612463Sralph 		}
98712463Sralph 		/*
98812463Sralph 		 * Child should run as daemon instead of root
98912463Sralph 		 */
99012463Sralph 		if (pid == 0)
99112463Sralph 			setuid(DU);
99212463Sralph 		return(pid);
99312111Sralph 	}
99416762Sralph 	syslog(LOG_ERR, "can't fork");
99512111Sralph 
99612111Sralph 	switch (action) {
99712111Sralph 	case DORETURN:
99812111Sralph 		return (-1);
99912111Sralph 	default:
100016762Sralph 		syslog(LOG_ERR, "bad action (%d) to dofork", action);
100112111Sralph 		/*FALL THRU*/
100212111Sralph 	case DOABORT:
100312111Sralph 		exit(1);
100412111Sralph 	}
100512111Sralph 	/*NOTREACHED*/
100612111Sralph }
100712111Sralph 
100812111Sralph /*
100916762Sralph  * Kill child processes to abort current job.
101012111Sralph  */
101116762Sralph abortpr()
101212111Sralph {
101339954Smckusick 	(void) unlink(tempfile);
101412111Sralph 	kill(0, SIGINT);
101512111Sralph 	if (ofilter > 0)
101612111Sralph 		kill(ofilter, SIGCONT);
101712111Sralph 	while (wait(0) > 0)
101812111Sralph 		;
101912111Sralph 	exit(0);
102012111Sralph }
102112111Sralph 
102212111Sralph init()
102312111Sralph {
102412111Sralph 	int status;
102538736Stef 	char *s;
102612111Sralph 
102725468Stef 	if ((status = pgetent(line, printer)) < 0) {
102825468Stef 		syslog(LOG_ERR, "can't open printer description file");
102925468Stef 		exit(1);
103025468Stef 	} else if (status == 0) {
103125468Stef 		syslog(LOG_ERR, "unknown printer: %s", printer);
103225468Stef 		exit(1);
103325468Stef 	}
103412111Sralph 	if ((LP = pgetstr("lp", &bp)) == NULL)
103537968Sbostic 		LP = _PATH_DEFDEVLP;
103612111Sralph 	if ((RP = pgetstr("rp", &bp)) == NULL)
103712463Sralph 		RP = DEFLP;
103812111Sralph 	if ((LO = pgetstr("lo", &bp)) == NULL)
103912111Sralph 		LO = DEFLOCK;
104012111Sralph 	if ((ST = pgetstr("st", &bp)) == NULL)
104112111Sralph 		ST = DEFSTAT;
104212111Sralph 	if ((LF = pgetstr("lf", &bp)) == NULL)
104337968Sbostic 		LF = _PATH_CONSOLE;
104412111Sralph 	if ((SD = pgetstr("sd", &bp)) == NULL)
104537968Sbostic 		SD = _PATH_DEFSPOOL;
104612111Sralph 	if ((DU = pgetnum("du")) < 0)
104712111Sralph 		DU = DEFUID;
104812111Sralph 	if ((FF = pgetstr("ff", &bp)) == NULL)
104912111Sralph 		FF = DEFFF;
105012111Sralph 	if ((PW = pgetnum("pw")) < 0)
105112111Sralph 		PW = DEFWIDTH;
105212111Sralph 	sprintf(&width[2], "%d", PW);
105312111Sralph 	if ((PL = pgetnum("pl")) < 0)
105412111Sralph 		PL = DEFLENGTH;
105512111Sralph 	sprintf(&length[2], "%d", PL);
105612463Sralph 	if ((PX = pgetnum("px")) < 0)
105712463Sralph 		PX = 0;
105812463Sralph 	sprintf(&pxwidth[2], "%d", PX);
105912463Sralph 	if ((PY = pgetnum("py")) < 0)
106012463Sralph 		PY = 0;
106112463Sralph 	sprintf(&pxlength[2], "%d", PY);
106212111Sralph 	RM = pgetstr("rm", &bp);
106338736Stef 	if (s = checkremote())
106438736Stef 		syslog(LOG_WARNING, s);
106525468Stef 
106612111Sralph 	AF = pgetstr("af", &bp);
106712111Sralph 	OF = pgetstr("of", &bp);
106812111Sralph 	IF = pgetstr("if", &bp);
106912463Sralph 	RF = pgetstr("rf", &bp);
107012111Sralph 	TF = pgetstr("tf", &bp);
107113233Sralph 	NF = pgetstr("nf", &bp);
107212111Sralph 	DF = pgetstr("df", &bp);
107312111Sralph 	GF = pgetstr("gf", &bp);
107412111Sralph 	VF = pgetstr("vf", &bp);
107512111Sralph 	CF = pgetstr("cf", &bp);
107612111Sralph 	TR = pgetstr("tr", &bp);
107712463Sralph 	RS = pgetflag("rs");
107812111Sralph 	SF = pgetflag("sf");
107912111Sralph 	SH = pgetflag("sh");
108012111Sralph 	SB = pgetflag("sb");
108118127Sralph 	HL = pgetflag("hl");
108212111Sralph 	RW = pgetflag("rw");
108312111Sralph 	BR = pgetnum("br");
108412111Sralph 	if ((FC = pgetnum("fc")) < 0)
108512111Sralph 		FC = 0;
108612111Sralph 	if ((FS = pgetnum("fs")) < 0)
108712111Sralph 		FS = 0;
108812111Sralph 	if ((XC = pgetnum("xc")) < 0)
108912111Sralph 		XC = 0;
109012111Sralph 	if ((XS = pgetnum("xs")) < 0)
109112111Sralph 		XS = 0;
109212581Sralph 	tof = !pgetflag("fo");
109312111Sralph }
109412111Sralph 
109512463Sralph /*
109612463Sralph  * Acquire line printer or remote connection.
109712463Sralph  */
109812463Sralph openpr()
109912463Sralph {
110012463Sralph 	register int i, n;
110116762Sralph 	int resp;
110212463Sralph 
110338736Stef 	if (!sendtorem && *LP) {
110412463Sralph 		for (i = 1; ; i = i < 32 ? i << 1 : i) {
110513148Ssam 			pfd = open(LP, RW ? O_RDWR : O_WRONLY);
110612463Sralph 			if (pfd >= 0)
110712463Sralph 				break;
110812463Sralph 			if (errno == ENOENT) {
110916762Sralph 				syslog(LOG_ERR, "%s: %m", LP);
111012463Sralph 				exit(1);
111112463Sralph 			}
111212463Sralph 			if (i == 1)
111312463Sralph 				status("waiting for %s to become ready (offline ?)", printer);
111412463Sralph 			sleep(i);
111512463Sralph 		}
111612463Sralph 		if (isatty(pfd))
111712463Sralph 			setty();
111812463Sralph 		status("%s is ready and printing", printer);
111912463Sralph 	} else if (RM != NULL) {
112016762Sralph 		for (i = 1; ; i = i < 256 ? i << 1 : i) {
112116762Sralph 			resp = -1;
112212528Sralph 			pfd = getport(RM);
112312463Sralph 			if (pfd >= 0) {
112412463Sralph 				(void) sprintf(line, "\2%s\n", RP);
112512463Sralph 				n = strlen(line);
112616762Sralph 				if (write(pfd, line, n) == n &&
112716762Sralph 				    (resp = response()) == '\0')
112812463Sralph 					break;
112916031Sralph 				(void) close(pfd);
113012463Sralph 			}
113116031Sralph 			if (i == 1) {
113216762Sralph 				if (resp < 0)
113316031Sralph 					status("waiting for %s to come up", RM);
113416762Sralph 				else {
113516031Sralph 					status("waiting for queue to be enabled on %s", RM);
113616762Sralph 					i = 256;
113716762Sralph 				}
113816031Sralph 			}
113912463Sralph 			sleep(i);
114012463Sralph 		}
114112463Sralph 		status("sending to %s", RM);
114212463Sralph 		remote = 1;
114312463Sralph 	} else {
114416762Sralph 		syslog(LOG_ERR, "%s: no line printer device or host name",
114516762Sralph 			printer);
114612463Sralph 		exit(1);
114712463Sralph 	}
114812463Sralph 	/*
114912463Sralph 	 * Start up an output filter, if needed.
115012463Sralph 	 */
115140049Stef 	if (!remote && OF) {
115212463Sralph 		int p[2];
115312463Sralph 		char *cp;
115412463Sralph 
115512463Sralph 		pipe(p);
115612463Sralph 		if ((ofilter = dofork(DOABORT)) == 0) {	/* child */
115712463Sralph 			dup2(p[0], 0);		/* pipe is std in */
115812463Sralph 			dup2(pfd, 1);		/* printer is std out */
115912463Sralph 			for (i = 3; i < NOFILE; i++)
116012463Sralph 				(void) close(i);
116112463Sralph 			if ((cp = rindex(OF, '/')) == NULL)
116212463Sralph 				cp = OF;
116312463Sralph 			else
116412463Sralph 				cp++;
116512463Sralph 			execl(OF, cp, width, length, 0);
116616762Sralph 			syslog(LOG_ERR, "%s: %s: %m", printer, OF);
116712463Sralph 			exit(1);
116812463Sralph 		}
116912463Sralph 		(void) close(p[0]);		/* close input side */
117012463Sralph 		ofd = p[1];			/* use pipe for output */
117112463Sralph 	} else {
117212463Sralph 		ofd = pfd;
117312463Sralph 		ofilter = 0;
117412463Sralph 	}
117512463Sralph }
117612463Sralph 
117712111Sralph struct bauds {
117812111Sralph 	int	baud;
117912111Sralph 	int	speed;
118012111Sralph } bauds[] = {
118112111Sralph 	50,	B50,
118212111Sralph 	75,	B75,
118312111Sralph 	110,	B110,
118412111Sralph 	134,	B134,
118512111Sralph 	150,	B150,
118612111Sralph 	200,	B200,
118712111Sralph 	300,	B300,
118812111Sralph 	600,	B600,
118912111Sralph 	1200,	B1200,
119012111Sralph 	1800,	B1800,
119112111Sralph 	2400,	B2400,
119212111Sralph 	4800,	B4800,
119312111Sralph 	9600,	B9600,
119412111Sralph 	19200,	EXTA,
119512111Sralph 	38400,	EXTB,
119612111Sralph 	0,	0
119712111Sralph };
119812111Sralph 
119912111Sralph /*
120012111Sralph  * setup tty lines.
120112111Sralph  */
120212111Sralph setty()
120312111Sralph {
120412111Sralph 	struct sgttyb ttybuf;
120512111Sralph 	register struct bauds *bp;
120612111Sralph 
120712111Sralph 	if (ioctl(pfd, TIOCEXCL, (char *)0) < 0) {
120816762Sralph 		syslog(LOG_ERR, "%s: ioctl(TIOCEXCL): %m", printer);
120912111Sralph 		exit(1);
121012111Sralph 	}
121112111Sralph 	if (ioctl(pfd, TIOCGETP, (char *)&ttybuf) < 0) {
121216762Sralph 		syslog(LOG_ERR, "%s: ioctl(TIOCGETP): %m", printer);
121312111Sralph 		exit(1);
121412111Sralph 	}
121512111Sralph 	if (BR > 0) {
121612111Sralph 		for (bp = bauds; bp->baud; bp++)
121712111Sralph 			if (BR == bp->baud)
121812111Sralph 				break;
121912111Sralph 		if (!bp->baud) {
122016762Sralph 			syslog(LOG_ERR, "%s: illegal baud rate %d", printer, BR);
122112111Sralph 			exit(1);
122212111Sralph 		}
122312111Sralph 		ttybuf.sg_ispeed = ttybuf.sg_ospeed = bp->speed;
122412111Sralph 	}
122513169Sralph 	ttybuf.sg_flags &= ~FC;
122613169Sralph 	ttybuf.sg_flags |= FS;
122712111Sralph 	if (ioctl(pfd, TIOCSETP, (char *)&ttybuf) < 0) {
122816762Sralph 		syslog(LOG_ERR, "%s: ioctl(TIOCSETP): %m", printer);
122912111Sralph 		exit(1);
123012111Sralph 	}
123112111Sralph 	if (XC) {
123212111Sralph 		if (ioctl(pfd, TIOCLBIC, &XC) < 0) {
123316762Sralph 			syslog(LOG_ERR, "%s: ioctl(TIOCLBIC): %m", printer);
123412111Sralph 			exit(1);
123512111Sralph 		}
123612111Sralph 	}
123712111Sralph 	if (XS) {
123812111Sralph 		if (ioctl(pfd, TIOCLBIS, &XS) < 0) {
123916762Sralph 			syslog(LOG_ERR, "%s: ioctl(TIOCLBIS): %m", printer);
124012111Sralph 			exit(1);
124112111Sralph 		}
124212111Sralph 	}
124312111Sralph }
124412463Sralph 
124512463Sralph /*VARARGS1*/
124612463Sralph status(msg, a1, a2, a3)
124712463Sralph 	char *msg;
124812463Sralph {
124912463Sralph 	register int fd;
125012463Sralph 	char buf[BUFSIZ];
125112463Sralph 
125212463Sralph 	umask(0);
125313148Ssam 	fd = open(ST, O_WRONLY|O_CREAT, 0664);
125416762Sralph 	if (fd < 0 || flock(fd, LOCK_EX) < 0) {
125516762Sralph 		syslog(LOG_ERR, "%s: %s: %m", printer, ST);
125616762Sralph 		exit(1);
125716762Sralph 	}
125813148Ssam 	ftruncate(fd, 0);
125912463Sralph 	sprintf(buf, msg, a1, a2, a3);
126012463Sralph 	strcat(buf, "\n");
126112463Sralph 	(void) write(fd, buf, strlen(buf));
126212463Sralph 	(void) close(fd);
126312463Sralph }
1264