xref: /csrg-svn/usr.sbin/lpr/lpd/printjob.c (revision 55474)
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*55474Sbostic static char sccsid[] = "@(#)printjob.c	5.15 (Berkeley) 07/21/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 
19*55474Sbostic #include <sys/param.h>
20*55474Sbostic #include <sys/wait.h>
21*55474Sbostic #include <sys/stat.h>
22*55474Sbostic 
23*55474Sbostic #include <signal.h>
24*55474Sbostic #include <sgtty.h>
25*55474Sbostic #include <syslog.h>
26*55474Sbostic #include <fcntl.h>
27*55474Sbostic #include <dirent.h>
28*55474Sbostic #include <errno.h>
29*55474Sbostic #include <stdio.h>
30*55474Sbostic #include <string.h>
3112111Sralph #include "lp.h"
32*55474Sbostic #include "lp.local.h"
3337968Sbostic #include "pathnames.h"
34*55474Sbostic #include "extern.h"
3512111Sralph 
3616762Sralph #define DORETURN	0	/* absorb fork error */
3716762Sralph #define DOABORT		1	/* abort if dofork fails */
3812111Sralph 
3917463Sralph /*
4017463Sralph  * Error tokens
4117463Sralph  */
4217463Sralph #define REPRINT		-2
4317463Sralph #define ERROR		-1
4417463Sralph #define	OK		0
4517463Sralph #define	FATALERR	1
4617463Sralph #define	NOACCT		2
4717463Sralph #define	FILTERERR	3
4817463Sralph #define	ACCESS		4
4917463Sralph 
5016762Sralph char	title[80];		/* ``pr'' title */
5116762Sralph FILE	*cfp;			/* control file */
5216762Sralph int	pfd;			/* printer file descriptor */
5316762Sralph int	ofd;			/* output filter file descriptor */
5416762Sralph int	lfd;			/* lock file descriptor */
5516762Sralph int	pid;			/* pid of lpd process */
5616762Sralph int	prchild;		/* id of pr process */
5716762Sralph int	child;			/* id of any filters */
5816762Sralph int	ofilter;		/* id of output filter, if any */
5916762Sralph int	tof;			/* true if at top of form */
6016762Sralph int	remote;			/* true if sending files to remote */
6117463Sralph dev_t	fdev;			/* device of file pointed to by symlink */
6217463Sralph ino_t	fino;			/* inode of file pointed to by symlink */
6312111Sralph 
6416762Sralph char	fromhost[32];		/* user's host machine */
6516762Sralph char	logname[32];		/* user's login name */
6616762Sralph char	jobname[100];		/* job or file name */
6716762Sralph char	class[32];		/* classification field */
6816762Sralph char	width[10] = "-w";	/* page width in characters */
6916762Sralph char	length[10] = "-l";	/* page length in lines */
7016762Sralph char	pxwidth[10] = "-x";	/* page width in pixels */
7116762Sralph char	pxlength[10] = "-y";	/* page length in pixels */
7216762Sralph char	indent[10] = "-i0";	/* indentation size in characters */
7339954Smckusick char	tempfile[] = "errsXXXXXX"; /* file name for filter output */
7412111Sralph 
75*55474Sbostic static void       abortpr __P((int));
76*55474Sbostic static void       banner __P((char *, char *));
77*55474Sbostic static int        dofork __P((int));
78*55474Sbostic static int        dropit __P((int));
79*55474Sbostic static void       init __P((void));
80*55474Sbostic static void       openpr __P((void));
81*55474Sbostic static int        print __P((int, char *));
82*55474Sbostic static int        printit __P((char *));
83*55474Sbostic static void       pstatus __P((const char *, ...));
84*55474Sbostic static char       response __P((void));
85*55474Sbostic static void       scan_out __P((int, char *, int));
86*55474Sbostic static char      *scnline __P((int, char *, int));
87*55474Sbostic static int        sendfile __P((int, char *));
88*55474Sbostic static int        sendit __P((char *));
89*55474Sbostic static void       sendmail __P((char *, int));
90*55474Sbostic static void       setty __P((void));
91*55474Sbostic 
92*55474Sbostic void
9312111Sralph printjob()
9412111Sralph {
9512111Sralph 	struct stat stb;
9612111Sralph 	register struct queue *q, **qp;
9712111Sralph 	struct queue **queue;
9812111Sralph 	register int i, nitems;
9912111Sralph 	long pidoff;
10016762Sralph 	int count = 0;
10112111Sralph 
10212111Sralph 	init();					/* set up capabilities */
10313442Sralph 	(void) write(1, "", 1);			/* ack that daemon is started */
10425496Seric 	(void) close(2);			/* set up log file */
10525496Seric 	if (open(LF, O_WRONLY|O_APPEND, 0664) < 0) {
10625496Seric 		syslog(LOG_ERR, "%s: %m", LF);
10737968Sbostic 		(void) open(_PATH_DEVNULL, O_WRONLY);
10825496Seric 	}
10916762Sralph 	setgid(getegid());
11012463Sralph 	pid = getpid();				/* for use with lprm */
11112111Sralph 	setpgrp(0, pid);
11216762Sralph 	signal(SIGHUP, abortpr);
11316762Sralph 	signal(SIGINT, abortpr);
11416762Sralph 	signal(SIGQUIT, abortpr);
11516762Sralph 	signal(SIGTERM, abortpr);
11612111Sralph 
11739954Smckusick 	(void) mktemp(tempfile);
11815811Sralph 
11912111Sralph 	/*
12012111Sralph 	 * uses short form file names
12112111Sralph 	 */
12212111Sralph 	if (chdir(SD) < 0) {
12316762Sralph 		syslog(LOG_ERR, "%s: %m", SD);
12412111Sralph 		exit(1);
12512111Sralph 	}
12612463Sralph 	if (stat(LO, &stb) == 0 && (stb.st_mode & 0100))
12712463Sralph 		exit(0);		/* printing disabled */
12814150Sralph 	lfd = open(LO, O_WRONLY|O_CREAT, 0644);
12913169Sralph 	if (lfd < 0) {
13016762Sralph 		syslog(LOG_ERR, "%s: %s: %m", printer, LO);
13113169Sralph 		exit(1);
13213169Sralph 	}
13313169Sralph 	if (flock(lfd, LOCK_EX|LOCK_NB) < 0) {
13412111Sralph 		if (errno == EWOULDBLOCK)	/* active deamon present */
13512111Sralph 			exit(0);
13616762Sralph 		syslog(LOG_ERR, "%s: %s: %m", printer, LO);
13712111Sralph 		exit(1);
13812111Sralph 	}
13913148Ssam 	ftruncate(lfd, 0);
14012111Sralph 	/*
14112111Sralph 	 * write process id for others to know
14212111Sralph 	 */
14312111Sralph 	sprintf(line, "%u\n", pid);
14412111Sralph 	pidoff = i = strlen(line);
14512463Sralph 	if (write(lfd, line, i) != i) {
14616762Sralph 		syslog(LOG_ERR, "%s: %s: %m", printer, LO);
14712111Sralph 		exit(1);
14812111Sralph 	}
14912111Sralph 	/*
15012111Sralph 	 * search the spool directory for work and sort by queue order.
15112111Sralph 	 */
15212111Sralph 	if ((nitems = getq(&queue)) < 0) {
15316762Sralph 		syslog(LOG_ERR, "%s: can't scan %s", printer, SD);
15412111Sralph 		exit(1);
15512111Sralph 	}
15612463Sralph 	if (nitems == 0)		/* no work to do */
15712111Sralph 		exit(0);
15813169Sralph 	if (stb.st_mode & 01) {		/* reset queue flag */
15913169Sralph 		if (fchmod(lfd, stb.st_mode & 0776) < 0)
16016762Sralph 			syslog(LOG_ERR, "%s: %s: %m", printer, LO);
16113169Sralph 	}
16212463Sralph 	openpr();			/* open printer or remote */
16312463Sralph again:
16412111Sralph 	/*
16512111Sralph 	 * we found something to do now do it --
16612111Sralph 	 *    write the name of the current control file into the lock file
16712111Sralph 	 *    so the spool queue program can tell what we're working on
16812111Sralph 	 */
16912111Sralph 	for (qp = queue; nitems--; free((char *) q)) {
17012111Sralph 		q = *qp++;
17112111Sralph 		if (stat(q->q_name, &stb) < 0)
17212111Sralph 			continue;
17312463Sralph 	restart:
174*55474Sbostic 		(void) lseek(lfd, (off_t)pidoff, 0);
17512111Sralph 		(void) sprintf(line, "%s\n", q->q_name);
17612111Sralph 		i = strlen(line);
17712111Sralph 		if (write(lfd, line, i) != i)
17816762Sralph 			syslog(LOG_ERR, "%s: %s: %m", printer, LO);
17912111Sralph 		if (!remote)
18012111Sralph 			i = printit(q->q_name);
18112111Sralph 		else
18212111Sralph 			i = sendit(q->q_name);
18312463Sralph 		/*
18413169Sralph 		 * Check to see if we are supposed to stop printing or
18513169Sralph 		 * if we are to rebuild the queue.
18612463Sralph 		 */
18713169Sralph 		if (fstat(lfd, &stb) == 0) {
18816762Sralph 			/* stop printing before starting next job? */
18913169Sralph 			if (stb.st_mode & 0100)
19013169Sralph 				goto done;
19116762Sralph 			/* rebuild queue (after lpc topq) */
19213169Sralph 			if (stb.st_mode & 01) {
19313169Sralph 				for (free((char *) q); nitems--; free((char *) q))
19413169Sralph 					q = *qp++;
19513169Sralph 				if (fchmod(lfd, stb.st_mode & 0776) < 0)
19616762Sralph 					syslog(LOG_WARNING, "%s: %s: %m",
19716762Sralph 						printer, LO);
19813169Sralph 				break;
19913169Sralph 			}
20013169Sralph 		}
20117463Sralph 		if (i == OK)		/* file ok and printed */
20214150Sralph 			count++;
20317463Sralph 		else if (i == REPRINT) { /* try reprinting the job */
20416762Sralph 			syslog(LOG_INFO, "restarting %s", printer);
20512111Sralph 			if (ofilter > 0) {
20612111Sralph 				kill(ofilter, SIGCONT);	/* to be sure */
20712111Sralph 				(void) close(ofd);
20812111Sralph 				while ((i = wait(0)) > 0 && i != ofilter)
20912111Sralph 					;
21012111Sralph 				ofilter = 0;
21112111Sralph 			}
21212463Sralph 			(void) close(pfd);	/* close printer */
21315811Sralph 			if (ftruncate(lfd, pidoff) < 0)
21416762Sralph 				syslog(LOG_WARNING, "%s: %s: %m", printer, LO);
21512463Sralph 			openpr();		/* try to reopen printer */
21612111Sralph 			goto restart;
21712111Sralph 		}
21812111Sralph 	}
21912111Sralph 	free((char *) queue);
22012463Sralph 	/*
22112463Sralph 	 * search the spool directory for more work.
22212463Sralph 	 */
22312463Sralph 	if ((nitems = getq(&queue)) < 0) {
22416762Sralph 		syslog(LOG_ERR, "%s: can't scan %s", printer, SD);
22512463Sralph 		exit(1);
22612463Sralph 	}
22712463Sralph 	if (nitems == 0) {		/* no more work to do */
22812463Sralph 	done:
22914150Sralph 		if (count > 0) {	/* Files actually printed */
23014150Sralph 			if (!SF && !tof)
23114150Sralph 				(void) write(ofd, FF, strlen(FF));
23214150Sralph 			if (TR != NULL)		/* output trailer */
23314150Sralph 				(void) write(ofd, TR, strlen(TR));
23414150Sralph 		}
23539954Smckusick 		(void) unlink(tempfile);
23612463Sralph 		exit(0);
23712463Sralph 	}
23812111Sralph 	goto again;
23912111Sralph }
24012111Sralph 
24112111Sralph char	fonts[4][50];	/* fonts for troff */
24212111Sralph 
24337968Sbostic char ifonts[4][40] = {
24437968Sbostic 	_PATH_VFONTR,
24537968Sbostic 	_PATH_VFONTI,
24637968Sbostic 	_PATH_VFONTB,
24737968Sbostic 	_PATH_VFONTS,
24812111Sralph };
24912111Sralph 
25012111Sralph /*
25112111Sralph  * The remaining part is the reading of the control file (cf)
25212111Sralph  * and performing the various actions.
25312111Sralph  */
254*55474Sbostic static int
25512111Sralph printit(file)
25612111Sralph 	char *file;
25712111Sralph {
25812111Sralph 	register int i;
25917463Sralph 	char *cp;
26017463Sralph 	int bombed = OK;
26112111Sralph 
26212111Sralph 	/*
26317463Sralph 	 * open control file; ignore if no longer there.
26412111Sralph 	 */
26512111Sralph 	if ((cfp = fopen(file, "r")) == NULL) {
26616762Sralph 		syslog(LOG_INFO, "%s: %s: %m", printer, file);
26717463Sralph 		return(OK);
26812111Sralph 	}
26912111Sralph 	/*
27012111Sralph 	 * Reset troff fonts.
27112111Sralph 	 */
27212111Sralph 	for (i = 0; i < 4; i++)
27312111Sralph 		strcpy(fonts[i], ifonts[i]);
27417339Sralph 	strcpy(width+2, "0");
27517302Sralph 	strcpy(indent+2, "0");
27612111Sralph 
27712111Sralph 	/*
27812111Sralph 	 *      read the control file for work to do
27912111Sralph 	 *
28012111Sralph 	 *      file format -- first character in the line is a command
28112111Sralph 	 *      rest of the line is the argument.
28212111Sralph 	 *      valid commands are:
28312111Sralph 	 *
28417463Sralph 	 *		S -- "stat info" for symbolic link protection
28512111Sralph 	 *		J -- "job name" on banner page
28612111Sralph 	 *		C -- "class name" on banner page
28712111Sralph 	 *              L -- "literal" user's name to print on banner
28812111Sralph 	 *		T -- "title" for pr
28912111Sralph 	 *		H -- "host name" of machine where lpr was done
29012111Sralph 	 *              P -- "person" user's login name
29112581Sralph 	 *              I -- "indent" amount to indent output
29212111Sralph 	 *              f -- "file name" name of text file to print
29312111Sralph 	 *		l -- "file name" text file with control chars
29412111Sralph 	 *		p -- "file name" text file to print with pr(1)
29512111Sralph 	 *		t -- "file name" troff(1) file to print
29613233Sralph 	 *		n -- "file name" ditroff(1) file to print
29712111Sralph 	 *		d -- "file name" dvi file to print
29812111Sralph 	 *		g -- "file name" plot(1G) file to print
29912111Sralph 	 *		v -- "file name" plain raster file to print
30012111Sralph 	 *		c -- "file name" cifplot file to print
30112111Sralph 	 *		1 -- "R font file" for troff
30212111Sralph 	 *		2 -- "I font file" for troff
30312111Sralph 	 *		3 -- "B font file" for troff
30412111Sralph 	 *		4 -- "S font file" for troff
30512111Sralph 	 *		N -- "name" of file (used by lpq)
30612111Sralph 	 *              U -- "unlink" name of file to remove
30712111Sralph 	 *                    (after we print it. (Pass 2 only)).
30812111Sralph 	 *		M -- "mail" to user when done printing
30912111Sralph 	 *
31012111Sralph 	 *      getline reads a line and expands tabs to blanks
31112111Sralph 	 */
31212111Sralph 
31312111Sralph 	/* pass 1 */
31412111Sralph 
31512111Sralph 	while (getline(cfp))
31612111Sralph 		switch (line[0]) {
31712111Sralph 		case 'H':
31814150Sralph 			strcpy(fromhost, line+1);
31912111Sralph 			if (class[0] == '\0')
32015552Sralph 				strncpy(class, line+1, sizeof(class)-1);
32112111Sralph 			continue;
32212111Sralph 
32312111Sralph 		case 'P':
32415552Sralph 			strncpy(logname, line+1, sizeof(logname)-1);
32512463Sralph 			if (RS) {			/* restricted */
326*55474Sbostic 				if (getpwnam(logname) == NULL) {
32717463Sralph 					bombed = NOACCT;
32815811Sralph 					sendmail(line+1, bombed);
32912463Sralph 					goto pass2;
33012463Sralph 				}
33112463Sralph 			}
33212111Sralph 			continue;
33312111Sralph 
33417463Sralph 		case 'S':
33517463Sralph 			cp = line+1;
33617463Sralph 			i = 0;
33717463Sralph 			while (*cp >= '0' && *cp <= '9')
33817463Sralph 				i = i * 10 + (*cp++ - '0');
33917463Sralph 			fdev = i;
34017463Sralph 			cp++;
34117463Sralph 			i = 0;
34217463Sralph 			while (*cp >= '0' && *cp <= '9')
34317463Sralph 				i = i * 10 + (*cp++ - '0');
34417463Sralph 			fino = i;
34517463Sralph 			continue;
34617463Sralph 
34712111Sralph 		case 'J':
34812111Sralph 			if (line[1] != '\0')
34915552Sralph 				strncpy(jobname, line+1, sizeof(jobname)-1);
35012111Sralph 			else
35112111Sralph 				strcpy(jobname, " ");
35212111Sralph 			continue;
35312111Sralph 
35412111Sralph 		case 'C':
35512111Sralph 			if (line[1] != '\0')
35615552Sralph 				strncpy(class, line+1, sizeof(class)-1);
35712111Sralph 			else if (class[0] == '\0')
35815811Sralph 				gethostname(class, sizeof(class));
35912111Sralph 			continue;
36012111Sralph 
36112111Sralph 		case 'T':	/* header title for pr */
36215552Sralph 			strncpy(title, line+1, sizeof(title)-1);
36312111Sralph 			continue;
36412111Sralph 
36512111Sralph 		case 'L':	/* identification line */
36618127Sralph 			if (!SH && !HL)
36712111Sralph 				banner(line+1, jobname);
36812111Sralph 			continue;
36912111Sralph 
37012111Sralph 		case '1':	/* troff fonts */
37112111Sralph 		case '2':
37212111Sralph 		case '3':
37312111Sralph 		case '4':
37412111Sralph 			if (line[1] != '\0')
37512111Sralph 				strcpy(fonts[line[0]-'1'], line+1);
37612111Sralph 			continue;
37712111Sralph 
37812111Sralph 		case 'W':	/* page width */
37915552Sralph 			strncpy(width+2, line+1, sizeof(width)-3);
38012111Sralph 			continue;
38112111Sralph 
38212581Sralph 		case 'I':	/* indent amount */
38315552Sralph 			strncpy(indent+2, line+1, sizeof(indent)-3);
38412581Sralph 			continue;
38512581Sralph 
38612111Sralph 		default:	/* some file to print */
38715811Sralph 			switch (i = print(line[0], line+1)) {
38817463Sralph 			case ERROR:
38917463Sralph 				if (bombed == OK)
39017463Sralph 					bombed = FATALERR;
39115811Sralph 				break;
39217463Sralph 			case REPRINT:
39312111Sralph 				(void) fclose(cfp);
39417463Sralph 				return(REPRINT);
39517463Sralph 			case FILTERERR:
39617463Sralph 			case ACCESS:
39717463Sralph 				bombed = i;
39815811Sralph 				sendmail(logname, bombed);
39915811Sralph 			}
40012111Sralph 			title[0] = '\0';
40112111Sralph 			continue;
40212111Sralph 
40312111Sralph 		case 'N':
40412111Sralph 		case 'U':
40512111Sralph 		case 'M':
40612111Sralph 			continue;
40712111Sralph 		}
40812111Sralph 
40912111Sralph 	/* pass 2 */
41012111Sralph 
41112463Sralph pass2:
41212111Sralph 	fseek(cfp, 0L, 0);
41312111Sralph 	while (getline(cfp))
41412111Sralph 		switch (line[0]) {
41518127Sralph 		case 'L':	/* identification line */
41618127Sralph 			if (!SH && HL)
41718127Sralph 				banner(line+1, jobname);
41818127Sralph 			continue;
41918127Sralph 
42012111Sralph 		case 'M':
42117463Sralph 			if (bombed < NOACCT)	/* already sent if >= NOACCT */
42215811Sralph 				sendmail(line+1, bombed);
42312111Sralph 			continue;
42412111Sralph 
42512111Sralph 		case 'U':
42612111Sralph 			(void) unlink(line+1);
42712111Sralph 		}
42812111Sralph 	/*
42915811Sralph 	 * clean-up in case another control file exists
43012111Sralph 	 */
43112111Sralph 	(void) fclose(cfp);
43212111Sralph 	(void) unlink(file);
43317463Sralph 	return(bombed == OK ? OK : ERROR);
43412111Sralph }
43512111Sralph 
43612111Sralph /*
43712111Sralph  * Print a file.
43813233Sralph  * Set up the chain [ PR [ | {IF, OF} ] ] or {IF, RF, TF, NF, DF, CF, VF}.
43915811Sralph  * Return -1 if a non-recoverable error occured,
44015811Sralph  * 2 if the filter detected some errors (but printed the job anyway),
44115811Sralph  * 1 if we should try to reprint this job and
44212111Sralph  * 0 if all is well.
44312111Sralph  * Note: all filters take stdin as the file, stdout as the printer,
44412111Sralph  * stderr as the log file, and must not ignore SIGINT.
44512111Sralph  */
446*55474Sbostic static int
44712111Sralph print(format, file)
44812111Sralph 	int format;
44912111Sralph 	char *file;
45012111Sralph {
45115811Sralph 	register int n;
45212111Sralph 	register char *prog;
45315811Sralph 	int fi, fo;
45439954Smckusick 	FILE *fp;
45512111Sralph 	char *av[15], buf[BUFSIZ];
45612111Sralph 	int pid, p[2], stopped = 0;
45712111Sralph 	union wait status;
45817463Sralph 	struct stat stb;
45912111Sralph 
46017463Sralph 	if (lstat(file, &stb) < 0 || (fi = open(file, O_RDONLY)) < 0)
46117463Sralph 		return(ERROR);
46217463Sralph 	/*
46317463Sralph 	 * Check to see if data file is a symbolic link. If so, it should
46417463Sralph 	 * still point to the same file or someone is trying to print
46517463Sralph 	 * something he shouldn't.
46617463Sralph 	 */
46717463Sralph 	if ((stb.st_mode & S_IFMT) == S_IFLNK && fstat(fi, &stb) == 0 &&
46817463Sralph 	    (stb.st_dev != fdev || stb.st_ino != fino))
46917463Sralph 		return(ACCESS);
47012111Sralph 	if (!SF && !tof) {		/* start on a fresh page */
47112111Sralph 		(void) write(ofd, FF, strlen(FF));
47212111Sralph 		tof = 1;
47312111Sralph 	}
47412111Sralph 	if (IF == NULL && (format == 'f' || format == 'l')) {
47512111Sralph 		tof = 0;
47612111Sralph 		while ((n = read(fi, buf, BUFSIZ)) > 0)
47712111Sralph 			if (write(ofd, buf, n) != n) {
47812111Sralph 				(void) close(fi);
47917463Sralph 				return(REPRINT);
48012111Sralph 			}
48112111Sralph 		(void) close(fi);
48217463Sralph 		return(OK);
48312111Sralph 	}
48412111Sralph 	switch (format) {
48512111Sralph 	case 'p':	/* print file using 'pr' */
48612111Sralph 		if (IF == NULL) {	/* use output filter */
48737968Sbostic 			prog = _PATH_PR;
48812111Sralph 			av[0] = "pr";
48912111Sralph 			av[1] = width;
49012111Sralph 			av[2] = length;
49112111Sralph 			av[3] = "-h";
49212111Sralph 			av[4] = *title ? title : " ";
49312111Sralph 			av[5] = 0;
49412111Sralph 			fo = ofd;
49512111Sralph 			goto start;
49612111Sralph 		}
49712111Sralph 		pipe(p);
49812111Sralph 		if ((prchild = dofork(DORETURN)) == 0) {	/* child */
49912111Sralph 			dup2(fi, 0);		/* file is stdin */
50012111Sralph 			dup2(p[1], 1);		/* pipe is stdout */
50112111Sralph 			for (n = 3; n < NOFILE; n++)
50212111Sralph 				(void) close(n);
50337968Sbostic 			execl(_PATH_PR, "pr", width, length,
50437968Sbostic 			    "-h", *title ? title : " ", 0);
50537968Sbostic 			syslog(LOG_ERR, "cannot execl %s", _PATH_PR);
50612111Sralph 			exit(2);
50712111Sralph 		}
50812111Sralph 		(void) close(p[1]);		/* close output side */
50912111Sralph 		(void) close(fi);
51012111Sralph 		if (prchild < 0) {
51112111Sralph 			prchild = 0;
51212111Sralph 			(void) close(p[0]);
51317463Sralph 			return(ERROR);
51412111Sralph 		}
51512111Sralph 		fi = p[0];			/* use pipe for input */
51612111Sralph 	case 'f':	/* print plain text file */
51712111Sralph 		prog = IF;
51812111Sralph 		av[1] = width;
51912111Sralph 		av[2] = length;
52012581Sralph 		av[3] = indent;
52112581Sralph 		n = 4;
52212111Sralph 		break;
52312111Sralph 	case 'l':	/* like 'f' but pass control characters */
52412111Sralph 		prog = IF;
52514325Sralph 		av[1] = "-c";
52612111Sralph 		av[2] = width;
52712111Sralph 		av[3] = length;
52812581Sralph 		av[4] = indent;
52912581Sralph 		n = 5;
53012111Sralph 		break;
53112463Sralph 	case 'r':	/* print a fortran text file */
53212463Sralph 		prog = RF;
53312463Sralph 		av[1] = width;
53412463Sralph 		av[2] = length;
53512463Sralph 		n = 3;
53612463Sralph 		break;
53712111Sralph 	case 't':	/* print troff output */
53813233Sralph 	case 'n':	/* print ditroff output */
53912463Sralph 	case 'd':	/* print tex output */
54012111Sralph 		(void) unlink(".railmag");
54112463Sralph 		if ((fo = creat(".railmag", FILMOD)) < 0) {
54216762Sralph 			syslog(LOG_ERR, "%s: cannot create .railmag", printer);
54312111Sralph 			(void) unlink(".railmag");
54412111Sralph 		} else {
54512111Sralph 			for (n = 0; n < 4; n++) {
54612111Sralph 				if (fonts[n][0] != '/')
54754520Sbostic 					(void) write(fo, _PATH_VFONT,
54854520Sbostic 					    sizeof(_PATH_VFONT) - 1);
54912111Sralph 				(void) write(fo, fonts[n], strlen(fonts[n]));
55012111Sralph 				(void) write(fo, "\n", 1);
55112111Sralph 			}
55212111Sralph 			(void) close(fo);
55312111Sralph 		}
55413233Sralph 		prog = (format == 't') ? TF : (format == 'n') ? NF : DF;
55512463Sralph 		av[1] = pxwidth;
55612463Sralph 		av[2] = pxlength;
55712463Sralph 		n = 3;
55812111Sralph 		break;
55912111Sralph 	case 'c':	/* print cifplot output */
56012111Sralph 		prog = CF;
56112463Sralph 		av[1] = pxwidth;
56212463Sralph 		av[2] = pxlength;
56312463Sralph 		n = 3;
56412111Sralph 		break;
56512111Sralph 	case 'g':	/* print plot(1G) output */
56612111Sralph 		prog = GF;
56712463Sralph 		av[1] = pxwidth;
56812463Sralph 		av[2] = pxlength;
56912463Sralph 		n = 3;
57012111Sralph 		break;
57112111Sralph 	case 'v':	/* print raster output */
57212111Sralph 		prog = VF;
57312463Sralph 		av[1] = pxwidth;
57412463Sralph 		av[2] = pxlength;
57512463Sralph 		n = 3;
57612111Sralph 		break;
57712111Sralph 	default:
57812111Sralph 		(void) close(fi);
57916762Sralph 		syslog(LOG_ERR, "%s: illegal format character '%c'",
58016762Sralph 			printer, format);
58117463Sralph 		return(ERROR);
58212111Sralph 	}
58312111Sralph 	if ((av[0] = rindex(prog, '/')) != NULL)
58412111Sralph 		av[0]++;
58512111Sralph 	else
58612111Sralph 		av[0] = prog;
58712111Sralph 	av[n++] = "-n";
58812111Sralph 	av[n++] = logname;
58912111Sralph 	av[n++] = "-h";
59014150Sralph 	av[n++] = fromhost;
59112111Sralph 	av[n++] = AF;
59212111Sralph 	av[n] = 0;
59312111Sralph 	fo = pfd;
59412111Sralph 	if (ofilter > 0) {		/* stop output filter */
59512111Sralph 		write(ofd, "\031\1", 2);
59646912Sbostic 		while ((pid =
59746912Sbostic 		    wait3((int *)&status, WUNTRACED, 0)) > 0 && pid != ofilter)
59812111Sralph 			;
59912111Sralph 		if (status.w_stopval != WSTOPPED) {
60012111Sralph 			(void) close(fi);
60116762Sralph 			syslog(LOG_WARNING, "%s: output filter died (%d)",
60216762Sralph 				printer, status.w_retcode);
60317463Sralph 			return(REPRINT);
60412111Sralph 		}
60512111Sralph 		stopped++;
60612111Sralph 	}
60712111Sralph start:
60812111Sralph 	if ((child = dofork(DORETURN)) == 0) {	/* child */
60912111Sralph 		dup2(fi, 0);
61012111Sralph 		dup2(fo, 1);
61139954Smckusick 		n = open(tempfile, O_WRONLY|O_CREAT|O_TRUNC, 0664);
61215811Sralph 		if (n >= 0)
61315811Sralph 			dup2(n, 2);
61412111Sralph 		for (n = 3; n < NOFILE; n++)
61512111Sralph 			(void) close(n);
61612111Sralph 		execv(prog, av);
61716762Sralph 		syslog(LOG_ERR, "cannot execv %s", prog);
61812111Sralph 		exit(2);
61912111Sralph 	}
62012111Sralph 	(void) close(fi);
62112111Sralph 	if (child < 0)
62212111Sralph 		status.w_retcode = 100;
62312111Sralph 	else
62446912Sbostic 		while ((pid = wait((int *)&status)) > 0 && pid != child)
62512111Sralph 			;
62612111Sralph 	child = 0;
62712111Sralph 	prchild = 0;
62812111Sralph 	if (stopped) {		/* restart output filter */
62912111Sralph 		if (kill(ofilter, SIGCONT) < 0) {
63016762Sralph 			syslog(LOG_ERR, "cannot restart output filter");
63112111Sralph 			exit(1);
63212111Sralph 		}
63312111Sralph 	}
63412111Sralph 	tof = 0;
63539954Smckusick 
63639954Smckusick 	/* Copy filter output to "lf" logfile */
63739954Smckusick 	if (fp = fopen(tempfile, "r")) {
63839954Smckusick 		char tbuf[512];
63939954Smckusick 
64039954Smckusick 		while (fgets(buf, sizeof(buf), fp))
64139954Smckusick 			fputs(buf, stderr);
64239954Smckusick 		close(fp);
64339954Smckusick 	}
64439954Smckusick 
64515811Sralph 	if (!WIFEXITED(status)) {
64616762Sralph 		syslog(LOG_WARNING, "%s: Daemon filter '%c' terminated (%d)",
64716762Sralph 			printer, format, status.w_termsig);
64817463Sralph 		return(ERROR);
64917463Sralph 	}
65017463Sralph 	switch (status.w_retcode) {
65117463Sralph 	case 0:
65217463Sralph 		tof = 1;
65317463Sralph 		return(OK);
65417463Sralph 	case 1:
65517463Sralph 		return(REPRINT);
65617463Sralph 	default:
65716762Sralph 		syslog(LOG_WARNING, "%s: Daemon filter '%c' exited (%d)",
65816762Sralph 			printer, format, status.w_retcode);
65917463Sralph 	case 2:
66017463Sralph 		return(ERROR);
66117463Sralph 	}
66212111Sralph }
66312111Sralph 
66412111Sralph /*
66512111Sralph  * Send the daemon control file (cf) and any data files.
66612111Sralph  * Return -1 if a non-recoverable error occured, 1 if a recoverable error and
66712111Sralph  * 0 if all is well.
66812111Sralph  */
669*55474Sbostic static int
67012111Sralph sendit(file)
67112111Sralph 	char *file;
67212111Sralph {
67317463Sralph 	register int i, err = OK;
67417463Sralph 	char *cp, last[BUFSIZ];
67512111Sralph 
67612111Sralph 	/*
67712111Sralph 	 * open control file
67812111Sralph 	 */
67916762Sralph 	if ((cfp = fopen(file, "r")) == NULL)
68017463Sralph 		return(OK);
68112111Sralph 	/*
68212111Sralph 	 *      read the control file for work to do
68312111Sralph 	 *
68412111Sralph 	 *      file format -- first character in the line is a command
68512111Sralph 	 *      rest of the line is the argument.
68612111Sralph 	 *      commands of interest are:
68712111Sralph 	 *
68812111Sralph 	 *            a-z -- "file name" name of file to print
68912111Sralph 	 *              U -- "unlink" name of file to remove
69012111Sralph 	 *                    (after we print it. (Pass 2 only)).
69112111Sralph 	 */
69212111Sralph 
69312111Sralph 	/*
69412111Sralph 	 * pass 1
69512111Sralph 	 */
69612111Sralph 	while (getline(cfp)) {
69712111Sralph 	again:
69817463Sralph 		if (line[0] == 'S') {
69917463Sralph 			cp = line+1;
70017463Sralph 			i = 0;
70117463Sralph 			while (*cp >= '0' && *cp <= '9')
70217463Sralph 				i = i * 10 + (*cp++ - '0');
70317463Sralph 			fdev = i;
70417463Sralph 			cp++;
70517463Sralph 			i = 0;
70617463Sralph 			while (*cp >= '0' && *cp <= '9')
70717463Sralph 				i = i * 10 + (*cp++ - '0');
70817463Sralph 			fino = i;
70917463Sralph 			continue;
71017463Sralph 		}
71112111Sralph 		if (line[0] >= 'a' && line[0] <= 'z') {
71212111Sralph 			strcpy(last, line);
71317463Sralph 			while (i = getline(cfp))
71412111Sralph 				if (strcmp(last, line))
71512111Sralph 					break;
71617463Sralph 			switch (sendfile('\3', last+1)) {
71717463Sralph 			case OK:
71817463Sralph 				if (i)
71917463Sralph 					goto again;
72017463Sralph 				break;
72117463Sralph 			case REPRINT:
72212111Sralph 				(void) fclose(cfp);
72317463Sralph 				return(REPRINT);
72417463Sralph 			case ACCESS:
72517463Sralph 				sendmail(logname, ACCESS);
72617463Sralph 			case ERROR:
72717463Sralph 				err = ERROR;
72817463Sralph 			}
72912111Sralph 			break;
73012111Sralph 		}
73112111Sralph 	}
73217463Sralph 	if (err == OK && sendfile('\2', file) > 0) {
73312111Sralph 		(void) fclose(cfp);
73417463Sralph 		return(REPRINT);
73512111Sralph 	}
73612111Sralph 	/*
73712111Sralph 	 * pass 2
73812111Sralph 	 */
73912111Sralph 	fseek(cfp, 0L, 0);
74012111Sralph 	while (getline(cfp))
74112111Sralph 		if (line[0] == 'U')
74212111Sralph 			(void) unlink(line+1);
74312111Sralph 	/*
74417463Sralph 	 * clean-up in case another control file exists
74512111Sralph 	 */
74612111Sralph 	(void) fclose(cfp);
74712111Sralph 	(void) unlink(file);
74817463Sralph 	return(err);
74912111Sralph }
75012111Sralph 
75112111Sralph /*
75212111Sralph  * Send a data file to the remote machine and spool it.
75312111Sralph  * Return positive if we should try resending.
75412111Sralph  */
755*55474Sbostic static int
75612111Sralph sendfile(type, file)
757*55474Sbostic 	int type;
758*55474Sbostic 	char *file;
75912111Sralph {
76012111Sralph 	register int f, i, amt;
76112111Sralph 	struct stat stb;
76212111Sralph 	char buf[BUFSIZ];
76316762Sralph 	int sizerr, resp;
76412111Sralph 
76517463Sralph 	if (lstat(file, &stb) < 0 || (f = open(file, O_RDONLY)) < 0)
76617463Sralph 		return(ERROR);
76717463Sralph 	/*
76817463Sralph 	 * Check to see if data file is a symbolic link. If so, it should
76917463Sralph 	 * still point to the same file or someone is trying to print something
77017463Sralph 	 * he shouldn't.
77117463Sralph 	 */
77217463Sralph 	if ((stb.st_mode & S_IFMT) == S_IFLNK && fstat(f, &stb) == 0 &&
77317463Sralph 	    (stb.st_dev != fdev || stb.st_ino != fino))
77417463Sralph 		return(ACCESS);
775*55474Sbostic 	(void) sprintf(buf, "%c%qd %s\n", type, stb.st_size, file);
77612111Sralph 	amt = strlen(buf);
77716762Sralph 	for (i = 0;  ; i++) {
77816762Sralph 		if (write(pfd, buf, amt) != amt ||
77916762Sralph 		    (resp = response()) < 0 || resp == '\1') {
78016762Sralph 			(void) close(f);
78117463Sralph 			return(REPRINT);
78216762Sralph 		} else if (resp == '\0')
78316762Sralph 			break;
78416762Sralph 		if (i == 0)
785*55474Sbostic 			pstatus("no space on remote; waiting for queue to drain");
78616762Sralph 		if (i == 10)
78724861Seric 			syslog(LOG_ALERT, "%s: can't send to %s; queue full",
78816762Sralph 				printer, RM);
78916762Sralph 		sleep(5 * 60);
79012692Sralph 	}
79116762Sralph 	if (i)
792*55474Sbostic 		pstatus("sending to %s", RM);
79312111Sralph 	sizerr = 0;
79412111Sralph 	for (i = 0; i < stb.st_size; i += BUFSIZ) {
79512111Sralph 		amt = BUFSIZ;
79612111Sralph 		if (i + amt > stb.st_size)
79712111Sralph 			amt = stb.st_size - i;
79812111Sralph 		if (sizerr == 0 && read(f, buf, amt) != amt)
79912111Sralph 			sizerr = 1;
80012692Sralph 		if (write(pfd, buf, amt) != amt) {
80112692Sralph 			(void) close(f);
80217463Sralph 			return(REPRINT);
80312692Sralph 		}
80412111Sralph 	}
805*55474Sbostic 
806*55474Sbostic 
807*55474Sbostic 
808*55474Sbostic 
80912111Sralph 	(void) close(f);
81012111Sralph 	if (sizerr) {
81116762Sralph 		syslog(LOG_INFO, "%s: %s: changed size", printer, file);
81217463Sralph 		/* tell recvjob to ignore this file */
81317463Sralph 		(void) write(pfd, "\1", 1);
81417463Sralph 		return(ERROR);
81517463Sralph 	}
81617463Sralph 	if (write(pfd, "", 1) != 1 || response())
81717463Sralph 		return(REPRINT);
81817463Sralph 	return(OK);
81912111Sralph }
82012111Sralph 
82112111Sralph /*
82212111Sralph  * Check to make sure there have been no errors and that both programs
82312111Sralph  * are in sync with eachother.
82412111Sralph  * Return non-zero if the connection was lost.
82512111Sralph  */
826*55474Sbostic static char
82716762Sralph response()
82812111Sralph {
82912111Sralph 	char resp;
83012111Sralph 
83116762Sralph 	if (read(pfd, &resp, 1) != 1) {
83216762Sralph 		syslog(LOG_INFO, "%s: lost connection", printer);
83316762Sralph 		return(-1);
83412111Sralph 	}
83516762Sralph 	return(resp);
83612111Sralph }
83712111Sralph 
83812111Sralph /*
83912111Sralph  * Banner printing stuff
84012111Sralph  */
841*55474Sbostic static void
84212111Sralph banner(name1, name2)
84312111Sralph 	char *name1, *name2;
84412111Sralph {
84512111Sralph 	time_t tvec;
84612111Sralph 	extern char *ctime();
84712111Sralph 
84812111Sralph 	time(&tvec);
84912111Sralph 	if (!SF && !tof)
85012111Sralph 		(void) write(ofd, FF, strlen(FF));
85112111Sralph 	if (SB) {	/* short banner only */
85212111Sralph 		if (class[0]) {
85312111Sralph 			(void) write(ofd, class, strlen(class));
85412111Sralph 			(void) write(ofd, ":", 1);
85512111Sralph 		}
85612111Sralph 		(void) write(ofd, name1, strlen(name1));
85712111Sralph 		(void) write(ofd, "  Job: ", 7);
85812111Sralph 		(void) write(ofd, name2, strlen(name2));
85912111Sralph 		(void) write(ofd, "  Date: ", 8);
86012111Sralph 		(void) write(ofd, ctime(&tvec), 24);
86112111Sralph 		(void) write(ofd, "\n", 1);
86212111Sralph 	} else {	/* normal banner */
86312111Sralph 		(void) write(ofd, "\n\n\n", 3);
86412111Sralph 		scan_out(ofd, name1, '\0');
86512111Sralph 		(void) write(ofd, "\n\n", 2);
86612111Sralph 		scan_out(ofd, name2, '\0');
86712111Sralph 		if (class[0]) {
86812111Sralph 			(void) write(ofd,"\n\n\n",3);
86912111Sralph 			scan_out(ofd, class, '\0');
87012111Sralph 		}
87112111Sralph 		(void) write(ofd, "\n\n\n\n\t\t\t\t\tJob:  ", 15);
87212111Sralph 		(void) write(ofd, name2, strlen(name2));
87312111Sralph 		(void) write(ofd, "\n\t\t\t\t\tDate: ", 12);
87412111Sralph 		(void) write(ofd, ctime(&tvec), 24);
87512111Sralph 		(void) write(ofd, "\n", 1);
87612111Sralph 	}
87712111Sralph 	if (!SF)
87812111Sralph 		(void) write(ofd, FF, strlen(FF));
87912111Sralph 	tof = 1;
88012111Sralph }
88112111Sralph 
882*55474Sbostic static char *
88312111Sralph scnline(key, p, c)
884*55474Sbostic 	register int key;
885*55474Sbostic 	register char *p;
886*55474Sbostic 	int c;
88712111Sralph {
88812111Sralph 	register scnwidth;
88912111Sralph 
89012111Sralph 	for (scnwidth = WIDTH; --scnwidth;) {
89112111Sralph 		key <<= 1;
89212111Sralph 		*p++ = key & 0200 ? c : BACKGND;
89312111Sralph 	}
89412111Sralph 	return (p);
89512111Sralph }
89612111Sralph 
89712111Sralph #define TRC(q)	(((q)-' ')&0177)
89812111Sralph 
899*55474Sbostic static void
90012111Sralph scan_out(scfd, scsp, dlm)
901*55474Sbostic 	int scfd, dlm;
902*55474Sbostic 	char *scsp;
90312111Sralph {
90412111Sralph 	register char *strp;
90512111Sralph 	register nchrs, j;
90612111Sralph 	char outbuf[LINELEN+1], *sp, c, cc;
90712111Sralph 	int d, scnhgt;
90812111Sralph 	extern char scnkey[][HEIGHT];	/* in lpdchar.c */
90912111Sralph 
91012111Sralph 	for (scnhgt = 0; scnhgt++ < HEIGHT+DROP; ) {
91112111Sralph 		strp = &outbuf[0];
91212111Sralph 		sp = scsp;
91312111Sralph 		for (nchrs = 0; ; ) {
91412111Sralph 			d = dropit(c = TRC(cc = *sp++));
91512111Sralph 			if ((!d && scnhgt > HEIGHT) || (scnhgt <= DROP && d))
91612111Sralph 				for (j = WIDTH; --j;)
91712111Sralph 					*strp++ = BACKGND;
91812111Sralph 			else
91912111Sralph 				strp = scnline(scnkey[c][scnhgt-1-d], strp, cc);
92012111Sralph 			if (*sp == dlm || *sp == '\0' || nchrs++ >= PW/(WIDTH+1)-1)
92112111Sralph 				break;
92212111Sralph 			*strp++ = BACKGND;
92312111Sralph 			*strp++ = BACKGND;
92412111Sralph 		}
92512111Sralph 		while (*--strp == BACKGND && strp >= outbuf)
92612111Sralph 			;
92712111Sralph 		strp++;
92812111Sralph 		*strp++ = '\n';
92912111Sralph 		(void) write(scfd, outbuf, strp-outbuf);
93012111Sralph 	}
93112111Sralph }
93212111Sralph 
933*55474Sbostic static int
93412111Sralph dropit(c)
935*55474Sbostic 	int c;
93612111Sralph {
93712111Sralph 	switch(c) {
93812111Sralph 
93912111Sralph 	case TRC('_'):
94012111Sralph 	case TRC(';'):
94112111Sralph 	case TRC(','):
94212111Sralph 	case TRC('g'):
94312111Sralph 	case TRC('j'):
94412111Sralph 	case TRC('p'):
94512111Sralph 	case TRC('q'):
94612111Sralph 	case TRC('y'):
94712111Sralph 		return (DROP);
94812111Sralph 
94912111Sralph 	default:
95012111Sralph 		return (0);
95112111Sralph 	}
95212111Sralph }
95312111Sralph 
95412111Sralph /*
95512111Sralph  * sendmail ---
95612111Sralph  *   tell people about job completion
95712111Sralph  */
958*55474Sbostic static void
95915811Sralph sendmail(user, bombed)
96015811Sralph 	char *user;
96112111Sralph 	int bombed;
96212111Sralph {
96312111Sralph 	register int i;
96415811Sralph 	int p[2], s;
96512111Sralph 	register char *cp;
96612111Sralph 	char buf[100];
96715811Sralph 	struct stat stb;
96815811Sralph 	FILE *fp;
96912111Sralph 
97012111Sralph 	pipe(p);
97115811Sralph 	if ((s = dofork(DORETURN)) == 0) {		/* child */
97212111Sralph 		dup2(p[0], 0);
97312111Sralph 		for (i = 3; i < NOFILE; i++)
97412111Sralph 			(void) close(i);
97537968Sbostic 		if ((cp = rindex(_PATH_SENDMAIL, '/')) != NULL)
97612111Sralph 			cp++;
977*55474Sbostic 	else
97837968Sbostic 			cp = _PATH_SENDMAIL;
97915811Sralph 		sprintf(buf, "%s@%s", user, fromhost);
98037968Sbostic 		execl(_PATH_SENDMAIL, cp, buf, 0);
98112111Sralph 		exit(0);
98215811Sralph 	} else if (s > 0) {				/* parent */
98312111Sralph 		dup2(p[1], 1);
98415811Sralph 		printf("To: %s@%s\n", user, fromhost);
98512111Sralph 		printf("Subject: printer job\n\n");
98612111Sralph 		printf("Your printer job ");
98712111Sralph 		if (*jobname)
98812111Sralph 			printf("(%s) ", jobname);
98912463Sralph 		switch (bombed) {
99017463Sralph 		case OK:
99112463Sralph 			printf("\ncompleted successfully\n");
99212463Sralph 			break;
99312463Sralph 		default:
99417463Sralph 		case FATALERR:
99512463Sralph 			printf("\ncould not be printed\n");
99612463Sralph 			break;
99717463Sralph 		case NOACCT:
99812463Sralph 			printf("\ncould not be printed without an account on %s\n", host);
99912463Sralph 			break;
100017463Sralph 		case FILTERERR:
100139954Smckusick 			if (stat(tempfile, &stb) < 0 || stb.st_size == 0 ||
100239954Smckusick 			    (fp = fopen(tempfile, "r")) == NULL) {
100315811Sralph 				printf("\nwas printed but had some errors\n");
100415811Sralph 				break;
100515811Sralph 			}
100615811Sralph 			printf("\nwas printed but had the following errors:\n");
100715811Sralph 			while ((i = getc(fp)) != EOF)
100815811Sralph 				putchar(i);
100915811Sralph 			(void) fclose(fp);
101017463Sralph 			break;
101117463Sralph 		case ACCESS:
101217463Sralph 			printf("\nwas not printed because it was not linked to the original file\n");
101312463Sralph 		}
101412111Sralph 		fflush(stdout);
101512111Sralph 		(void) close(1);
101612111Sralph 	}
101712111Sralph 	(void) close(p[0]);
101812111Sralph 	(void) close(p[1]);
101915811Sralph 	wait(&s);
102012111Sralph }
102112111Sralph 
102212111Sralph /*
102312111Sralph  * dofork - fork with retries on failure
102412111Sralph  */
1025*55474Sbostic static int
102612111Sralph dofork(action)
102712111Sralph 	int action;
102812111Sralph {
102912111Sralph 	register int i, pid;
103012111Sralph 
103112111Sralph 	for (i = 0; i < 20; i++) {
103212463Sralph 		if ((pid = fork()) < 0) {
103312111Sralph 			sleep((unsigned)(i*i));
103412463Sralph 			continue;
103512463Sralph 		}
103612463Sralph 		/*
103712463Sralph 		 * Child should run as daemon instead of root
103812463Sralph 		 */
103912463Sralph 		if (pid == 0)
104012463Sralph 			setuid(DU);
104112463Sralph 		return(pid);
104212111Sralph 	}
104316762Sralph 	syslog(LOG_ERR, "can't fork");
104412111Sralph 
104512111Sralph 	switch (action) {
104612111Sralph 	case DORETURN:
104712111Sralph 		return (-1);
104812111Sralph 	default:
104916762Sralph 		syslog(LOG_ERR, "bad action (%d) to dofork", action);
105012111Sralph 		/*FALL THRU*/
105112111Sralph 	case DOABORT:
105212111Sralph 		exit(1);
105312111Sralph 	}
105412111Sralph 	/*NOTREACHED*/
105512111Sralph }
105612111Sralph 
105712111Sralph /*
105816762Sralph  * Kill child processes to abort current job.
105912111Sralph  */
1060*55474Sbostic static void
1061*55474Sbostic abortpr(signo)
1062*55474Sbostic 	int signo;
106312111Sralph {
106439954Smckusick 	(void) unlink(tempfile);
106512111Sralph 	kill(0, SIGINT);
106612111Sralph 	if (ofilter > 0)
106712111Sralph 		kill(ofilter, SIGCONT);
106846912Sbostic 	while (wait(NULL) > 0)
106912111Sralph 		;
107012111Sralph 	exit(0);
107112111Sralph }
107212111Sralph 
1073*55474Sbostic static void
107412111Sralph init()
107512111Sralph {
107612111Sralph 	int status;
107738736Stef 	char *s;
107812111Sralph 
107925468Stef 	if ((status = pgetent(line, printer)) < 0) {
108025468Stef 		syslog(LOG_ERR, "can't open printer description file");
108125468Stef 		exit(1);
108225468Stef 	} else if (status == 0) {
108325468Stef 		syslog(LOG_ERR, "unknown printer: %s", printer);
108425468Stef 		exit(1);
108525468Stef 	}
108612111Sralph 	if ((LP = pgetstr("lp", &bp)) == NULL)
108737968Sbostic 		LP = _PATH_DEFDEVLP;
108812111Sralph 	if ((RP = pgetstr("rp", &bp)) == NULL)
108912463Sralph 		RP = DEFLP;
109012111Sralph 	if ((LO = pgetstr("lo", &bp)) == NULL)
109112111Sralph 		LO = DEFLOCK;
109212111Sralph 	if ((ST = pgetstr("st", &bp)) == NULL)
109312111Sralph 		ST = DEFSTAT;
109412111Sralph 	if ((LF = pgetstr("lf", &bp)) == NULL)
109537968Sbostic 		LF = _PATH_CONSOLE;
109612111Sralph 	if ((SD = pgetstr("sd", &bp)) == NULL)
109737968Sbostic 		SD = _PATH_DEFSPOOL;
109812111Sralph 	if ((DU = pgetnum("du")) < 0)
109912111Sralph 		DU = DEFUID;
110012111Sralph 	if ((FF = pgetstr("ff", &bp)) == NULL)
110112111Sralph 		FF = DEFFF;
110212111Sralph 	if ((PW = pgetnum("pw")) < 0)
110312111Sralph 		PW = DEFWIDTH;
110412111Sralph 	sprintf(&width[2], "%d", PW);
110512111Sralph 	if ((PL = pgetnum("pl")) < 0)
110612111Sralph 		PL = DEFLENGTH;
110712111Sralph 	sprintf(&length[2], "%d", PL);
110812463Sralph 	if ((PX = pgetnum("px")) < 0)
110912463Sralph 		PX = 0;
111012463Sralph 	sprintf(&pxwidth[2], "%d", PX);
111112463Sralph 	if ((PY = pgetnum("py")) < 0)
111212463Sralph 		PY = 0;
111312463Sralph 	sprintf(&pxlength[2], "%d", PY);
111412111Sralph 	RM = pgetstr("rm", &bp);
111538736Stef 	if (s = checkremote())
111638736Stef 		syslog(LOG_WARNING, s);
111725468Stef 
111812111Sralph 	AF = pgetstr("af", &bp);
111912111Sralph 	OF = pgetstr("of", &bp);
112012111Sralph 	IF = pgetstr("if", &bp);
112112463Sralph 	RF = pgetstr("rf", &bp);
112212111Sralph 	TF = pgetstr("tf", &bp);
112313233Sralph 	NF = pgetstr("nf", &bp);
112412111Sralph 	DF = pgetstr("df", &bp);
112512111Sralph 	GF = pgetstr("gf", &bp);
112612111Sralph 	VF = pgetstr("vf", &bp);
112712111Sralph 	CF = pgetstr("cf", &bp);
112812111Sralph 	TR = pgetstr("tr", &bp);
112912463Sralph 	RS = pgetflag("rs");
113012111Sralph 	SF = pgetflag("sf");
113112111Sralph 	SH = pgetflag("sh");
113212111Sralph 	SB = pgetflag("sb");
113318127Sralph 	HL = pgetflag("hl");
113412111Sralph 	RW = pgetflag("rw");
113512111Sralph 	BR = pgetnum("br");
113612111Sralph 	if ((FC = pgetnum("fc")) < 0)
113712111Sralph 		FC = 0;
113812111Sralph 	if ((FS = pgetnum("fs")) < 0)
113912111Sralph 		FS = 0;
114012111Sralph 	if ((XC = pgetnum("xc")) < 0)
114112111Sralph 		XC = 0;
114212111Sralph 	if ((XS = pgetnum("xs")) < 0)
114312111Sralph 		XS = 0;
114412581Sralph 	tof = !pgetflag("fo");
114512111Sralph }
114612111Sralph 
114712463Sralph /*
114812463Sralph  * Acquire line printer or remote connection.
114912463Sralph  */
1150*55474Sbostic static void
115112463Sralph openpr()
115212463Sralph {
115312463Sralph 	register int i, n;
115416762Sralph 	int resp;
115512463Sralph 
115638736Stef 	if (!sendtorem && *LP) {
115712463Sralph 		for (i = 1; ; i = i < 32 ? i << 1 : i) {
115813148Ssam 			pfd = open(LP, RW ? O_RDWR : O_WRONLY);
115912463Sralph 			if (pfd >= 0)
116012463Sralph 				break;
116112463Sralph 			if (errno == ENOENT) {
116216762Sralph 				syslog(LOG_ERR, "%s: %m", LP);
116312463Sralph 				exit(1);
116412463Sralph 			}
116512463Sralph 			if (i == 1)
1166*55474Sbostic 				pstatus("waiting for %s to become ready (offline ?)", printer);
116712463Sralph 			sleep(i);
116812463Sralph 		}
116912463Sralph 		if (isatty(pfd))
117012463Sralph 			setty();
1171*55474Sbostic 		pstatus("%s is ready and printing", printer);
117212463Sralph 	} else if (RM != NULL) {
117316762Sralph 		for (i = 1; ; i = i < 256 ? i << 1 : i) {
117416762Sralph 			resp = -1;
117512528Sralph 			pfd = getport(RM);
117612463Sralph 			if (pfd >= 0) {
117712463Sralph 				(void) sprintf(line, "\2%s\n", RP);
117812463Sralph 				n = strlen(line);
117916762Sralph 				if (write(pfd, line, n) == n &&
118016762Sralph 				    (resp = response()) == '\0')
118112463Sralph 					break;
118216031Sralph 				(void) close(pfd);
118312463Sralph 			}
118416031Sralph 			if (i == 1) {
118516762Sralph 				if (resp < 0)
1186*55474Sbostic 					pstatus("waiting for %s to come up", RM);
118716762Sralph 				else {
1188*55474Sbostic 					pstatus("waiting for queue to be enabled on %s", RM);
118916762Sralph 					i = 256;
119016762Sralph 				}
119116031Sralph 			}
119212463Sralph 			sleep(i);
119312463Sralph 		}
1194*55474Sbostic 		pstatus("sending to %s", RM);
119512463Sralph 		remote = 1;
119612463Sralph 	} else {
119716762Sralph 		syslog(LOG_ERR, "%s: no line printer device or host name",
119816762Sralph 			printer);
119912463Sralph 		exit(1);
120012463Sralph 	}
120112463Sralph 	/*
120212463Sralph 	 * Start up an output filter, if needed.
120312463Sralph 	 */
120440049Stef 	if (!remote && OF) {
120512463Sralph 		int p[2];
120612463Sralph 		char *cp;
120712463Sralph 
120812463Sralph 		pipe(p);
120912463Sralph 		if ((ofilter = dofork(DOABORT)) == 0) {	/* child */
121012463Sralph 			dup2(p[0], 0);		/* pipe is std in */
121112463Sralph 			dup2(pfd, 1);		/* printer is std out */
121212463Sralph 			for (i = 3; i < NOFILE; i++)
121312463Sralph 				(void) close(i);
121412463Sralph 			if ((cp = rindex(OF, '/')) == NULL)
121512463Sralph 				cp = OF;
121612463Sralph 			else
121712463Sralph 				cp++;
121812463Sralph 			execl(OF, cp, width, length, 0);
121916762Sralph 			syslog(LOG_ERR, "%s: %s: %m", printer, OF);
122012463Sralph 			exit(1);
122112463Sralph 		}
122212463Sralph 		(void) close(p[0]);		/* close input side */
122312463Sralph 		ofd = p[1];			/* use pipe for output */
122412463Sralph 	} else {
122512463Sralph 		ofd = pfd;
122612463Sralph 		ofilter = 0;
122712463Sralph 	}
122812463Sralph }
122912463Sralph 
123012111Sralph struct bauds {
123112111Sralph 	int	baud;
123212111Sralph 	int	speed;
123312111Sralph } bauds[] = {
123412111Sralph 	50,	B50,
123512111Sralph 	75,	B75,
123612111Sralph 	110,	B110,
123712111Sralph 	134,	B134,
123812111Sralph 	150,	B150,
123912111Sralph 	200,	B200,
124012111Sralph 	300,	B300,
124112111Sralph 	600,	B600,
124212111Sralph 	1200,	B1200,
124312111Sralph 	1800,	B1800,
124412111Sralph 	2400,	B2400,
124512111Sralph 	4800,	B4800,
124612111Sralph 	9600,	B9600,
124712111Sralph 	19200,	EXTA,
124812111Sralph 	38400,	EXTB,
124912111Sralph 	0,	0
125012111Sralph };
125112111Sralph 
125212111Sralph /*
125312111Sralph  * setup tty lines.
125412111Sralph  */
1255*55474Sbostic static void
125612111Sralph setty()
125712111Sralph {
125812111Sralph 	struct sgttyb ttybuf;
125912111Sralph 	register struct bauds *bp;
126012111Sralph 
126112111Sralph 	if (ioctl(pfd, TIOCEXCL, (char *)0) < 0) {
126216762Sralph 		syslog(LOG_ERR, "%s: ioctl(TIOCEXCL): %m", printer);
126312111Sralph 		exit(1);
126412111Sralph 	}
126512111Sralph 	if (ioctl(pfd, TIOCGETP, (char *)&ttybuf) < 0) {
126616762Sralph 		syslog(LOG_ERR, "%s: ioctl(TIOCGETP): %m", printer);
126712111Sralph 		exit(1);
126812111Sralph 	}
126912111Sralph 	if (BR > 0) {
127012111Sralph 		for (bp = bauds; bp->baud; bp++)
127112111Sralph 			if (BR == bp->baud)
127212111Sralph 				break;
127312111Sralph 		if (!bp->baud) {
127416762Sralph 			syslog(LOG_ERR, "%s: illegal baud rate %d", printer, BR);
127512111Sralph 			exit(1);
127612111Sralph 		}
127712111Sralph 		ttybuf.sg_ispeed = ttybuf.sg_ospeed = bp->speed;
127812111Sralph 	}
127913169Sralph 	ttybuf.sg_flags &= ~FC;
128013169Sralph 	ttybuf.sg_flags |= FS;
128112111Sralph 	if (ioctl(pfd, TIOCSETP, (char *)&ttybuf) < 0) {
128216762Sralph 		syslog(LOG_ERR, "%s: ioctl(TIOCSETP): %m", printer);
128312111Sralph 		exit(1);
128412111Sralph 	}
128512111Sralph 	if (XC) {
128612111Sralph 		if (ioctl(pfd, TIOCLBIC, &XC) < 0) {
128716762Sralph 			syslog(LOG_ERR, "%s: ioctl(TIOCLBIC): %m", printer);
128812111Sralph 			exit(1);
128912111Sralph 		}
129012111Sralph 	}
129112111Sralph 	if (XS) {
129212111Sralph 		if (ioctl(pfd, TIOCLBIS, &XS) < 0) {
129316762Sralph 			syslog(LOG_ERR, "%s: ioctl(TIOCLBIS): %m", printer);
129412111Sralph 			exit(1);
129512111Sralph 		}
129612111Sralph 	}
129712111Sralph }
129812463Sralph 
1299*55474Sbostic #if __STDC__
1300*55474Sbostic #include <stdarg.h>
1301*55474Sbostic #else
1302*55474Sbostic #include <varargs.h>
1303*55474Sbostic #endif
1304*55474Sbostic 
1305*55474Sbostic void
1306*55474Sbostic #if __STDC__
1307*55474Sbostic pstatus(const char *msg, ...)
1308*55474Sbostic #else
1309*55474Sbostic pstatus(msg, va_alist)
131012463Sralph 	char *msg;
1311*55474Sbostic         va_dcl
1312*55474Sbostic #endif
131312463Sralph {
131412463Sralph 	register int fd;
131512463Sralph 	char buf[BUFSIZ];
1316*55474Sbostic 	va_list ap;
1317*55474Sbostic #if __STDC__
1318*55474Sbostic 	va_start(ap, msg);
1319*55474Sbostic #else
1320*55474Sbostic 	va_start(ap);
1321*55474Sbostic #endif
132212463Sralph 
132312463Sralph 	umask(0);
132413148Ssam 	fd = open(ST, O_WRONLY|O_CREAT, 0664);
132516762Sralph 	if (fd < 0 || flock(fd, LOCK_EX) < 0) {
132616762Sralph 		syslog(LOG_ERR, "%s: %s: %m", printer, ST);
132716762Sralph 		exit(1);
132816762Sralph 	}
132913148Ssam 	ftruncate(fd, 0);
1330*55474Sbostic 	(void)vsnprintf(buf, sizeof(buf), msg, ap);
1331*55474Sbostic 	va_end(ap);
133212463Sralph 	strcat(buf, "\n");
133312463Sralph 	(void) write(fd, buf, strlen(buf));
133412463Sralph 	(void) close(fd);
133512463Sralph }
1336