xref: /csrg-svn/usr.sbin/lpr/lpd/printjob.c (revision 18127)
113954Ssam #ifndef lint
2*18127Sralph static char sccsid[] = "@(#)printjob.c	4.24 (Berkeley) 02/27/85";
313954Ssam #endif
413954Ssam 
512111Sralph /*
612111Sralph  * printjob -- print jobs in the queue.
712111Sralph  *
812111Sralph  *	NOTE: the lock file is used to pass information to lpq and lprm.
912111Sralph  *	it does not need to be removed because file locks are dynamic.
1012111Sralph  */
1112111Sralph 
1212111Sralph #include "lp.h"
1312111Sralph 
1416762Sralph #define DORETURN	0	/* absorb fork error */
1516762Sralph #define DOABORT		1	/* abort if dofork fails */
1612111Sralph 
1717463Sralph /*
1817463Sralph  * Error tokens
1917463Sralph  */
2017463Sralph #define REPRINT		-2
2117463Sralph #define ERROR		-1
2217463Sralph #define	OK		0
2317463Sralph #define	FATALERR	1
2417463Sralph #define	NOACCT		2
2517463Sralph #define	FILTERERR	3
2617463Sralph #define	ACCESS		4
2717463Sralph 
2816762Sralph char	title[80];		/* ``pr'' title */
2916762Sralph FILE	*cfp;			/* control file */
3016762Sralph int	pfd;			/* printer file descriptor */
3116762Sralph int	ofd;			/* output filter file descriptor */
3216762Sralph int	lfd;			/* lock file descriptor */
3316762Sralph int	pid;			/* pid of lpd process */
3416762Sralph int	prchild;		/* id of pr process */
3516762Sralph int	child;			/* id of any filters */
3616762Sralph int	ofilter;		/* id of output filter, if any */
3716762Sralph int	tof;			/* true if at top of form */
3816762Sralph int	remote;			/* true if sending files to remote */
3917463Sralph dev_t	fdev;			/* device of file pointed to by symlink */
4017463Sralph ino_t	fino;			/* inode of file pointed to by symlink */
4112111Sralph 
4216762Sralph char	fromhost[32];		/* user's host machine */
4316762Sralph char	logname[32];		/* user's login name */
4416762Sralph char	jobname[100];		/* job or file name */
4516762Sralph char	class[32];		/* classification field */
4616762Sralph char	width[10] = "-w";	/* page width in characters */
4716762Sralph char	length[10] = "-l";	/* page length in lines */
4816762Sralph char	pxwidth[10] = "-x";	/* page width in pixels */
4916762Sralph char	pxlength[10] = "-y";	/* page length in pixels */
5016762Sralph char	indent[10] = "-i0";	/* indentation size in characters */
5116762Sralph char	tmpfile[] = "errsXXXXXX"; /* file name for filter output */
5212111Sralph 
5312111Sralph printjob()
5412111Sralph {
5512111Sralph 	struct stat stb;
5612111Sralph 	register struct queue *q, **qp;
5712111Sralph 	struct queue **queue;
5812111Sralph 	register int i, nitems;
5912111Sralph 	long pidoff;
6016762Sralph 	int count = 0;
6116762Sralph 	extern int abortpr();
6212111Sralph 
6312111Sralph 	init();					/* set up capabilities */
6413442Sralph 	(void) write(1, "", 1);			/* ack that daemon is started */
6516762Sralph 	setgid(getegid());
6612463Sralph 	pid = getpid();				/* for use with lprm */
6712111Sralph 	setpgrp(0, pid);
6816762Sralph 	signal(SIGHUP, abortpr);
6916762Sralph 	signal(SIGINT, abortpr);
7016762Sralph 	signal(SIGQUIT, abortpr);
7116762Sralph 	signal(SIGTERM, abortpr);
7212111Sralph 
7315811Sralph 	(void) mktemp(tmpfile);
7415811Sralph 
7512111Sralph 	/*
7612111Sralph 	 * uses short form file names
7712111Sralph 	 */
7812111Sralph 	if (chdir(SD) < 0) {
7916762Sralph 		syslog(LOG_ERR, "%s: %m", SD);
8012111Sralph 		exit(1);
8112111Sralph 	}
8212463Sralph 	if (stat(LO, &stb) == 0 && (stb.st_mode & 0100))
8312463Sralph 		exit(0);		/* printing disabled */
8414150Sralph 	lfd = open(LO, O_WRONLY|O_CREAT, 0644);
8513169Sralph 	if (lfd < 0) {
8616762Sralph 		syslog(LOG_ERR, "%s: %s: %m", printer, LO);
8713169Sralph 		exit(1);
8813169Sralph 	}
8913169Sralph 	if (flock(lfd, LOCK_EX|LOCK_NB) < 0) {
9012111Sralph 		if (errno == EWOULDBLOCK)	/* active deamon present */
9112111Sralph 			exit(0);
9216762Sralph 		syslog(LOG_ERR, "%s: %s: %m", printer, LO);
9312111Sralph 		exit(1);
9412111Sralph 	}
9513148Ssam 	ftruncate(lfd, 0);
9612111Sralph 	/*
9712111Sralph 	 * write process id for others to know
9812111Sralph 	 */
9912111Sralph 	sprintf(line, "%u\n", pid);
10012111Sralph 	pidoff = i = strlen(line);
10112463Sralph 	if (write(lfd, line, i) != i) {
10216762Sralph 		syslog(LOG_ERR, "%s: %s: %m", printer, LO);
10312111Sralph 		exit(1);
10412111Sralph 	}
10512111Sralph 	/*
10612111Sralph 	 * search the spool directory for work and sort by queue order.
10712111Sralph 	 */
10812111Sralph 	if ((nitems = getq(&queue)) < 0) {
10916762Sralph 		syslog(LOG_ERR, "%s: can't scan %s", printer, SD);
11012111Sralph 		exit(1);
11112111Sralph 	}
11212463Sralph 	if (nitems == 0)		/* no work to do */
11312111Sralph 		exit(0);
11413169Sralph 	if (stb.st_mode & 01) {		/* reset queue flag */
11513169Sralph 		if (fchmod(lfd, stb.st_mode & 0776) < 0)
11616762Sralph 			syslog(LOG_ERR, "%s: %s: %m", printer, LO);
11713169Sralph 	}
11812463Sralph 	openpr();			/* open printer or remote */
11912463Sralph again:
12012111Sralph 	/*
12112111Sralph 	 * we found something to do now do it --
12212111Sralph 	 *    write the name of the current control file into the lock file
12312111Sralph 	 *    so the spool queue program can tell what we're working on
12412111Sralph 	 */
12512111Sralph 	for (qp = queue; nitems--; free((char *) q)) {
12612111Sralph 		q = *qp++;
12712111Sralph 		if (stat(q->q_name, &stb) < 0)
12812111Sralph 			continue;
12912463Sralph 	restart:
13012111Sralph 		(void) lseek(lfd, pidoff, 0);
13112111Sralph 		(void) sprintf(line, "%s\n", q->q_name);
13212111Sralph 		i = strlen(line);
13312111Sralph 		if (write(lfd, line, i) != i)
13416762Sralph 			syslog(LOG_ERR, "%s: %s: %m", printer, LO);
13512111Sralph 		if (!remote)
13612111Sralph 			i = printit(q->q_name);
13712111Sralph 		else
13812111Sralph 			i = sendit(q->q_name);
13912463Sralph 		/*
14013169Sralph 		 * Check to see if we are supposed to stop printing or
14113169Sralph 		 * if we are to rebuild the queue.
14212463Sralph 		 */
14313169Sralph 		if (fstat(lfd, &stb) == 0) {
14416762Sralph 			/* stop printing before starting next job? */
14513169Sralph 			if (stb.st_mode & 0100)
14613169Sralph 				goto done;
14716762Sralph 			/* rebuild queue (after lpc topq) */
14813169Sralph 			if (stb.st_mode & 01) {
14913169Sralph 				for (free((char *) q); nitems--; free((char *) q))
15013169Sralph 					q = *qp++;
15113169Sralph 				if (fchmod(lfd, stb.st_mode & 0776) < 0)
15216762Sralph 					syslog(LOG_WARNING, "%s: %s: %m",
15316762Sralph 						printer, LO);
15413169Sralph 				break;
15513169Sralph 			}
15613169Sralph 		}
15717463Sralph 		if (i == OK)		/* file ok and printed */
15814150Sralph 			count++;
15917463Sralph 		else if (i == REPRINT) { /* try reprinting the job */
16016762Sralph 			syslog(LOG_INFO, "restarting %s", printer);
16112111Sralph 			if (ofilter > 0) {
16212111Sralph 				kill(ofilter, SIGCONT);	/* to be sure */
16312111Sralph 				(void) close(ofd);
16412111Sralph 				while ((i = wait(0)) > 0 && i != ofilter)
16512111Sralph 					;
16612111Sralph 				ofilter = 0;
16712111Sralph 			}
16812463Sralph 			(void) close(pfd);	/* close printer */
16915811Sralph 			if (ftruncate(lfd, pidoff) < 0)
17016762Sralph 				syslog(LOG_WARNING, "%s: %s: %m", printer, LO);
17112463Sralph 			openpr();		/* try to reopen printer */
17212111Sralph 			goto restart;
17312111Sralph 		}
17412111Sralph 	}
17512111Sralph 	free((char *) queue);
17612463Sralph 	/*
17712463Sralph 	 * search the spool directory for more work.
17812463Sralph 	 */
17912463Sralph 	if ((nitems = getq(&queue)) < 0) {
18016762Sralph 		syslog(LOG_ERR, "%s: can't scan %s", printer, SD);
18112463Sralph 		exit(1);
18212463Sralph 	}
18312463Sralph 	if (nitems == 0) {		/* no more work to do */
18412463Sralph 	done:
18514150Sralph 		if (count > 0) {	/* Files actually printed */
18614150Sralph 			if (!SF && !tof)
18714150Sralph 				(void) write(ofd, FF, strlen(FF));
18814150Sralph 			if (TR != NULL)		/* output trailer */
18914150Sralph 				(void) write(ofd, TR, strlen(TR));
19014150Sralph 		}
19115811Sralph 		(void) unlink(tmpfile);
19212463Sralph 		exit(0);
19312463Sralph 	}
19412111Sralph 	goto again;
19512111Sralph }
19612111Sralph 
19712111Sralph char	fonts[4][50];	/* fonts for troff */
19812111Sralph 
19916762Sralph char ifonts[4][18] = {
20012111Sralph 	"/usr/lib/vfont/R",
20112111Sralph 	"/usr/lib/vfont/I",
20212111Sralph 	"/usr/lib/vfont/B",
20312111Sralph 	"/usr/lib/vfont/S"
20412111Sralph };
20512111Sralph 
20612111Sralph /*
20712111Sralph  * The remaining part is the reading of the control file (cf)
20812111Sralph  * and performing the various actions.
20912111Sralph  */
21012111Sralph printit(file)
21112111Sralph 	char *file;
21212111Sralph {
21312111Sralph 	register int i;
21417463Sralph 	char *cp;
21517463Sralph 	int bombed = OK;
21612111Sralph 
21712111Sralph 	/*
21817463Sralph 	 * open control file; ignore if no longer there.
21912111Sralph 	 */
22012111Sralph 	if ((cfp = fopen(file, "r")) == NULL) {
22116762Sralph 		syslog(LOG_INFO, "%s: %s: %m", printer, file);
22217463Sralph 		return(OK);
22312111Sralph 	}
22412111Sralph 	/*
22512111Sralph 	 * Reset troff fonts.
22612111Sralph 	 */
22712111Sralph 	for (i = 0; i < 4; i++)
22812111Sralph 		strcpy(fonts[i], ifonts[i]);
22917339Sralph 	strcpy(width+2, "0");
23017302Sralph 	strcpy(indent+2, "0");
23112111Sralph 
23212111Sralph 	/*
23312111Sralph 	 *      read the control file for work to do
23412111Sralph 	 *
23512111Sralph 	 *      file format -- first character in the line is a command
23612111Sralph 	 *      rest of the line is the argument.
23712111Sralph 	 *      valid commands are:
23812111Sralph 	 *
23917463Sralph 	 *		S -- "stat info" for symbolic link protection
24012111Sralph 	 *		J -- "job name" on banner page
24112111Sralph 	 *		C -- "class name" on banner page
24212111Sralph 	 *              L -- "literal" user's name to print on banner
24312111Sralph 	 *		T -- "title" for pr
24412111Sralph 	 *		H -- "host name" of machine where lpr was done
24512111Sralph 	 *              P -- "person" user's login name
24612581Sralph 	 *              I -- "indent" amount to indent output
24712111Sralph 	 *              f -- "file name" name of text file to print
24812111Sralph 	 *		l -- "file name" text file with control chars
24912111Sralph 	 *		p -- "file name" text file to print with pr(1)
25012111Sralph 	 *		t -- "file name" troff(1) file to print
25113233Sralph 	 *		n -- "file name" ditroff(1) file to print
25212111Sralph 	 *		d -- "file name" dvi file to print
25312111Sralph 	 *		g -- "file name" plot(1G) file to print
25412111Sralph 	 *		v -- "file name" plain raster file to print
25512111Sralph 	 *		c -- "file name" cifplot file to print
25612111Sralph 	 *		1 -- "R font file" for troff
25712111Sralph 	 *		2 -- "I font file" for troff
25812111Sralph 	 *		3 -- "B font file" for troff
25912111Sralph 	 *		4 -- "S font file" for troff
26012111Sralph 	 *		N -- "name" of file (used by lpq)
26112111Sralph 	 *              U -- "unlink" name of file to remove
26212111Sralph 	 *                    (after we print it. (Pass 2 only)).
26312111Sralph 	 *		M -- "mail" to user when done printing
26412111Sralph 	 *
26512111Sralph 	 *      getline reads a line and expands tabs to blanks
26612111Sralph 	 */
26712111Sralph 
26812111Sralph 	/* pass 1 */
26912111Sralph 
27012111Sralph 	while (getline(cfp))
27112111Sralph 		switch (line[0]) {
27212111Sralph 		case 'H':
27314150Sralph 			strcpy(fromhost, line+1);
27412111Sralph 			if (class[0] == '\0')
27515552Sralph 				strncpy(class, line+1, sizeof(class)-1);
27612111Sralph 			continue;
27712111Sralph 
27812111Sralph 		case 'P':
27915552Sralph 			strncpy(logname, line+1, sizeof(logname)-1);
28012463Sralph 			if (RS) {			/* restricted */
28112463Sralph 				if (getpwnam(logname) == (struct passwd *)0) {
28217463Sralph 					bombed = NOACCT;
28315811Sralph 					sendmail(line+1, bombed);
28412463Sralph 					goto pass2;
28512463Sralph 				}
28612463Sralph 			}
28712111Sralph 			continue;
28812111Sralph 
28917463Sralph 		case 'S':
29017463Sralph 			cp = line+1;
29117463Sralph 			i = 0;
29217463Sralph 			while (*cp >= '0' && *cp <= '9')
29317463Sralph 				i = i * 10 + (*cp++ - '0');
29417463Sralph 			fdev = i;
29517463Sralph 			cp++;
29617463Sralph 			i = 0;
29717463Sralph 			while (*cp >= '0' && *cp <= '9')
29817463Sralph 				i = i * 10 + (*cp++ - '0');
29917463Sralph 			fino = i;
30017463Sralph 			continue;
30117463Sralph 
30212111Sralph 		case 'J':
30312111Sralph 			if (line[1] != '\0')
30415552Sralph 				strncpy(jobname, line+1, sizeof(jobname)-1);
30512111Sralph 			else
30612111Sralph 				strcpy(jobname, " ");
30712111Sralph 			continue;
30812111Sralph 
30912111Sralph 		case 'C':
31012111Sralph 			if (line[1] != '\0')
31115552Sralph 				strncpy(class, line+1, sizeof(class)-1);
31212111Sralph 			else if (class[0] == '\0')
31315811Sralph 				gethostname(class, sizeof(class));
31412111Sralph 			continue;
31512111Sralph 
31612111Sralph 		case 'T':	/* header title for pr */
31715552Sralph 			strncpy(title, line+1, sizeof(title)-1);
31812111Sralph 			continue;
31912111Sralph 
32012111Sralph 		case 'L':	/* identification line */
321*18127Sralph 			if (!SH && !HL)
32212111Sralph 				banner(line+1, jobname);
32312111Sralph 			continue;
32412111Sralph 
32512111Sralph 		case '1':	/* troff fonts */
32612111Sralph 		case '2':
32712111Sralph 		case '3':
32812111Sralph 		case '4':
32912111Sralph 			if (line[1] != '\0')
33012111Sralph 				strcpy(fonts[line[0]-'1'], line+1);
33112111Sralph 			continue;
33212111Sralph 
33312111Sralph 		case 'W':	/* page width */
33415552Sralph 			strncpy(width+2, line+1, sizeof(width)-3);
33512111Sralph 			continue;
33612111Sralph 
33712581Sralph 		case 'I':	/* indent amount */
33815552Sralph 			strncpy(indent+2, line+1, sizeof(indent)-3);
33912581Sralph 			continue;
34012581Sralph 
34112111Sralph 		default:	/* some file to print */
34215811Sralph 			switch (i = print(line[0], line+1)) {
34317463Sralph 			case ERROR:
34417463Sralph 				if (bombed == OK)
34517463Sralph 					bombed = FATALERR;
34615811Sralph 				break;
34717463Sralph 			case REPRINT:
34812111Sralph 				(void) fclose(cfp);
34917463Sralph 				return(REPRINT);
35017463Sralph 			case FILTERERR:
35117463Sralph 			case ACCESS:
35217463Sralph 				bombed = i;
35315811Sralph 				sendmail(logname, bombed);
35415811Sralph 			}
35512111Sralph 			title[0] = '\0';
35612111Sralph 			continue;
35712111Sralph 
35812111Sralph 		case 'N':
35912111Sralph 		case 'U':
36012111Sralph 		case 'M':
36112111Sralph 			continue;
36212111Sralph 		}
36312111Sralph 
36412111Sralph 	/* pass 2 */
36512111Sralph 
36612463Sralph pass2:
36712111Sralph 	fseek(cfp, 0L, 0);
36812111Sralph 	while (getline(cfp))
36912111Sralph 		switch (line[0]) {
370*18127Sralph 		case 'L':	/* identification line */
371*18127Sralph 			if (!SH && HL)
372*18127Sralph 				banner(line+1, jobname);
373*18127Sralph 			continue;
374*18127Sralph 
37512111Sralph 		case 'M':
37617463Sralph 			if (bombed < NOACCT)	/* already sent if >= NOACCT */
37715811Sralph 				sendmail(line+1, bombed);
37812111Sralph 			continue;
37912111Sralph 
38012111Sralph 		case 'U':
38112111Sralph 			(void) unlink(line+1);
38212111Sralph 		}
38312111Sralph 	/*
38415811Sralph 	 * clean-up in case another control file exists
38512111Sralph 	 */
38612111Sralph 	(void) fclose(cfp);
38712111Sralph 	(void) unlink(file);
38817463Sralph 	return(bombed == OK ? OK : ERROR);
38912111Sralph }
39012111Sralph 
39112111Sralph /*
39212111Sralph  * Print a file.
39313233Sralph  * Set up the chain [ PR [ | {IF, OF} ] ] or {IF, RF, TF, NF, DF, CF, VF}.
39415811Sralph  * Return -1 if a non-recoverable error occured,
39515811Sralph  * 2 if the filter detected some errors (but printed the job anyway),
39615811Sralph  * 1 if we should try to reprint this job and
39712111Sralph  * 0 if all is well.
39812111Sralph  * Note: all filters take stdin as the file, stdout as the printer,
39912111Sralph  * stderr as the log file, and must not ignore SIGINT.
40012111Sralph  */
40112111Sralph print(format, file)
40212111Sralph 	int format;
40312111Sralph 	char *file;
40412111Sralph {
40515811Sralph 	register int n;
40612111Sralph 	register char *prog;
40715811Sralph 	int fi, fo;
40812111Sralph 	char *av[15], buf[BUFSIZ];
40912111Sralph 	int pid, p[2], stopped = 0;
41012111Sralph 	union wait status;
41117463Sralph 	struct stat stb;
41212111Sralph 
41317463Sralph 	if (lstat(file, &stb) < 0 || (fi = open(file, O_RDONLY)) < 0)
41417463Sralph 		return(ERROR);
41517463Sralph 	/*
41617463Sralph 	 * Check to see if data file is a symbolic link. If so, it should
41717463Sralph 	 * still point to the same file or someone is trying to print
41817463Sralph 	 * something he shouldn't.
41917463Sralph 	 */
42017463Sralph 	if ((stb.st_mode & S_IFMT) == S_IFLNK && fstat(fi, &stb) == 0 &&
42117463Sralph 	    (stb.st_dev != fdev || stb.st_ino != fino))
42217463Sralph 		return(ACCESS);
42312111Sralph 	if (!SF && !tof) {		/* start on a fresh page */
42412111Sralph 		(void) write(ofd, FF, strlen(FF));
42512111Sralph 		tof = 1;
42612111Sralph 	}
42712111Sralph 	if (IF == NULL && (format == 'f' || format == 'l')) {
42812111Sralph 		tof = 0;
42912111Sralph 		while ((n = read(fi, buf, BUFSIZ)) > 0)
43012111Sralph 			if (write(ofd, buf, n) != n) {
43112111Sralph 				(void) close(fi);
43217463Sralph 				return(REPRINT);
43312111Sralph 			}
43412111Sralph 		(void) close(fi);
43517463Sralph 		return(OK);
43612111Sralph 	}
43712111Sralph 	switch (format) {
43812111Sralph 	case 'p':	/* print file using 'pr' */
43912111Sralph 		if (IF == NULL) {	/* use output filter */
44012111Sralph 			prog = PR;
44112111Sralph 			av[0] = "pr";
44212111Sralph 			av[1] = width;
44312111Sralph 			av[2] = length;
44412111Sralph 			av[3] = "-h";
44512111Sralph 			av[4] = *title ? title : " ";
44612111Sralph 			av[5] = 0;
44712111Sralph 			fo = ofd;
44812111Sralph 			goto start;
44912111Sralph 		}
45012111Sralph 		pipe(p);
45112111Sralph 		if ((prchild = dofork(DORETURN)) == 0) {	/* child */
45212111Sralph 			dup2(fi, 0);		/* file is stdin */
45312111Sralph 			dup2(p[1], 1);		/* pipe is stdout */
45412111Sralph 			for (n = 3; n < NOFILE; n++)
45512111Sralph 				(void) close(n);
45612111Sralph 			execl(PR, "pr", width, length, "-h", *title ? title : " ", 0);
45716762Sralph 			syslog(LOG_ERR, "cannot execl %s", PR);
45812111Sralph 			exit(2);
45912111Sralph 		}
46012111Sralph 		(void) close(p[1]);		/* close output side */
46112111Sralph 		(void) close(fi);
46212111Sralph 		if (prchild < 0) {
46312111Sralph 			prchild = 0;
46412111Sralph 			(void) close(p[0]);
46517463Sralph 			return(ERROR);
46612111Sralph 		}
46712111Sralph 		fi = p[0];			/* use pipe for input */
46812111Sralph 	case 'f':	/* print plain text file */
46912111Sralph 		prog = IF;
47012111Sralph 		av[1] = width;
47112111Sralph 		av[2] = length;
47212581Sralph 		av[3] = indent;
47312581Sralph 		n = 4;
47412111Sralph 		break;
47512111Sralph 	case 'l':	/* like 'f' but pass control characters */
47612111Sralph 		prog = IF;
47714325Sralph 		av[1] = "-c";
47812111Sralph 		av[2] = width;
47912111Sralph 		av[3] = length;
48012581Sralph 		av[4] = indent;
48112581Sralph 		n = 5;
48212111Sralph 		break;
48312463Sralph 	case 'r':	/* print a fortran text file */
48412463Sralph 		prog = RF;
48512463Sralph 		av[1] = width;
48612463Sralph 		av[2] = length;
48712463Sralph 		n = 3;
48812463Sralph 		break;
48912111Sralph 	case 't':	/* print troff output */
49013233Sralph 	case 'n':	/* print ditroff output */
49112463Sralph 	case 'd':	/* print tex output */
49212111Sralph 		(void) unlink(".railmag");
49312463Sralph 		if ((fo = creat(".railmag", FILMOD)) < 0) {
49416762Sralph 			syslog(LOG_ERR, "%s: cannot create .railmag", printer);
49512111Sralph 			(void) unlink(".railmag");
49612111Sralph 		} else {
49712111Sralph 			for (n = 0; n < 4; n++) {
49812111Sralph 				if (fonts[n][0] != '/')
49912111Sralph 					(void) write(fo, "/usr/lib/vfont/", 15);
50012111Sralph 				(void) write(fo, fonts[n], strlen(fonts[n]));
50112111Sralph 				(void) write(fo, "\n", 1);
50212111Sralph 			}
50312111Sralph 			(void) close(fo);
50412111Sralph 		}
50513233Sralph 		prog = (format == 't') ? TF : (format == 'n') ? NF : DF;
50612463Sralph 		av[1] = pxwidth;
50712463Sralph 		av[2] = pxlength;
50812463Sralph 		n = 3;
50912111Sralph 		break;
51012111Sralph 	case 'c':	/* print cifplot output */
51112111Sralph 		prog = CF;
51212463Sralph 		av[1] = pxwidth;
51312463Sralph 		av[2] = pxlength;
51412463Sralph 		n = 3;
51512111Sralph 		break;
51612111Sralph 	case 'g':	/* print plot(1G) output */
51712111Sralph 		prog = GF;
51812463Sralph 		av[1] = pxwidth;
51912463Sralph 		av[2] = pxlength;
52012463Sralph 		n = 3;
52112111Sralph 		break;
52212111Sralph 	case 'v':	/* print raster output */
52312111Sralph 		prog = VF;
52412463Sralph 		av[1] = pxwidth;
52512463Sralph 		av[2] = pxlength;
52612463Sralph 		n = 3;
52712111Sralph 		break;
52812111Sralph 	default:
52912111Sralph 		(void) close(fi);
53016762Sralph 		syslog(LOG_ERR, "%s: illegal format character '%c'",
53116762Sralph 			printer, format);
53217463Sralph 		return(ERROR);
53312111Sralph 	}
53412111Sralph 	if ((av[0] = rindex(prog, '/')) != NULL)
53512111Sralph 		av[0]++;
53612111Sralph 	else
53712111Sralph 		av[0] = prog;
53812111Sralph 	av[n++] = "-n";
53912111Sralph 	av[n++] = logname;
54012111Sralph 	av[n++] = "-h";
54114150Sralph 	av[n++] = fromhost;
54212111Sralph 	av[n++] = AF;
54312111Sralph 	av[n] = 0;
54412111Sralph 	fo = pfd;
54512111Sralph 	if (ofilter > 0) {		/* stop output filter */
54612111Sralph 		write(ofd, "\031\1", 2);
54712111Sralph 		while ((pid = wait3(&status, WUNTRACED, 0)) > 0 && pid != ofilter)
54812111Sralph 			;
54912111Sralph 		if (status.w_stopval != WSTOPPED) {
55012111Sralph 			(void) close(fi);
55116762Sralph 			syslog(LOG_WARNING, "%s: output filter died (%d)",
55216762Sralph 				printer, status.w_retcode);
55317463Sralph 			return(REPRINT);
55412111Sralph 		}
55512111Sralph 		stopped++;
55612111Sralph 	}
55712111Sralph start:
55812111Sralph 	if ((child = dofork(DORETURN)) == 0) {	/* child */
55912111Sralph 		dup2(fi, 0);
56012111Sralph 		dup2(fo, 1);
56117304Sralph 		n = open(tmpfile, O_WRONLY|O_CREAT|O_TRUNC, 0664);
56215811Sralph 		if (n >= 0)
56315811Sralph 			dup2(n, 2);
56412111Sralph 		for (n = 3; n < NOFILE; n++)
56512111Sralph 			(void) close(n);
56612111Sralph 		execv(prog, av);
56716762Sralph 		syslog(LOG_ERR, "cannot execv %s", prog);
56812111Sralph 		exit(2);
56912111Sralph 	}
57012111Sralph 	(void) close(fi);
57112111Sralph 	if (child < 0)
57212111Sralph 		status.w_retcode = 100;
57312111Sralph 	else
57412111Sralph 		while ((pid = wait(&status)) > 0 && pid != child)
57512111Sralph 			;
57612111Sralph 	child = 0;
57712111Sralph 	prchild = 0;
57812111Sralph 	if (stopped) {		/* restart output filter */
57912111Sralph 		if (kill(ofilter, SIGCONT) < 0) {
58016762Sralph 			syslog(LOG_ERR, "cannot restart output filter");
58112111Sralph 			exit(1);
58212111Sralph 		}
58312111Sralph 	}
58412111Sralph 	tof = 0;
58515811Sralph 	if (!WIFEXITED(status)) {
58616762Sralph 		syslog(LOG_WARNING, "%s: Daemon filter '%c' terminated (%d)",
58716762Sralph 			printer, format, status.w_termsig);
58817463Sralph 		return(ERROR);
58917463Sralph 	}
59017463Sralph 	switch (status.w_retcode) {
59117463Sralph 	case 0:
59217463Sralph 		tof = 1;
59317463Sralph 		return(OK);
59417463Sralph 	case 1:
59517463Sralph 		return(REPRINT);
59617463Sralph 	default:
59716762Sralph 		syslog(LOG_WARNING, "%s: Daemon filter '%c' exited (%d)",
59816762Sralph 			printer, format, status.w_retcode);
59917463Sralph 	case 2:
60017463Sralph 		return(ERROR);
60117463Sralph 	}
60212111Sralph }
60312111Sralph 
60412111Sralph /*
60512111Sralph  * Send the daemon control file (cf) and any data files.
60612111Sralph  * Return -1 if a non-recoverable error occured, 1 if a recoverable error and
60712111Sralph  * 0 if all is well.
60812111Sralph  */
60912111Sralph sendit(file)
61012111Sralph 	char *file;
61112111Sralph {
61217463Sralph 	register int i, err = OK;
61317463Sralph 	char *cp, last[BUFSIZ];
61412111Sralph 
61512111Sralph 	/*
61612111Sralph 	 * open control file
61712111Sralph 	 */
61816762Sralph 	if ((cfp = fopen(file, "r")) == NULL)
61917463Sralph 		return(OK);
62012111Sralph 	/*
62112111Sralph 	 *      read the control file for work to do
62212111Sralph 	 *
62312111Sralph 	 *      file format -- first character in the line is a command
62412111Sralph 	 *      rest of the line is the argument.
62512111Sralph 	 *      commands of interest are:
62612111Sralph 	 *
62712111Sralph 	 *            a-z -- "file name" name of file to print
62812111Sralph 	 *              U -- "unlink" name of file to remove
62912111Sralph 	 *                    (after we print it. (Pass 2 only)).
63012111Sralph 	 */
63112111Sralph 
63212111Sralph 	/*
63312111Sralph 	 * pass 1
63412111Sralph 	 */
63512111Sralph 	while (getline(cfp)) {
63612111Sralph 	again:
63717463Sralph 		if (line[0] == 'S') {
63817463Sralph 			cp = line+1;
63917463Sralph 			i = 0;
64017463Sralph 			while (*cp >= '0' && *cp <= '9')
64117463Sralph 				i = i * 10 + (*cp++ - '0');
64217463Sralph 			fdev = i;
64317463Sralph 			cp++;
64417463Sralph 			i = 0;
64517463Sralph 			while (*cp >= '0' && *cp <= '9')
64617463Sralph 				i = i * 10 + (*cp++ - '0');
64717463Sralph 			fino = i;
64817463Sralph 			continue;
64917463Sralph 		}
65012111Sralph 		if (line[0] >= 'a' && line[0] <= 'z') {
65112111Sralph 			strcpy(last, line);
65217463Sralph 			while (i = getline(cfp))
65312111Sralph 				if (strcmp(last, line))
65412111Sralph 					break;
65517463Sralph 			switch (sendfile('\3', last+1)) {
65617463Sralph 			case OK:
65717463Sralph 				if (i)
65817463Sralph 					goto again;
65917463Sralph 				break;
66017463Sralph 			case REPRINT:
66112111Sralph 				(void) fclose(cfp);
66217463Sralph 				return(REPRINT);
66317463Sralph 			case ACCESS:
66417463Sralph 				sendmail(logname, ACCESS);
66517463Sralph 			case ERROR:
66617463Sralph 				err = ERROR;
66717463Sralph 			}
66812111Sralph 			break;
66912111Sralph 		}
67012111Sralph 	}
67117463Sralph 	if (err == OK && sendfile('\2', file) > 0) {
67212111Sralph 		(void) fclose(cfp);
67317463Sralph 		return(REPRINT);
67412111Sralph 	}
67512111Sralph 	/*
67612111Sralph 	 * pass 2
67712111Sralph 	 */
67812111Sralph 	fseek(cfp, 0L, 0);
67912111Sralph 	while (getline(cfp))
68012111Sralph 		if (line[0] == 'U')
68112111Sralph 			(void) unlink(line+1);
68212111Sralph 	/*
68317463Sralph 	 * clean-up in case another control file exists
68412111Sralph 	 */
68512111Sralph 	(void) fclose(cfp);
68612111Sralph 	(void) unlink(file);
68717463Sralph 	return(err);
68812111Sralph }
68912111Sralph 
69012111Sralph /*
69112111Sralph  * Send a data file to the remote machine and spool it.
69212111Sralph  * Return positive if we should try resending.
69312111Sralph  */
69412111Sralph sendfile(type, file)
69512111Sralph 	char type, *file;
69612111Sralph {
69712111Sralph 	register int f, i, amt;
69812111Sralph 	struct stat stb;
69912111Sralph 	char buf[BUFSIZ];
70016762Sralph 	int sizerr, resp;
70112111Sralph 
70217463Sralph 	if (lstat(file, &stb) < 0 || (f = open(file, O_RDONLY)) < 0)
70317463Sralph 		return(ERROR);
70417463Sralph 	/*
70517463Sralph 	 * Check to see if data file is a symbolic link. If so, it should
70617463Sralph 	 * still point to the same file or someone is trying to print something
70717463Sralph 	 * he shouldn't.
70817463Sralph 	 */
70917463Sralph 	if ((stb.st_mode & S_IFMT) == S_IFLNK && fstat(f, &stb) == 0 &&
71017463Sralph 	    (stb.st_dev != fdev || stb.st_ino != fino))
71117463Sralph 		return(ACCESS);
71212111Sralph 	(void) sprintf(buf, "%c%d %s\n", type, stb.st_size, file);
71312111Sralph 	amt = strlen(buf);
71416762Sralph 	for (i = 0;  ; i++) {
71516762Sralph 		if (write(pfd, buf, amt) != amt ||
71616762Sralph 		    (resp = response()) < 0 || resp == '\1') {
71716762Sralph 			(void) close(f);
71817463Sralph 			return(REPRINT);
71916762Sralph 		} else if (resp == '\0')
72016762Sralph 			break;
72116762Sralph 		if (i == 0)
72216762Sralph 			status("no space on remote; waiting for queue to drain");
72316762Sralph 		if (i == 10)
72416762Sralph 			syslog(LOG_SALERT, "%s: can't send to %s; queue full",
72516762Sralph 				printer, RM);
72616762Sralph 		sleep(5 * 60);
72712692Sralph 	}
72816762Sralph 	if (i)
72916762Sralph 		status("sending to %s", RM);
73012111Sralph 	sizerr = 0;
73112111Sralph 	for (i = 0; i < stb.st_size; i += BUFSIZ) {
73212111Sralph 		amt = BUFSIZ;
73312111Sralph 		if (i + amt > stb.st_size)
73412111Sralph 			amt = stb.st_size - i;
73512111Sralph 		if (sizerr == 0 && read(f, buf, amt) != amt)
73612111Sralph 			sizerr = 1;
73712692Sralph 		if (write(pfd, buf, amt) != amt) {
73812692Sralph 			(void) close(f);
73917463Sralph 			return(REPRINT);
74012692Sralph 		}
74112111Sralph 	}
74212111Sralph 	(void) close(f);
74312111Sralph 	if (sizerr) {
74416762Sralph 		syslog(LOG_INFO, "%s: %s: changed size", printer, file);
74517463Sralph 		/* tell recvjob to ignore this file */
74617463Sralph 		(void) write(pfd, "\1", 1);
74717463Sralph 		return(ERROR);
74817463Sralph 	}
74917463Sralph 	if (write(pfd, "", 1) != 1 || response())
75017463Sralph 		return(REPRINT);
75117463Sralph 	return(OK);
75212111Sralph }
75312111Sralph 
75412111Sralph /*
75512111Sralph  * Check to make sure there have been no errors and that both programs
75612111Sralph  * are in sync with eachother.
75712111Sralph  * Return non-zero if the connection was lost.
75812111Sralph  */
75916762Sralph response()
76012111Sralph {
76112111Sralph 	char resp;
76212111Sralph 
76316762Sralph 	if (read(pfd, &resp, 1) != 1) {
76416762Sralph 		syslog(LOG_INFO, "%s: lost connection", printer);
76516762Sralph 		return(-1);
76612111Sralph 	}
76716762Sralph 	return(resp);
76812111Sralph }
76912111Sralph 
77012111Sralph /*
77112111Sralph  * Banner printing stuff
77212111Sralph  */
77312111Sralph banner(name1, name2)
77412111Sralph 	char *name1, *name2;
77512111Sralph {
77612111Sralph 	time_t tvec;
77712111Sralph 	extern char *ctime();
77812111Sralph 
77912111Sralph 	time(&tvec);
78012111Sralph 	if (!SF && !tof)
78112111Sralph 		(void) write(ofd, FF, strlen(FF));
78212111Sralph 	if (SB) {	/* short banner only */
78312111Sralph 		if (class[0]) {
78412111Sralph 			(void) write(ofd, class, strlen(class));
78512111Sralph 			(void) write(ofd, ":", 1);
78612111Sralph 		}
78712111Sralph 		(void) write(ofd, name1, strlen(name1));
78812111Sralph 		(void) write(ofd, "  Job: ", 7);
78912111Sralph 		(void) write(ofd, name2, strlen(name2));
79012111Sralph 		(void) write(ofd, "  Date: ", 8);
79112111Sralph 		(void) write(ofd, ctime(&tvec), 24);
79212111Sralph 		(void) write(ofd, "\n", 1);
79312111Sralph 	} else {	/* normal banner */
79412111Sralph 		(void) write(ofd, "\n\n\n", 3);
79512111Sralph 		scan_out(ofd, name1, '\0');
79612111Sralph 		(void) write(ofd, "\n\n", 2);
79712111Sralph 		scan_out(ofd, name2, '\0');
79812111Sralph 		if (class[0]) {
79912111Sralph 			(void) write(ofd,"\n\n\n",3);
80012111Sralph 			scan_out(ofd, class, '\0');
80112111Sralph 		}
80212111Sralph 		(void) write(ofd, "\n\n\n\n\t\t\t\t\tJob:  ", 15);
80312111Sralph 		(void) write(ofd, name2, strlen(name2));
80412111Sralph 		(void) write(ofd, "\n\t\t\t\t\tDate: ", 12);
80512111Sralph 		(void) write(ofd, ctime(&tvec), 24);
80612111Sralph 		(void) write(ofd, "\n", 1);
80712111Sralph 	}
80812111Sralph 	if (!SF)
80912111Sralph 		(void) write(ofd, FF, strlen(FF));
81012111Sralph 	tof = 1;
81112111Sralph }
81212111Sralph 
81316762Sralph char *
81412111Sralph scnline(key, p, c)
81512111Sralph 	register char key, *p;
81612111Sralph 	char c;
81712111Sralph {
81812111Sralph 	register scnwidth;
81912111Sralph 
82012111Sralph 	for (scnwidth = WIDTH; --scnwidth;) {
82112111Sralph 		key <<= 1;
82212111Sralph 		*p++ = key & 0200 ? c : BACKGND;
82312111Sralph 	}
82412111Sralph 	return (p);
82512111Sralph }
82612111Sralph 
82712111Sralph #define TRC(q)	(((q)-' ')&0177)
82812111Sralph 
82912111Sralph scan_out(scfd, scsp, dlm)
83012111Sralph 	int scfd;
83112111Sralph 	char *scsp, dlm;
83212111Sralph {
83312111Sralph 	register char *strp;
83412111Sralph 	register nchrs, j;
83512111Sralph 	char outbuf[LINELEN+1], *sp, c, cc;
83612111Sralph 	int d, scnhgt;
83712111Sralph 	extern char scnkey[][HEIGHT];	/* in lpdchar.c */
83812111Sralph 
83912111Sralph 	for (scnhgt = 0; scnhgt++ < HEIGHT+DROP; ) {
84012111Sralph 		strp = &outbuf[0];
84112111Sralph 		sp = scsp;
84212111Sralph 		for (nchrs = 0; ; ) {
84312111Sralph 			d = dropit(c = TRC(cc = *sp++));
84412111Sralph 			if ((!d && scnhgt > HEIGHT) || (scnhgt <= DROP && d))
84512111Sralph 				for (j = WIDTH; --j;)
84612111Sralph 					*strp++ = BACKGND;
84712111Sralph 			else
84812111Sralph 				strp = scnline(scnkey[c][scnhgt-1-d], strp, cc);
84912111Sralph 			if (*sp == dlm || *sp == '\0' || nchrs++ >= PW/(WIDTH+1)-1)
85012111Sralph 				break;
85112111Sralph 			*strp++ = BACKGND;
85212111Sralph 			*strp++ = BACKGND;
85312111Sralph 		}
85412111Sralph 		while (*--strp == BACKGND && strp >= outbuf)
85512111Sralph 			;
85612111Sralph 		strp++;
85712111Sralph 		*strp++ = '\n';
85812111Sralph 		(void) write(scfd, outbuf, strp-outbuf);
85912111Sralph 	}
86012111Sralph }
86112111Sralph 
86212111Sralph dropit(c)
86312111Sralph 	char c;
86412111Sralph {
86512111Sralph 	switch(c) {
86612111Sralph 
86712111Sralph 	case TRC('_'):
86812111Sralph 	case TRC(';'):
86912111Sralph 	case TRC(','):
87012111Sralph 	case TRC('g'):
87112111Sralph 	case TRC('j'):
87212111Sralph 	case TRC('p'):
87312111Sralph 	case TRC('q'):
87412111Sralph 	case TRC('y'):
87512111Sralph 		return (DROP);
87612111Sralph 
87712111Sralph 	default:
87812111Sralph 		return (0);
87912111Sralph 	}
88012111Sralph }
88112111Sralph 
88212111Sralph /*
88312111Sralph  * sendmail ---
88412111Sralph  *   tell people about job completion
88512111Sralph  */
88615811Sralph sendmail(user, bombed)
88715811Sralph 	char *user;
88812111Sralph 	int bombed;
88912111Sralph {
89012111Sralph 	register int i;
89115811Sralph 	int p[2], s;
89212111Sralph 	register char *cp;
89312111Sralph 	char buf[100];
89415811Sralph 	struct stat stb;
89515811Sralph 	FILE *fp;
89612111Sralph 
89712111Sralph 	pipe(p);
89815811Sralph 	if ((s = dofork(DORETURN)) == 0) {		/* child */
89912111Sralph 		dup2(p[0], 0);
90012111Sralph 		for (i = 3; i < NOFILE; i++)
90112111Sralph 			(void) close(i);
90212111Sralph 		if ((cp = rindex(MAIL, '/')) != NULL)
90312111Sralph 			cp++;
90412111Sralph 		else
90512111Sralph 			cp = MAIL;
90615811Sralph 		sprintf(buf, "%s@%s", user, fromhost);
90712111Sralph 		execl(MAIL, cp, buf, 0);
90812111Sralph 		exit(0);
90915811Sralph 	} else if (s > 0) {				/* parent */
91012111Sralph 		dup2(p[1], 1);
91115811Sralph 		printf("To: %s@%s\n", user, fromhost);
91212111Sralph 		printf("Subject: printer job\n\n");
91312111Sralph 		printf("Your printer job ");
91412111Sralph 		if (*jobname)
91512111Sralph 			printf("(%s) ", jobname);
91612463Sralph 		switch (bombed) {
91717463Sralph 		case OK:
91812463Sralph 			printf("\ncompleted successfully\n");
91912463Sralph 			break;
92012463Sralph 		default:
92117463Sralph 		case FATALERR:
92212463Sralph 			printf("\ncould not be printed\n");
92312463Sralph 			break;
92417463Sralph 		case NOACCT:
92512463Sralph 			printf("\ncould not be printed without an account on %s\n", host);
92612463Sralph 			break;
92717463Sralph 		case FILTERERR:
92815811Sralph 			if (stat(tmpfile, &stb) < 0 || stb.st_size == 0 ||
92915811Sralph 			    (fp = fopen(tmpfile, "r")) == NULL) {
93015811Sralph 				printf("\nwas printed but had some errors\n");
93115811Sralph 				break;
93215811Sralph 			}
93315811Sralph 			printf("\nwas printed but had the following errors:\n");
93415811Sralph 			while ((i = getc(fp)) != EOF)
93515811Sralph 				putchar(i);
93615811Sralph 			(void) fclose(fp);
93717463Sralph 			break;
93817463Sralph 		case ACCESS:
93917463Sralph 			printf("\nwas not printed because it was not linked to the original file\n");
94012463Sralph 		}
94112111Sralph 		fflush(stdout);
94212111Sralph 		(void) close(1);
94312111Sralph 	}
94412111Sralph 	(void) close(p[0]);
94512111Sralph 	(void) close(p[1]);
94615811Sralph 	wait(&s);
94712111Sralph }
94812111Sralph 
94912111Sralph /*
95012111Sralph  * dofork - fork with retries on failure
95112111Sralph  */
95212111Sralph dofork(action)
95312111Sralph 	int action;
95412111Sralph {
95512111Sralph 	register int i, pid;
95612111Sralph 
95712111Sralph 	for (i = 0; i < 20; i++) {
95812463Sralph 		if ((pid = fork()) < 0) {
95912111Sralph 			sleep((unsigned)(i*i));
96012463Sralph 			continue;
96112463Sralph 		}
96212463Sralph 		/*
96312463Sralph 		 * Child should run as daemon instead of root
96412463Sralph 		 */
96512463Sralph 		if (pid == 0)
96612463Sralph 			setuid(DU);
96712463Sralph 		return(pid);
96812111Sralph 	}
96916762Sralph 	syslog(LOG_ERR, "can't fork");
97012111Sralph 
97112111Sralph 	switch (action) {
97212111Sralph 	case DORETURN:
97312111Sralph 		return (-1);
97412111Sralph 	default:
97516762Sralph 		syslog(LOG_ERR, "bad action (%d) to dofork", action);
97612111Sralph 		/*FALL THRU*/
97712111Sralph 	case DOABORT:
97812111Sralph 		exit(1);
97912111Sralph 	}
98012111Sralph 	/*NOTREACHED*/
98112111Sralph }
98212111Sralph 
98312111Sralph /*
98416762Sralph  * Kill child processes to abort current job.
98512111Sralph  */
98616762Sralph abortpr()
98712111Sralph {
98815811Sralph 	(void) unlink(tmpfile);
98912111Sralph 	kill(0, SIGINT);
99012111Sralph 	if (ofilter > 0)
99112111Sralph 		kill(ofilter, SIGCONT);
99212111Sralph 	while (wait(0) > 0)
99312111Sralph 		;
99412111Sralph 	exit(0);
99512111Sralph }
99612111Sralph 
99712111Sralph init()
99812111Sralph {
99912111Sralph 	int status;
100012111Sralph 
100113169Sralph 	if ((status = pgetent(line, printer)) < 0)
100213169Sralph 		fatal("can't open printer description file");
100313169Sralph 	else if (status == 0)
100413169Sralph 		fatal("unknown printer");
100512111Sralph 	if ((LP = pgetstr("lp", &bp)) == NULL)
100612111Sralph 		LP = DEFDEVLP;
100712111Sralph 	if ((RP = pgetstr("rp", &bp)) == NULL)
100812463Sralph 		RP = DEFLP;
100912111Sralph 	if ((LO = pgetstr("lo", &bp)) == NULL)
101012111Sralph 		LO = DEFLOCK;
101112111Sralph 	if ((ST = pgetstr("st", &bp)) == NULL)
101212111Sralph 		ST = DEFSTAT;
101312111Sralph 	if ((LF = pgetstr("lf", &bp)) == NULL)
101412111Sralph 		LF = DEFLOGF;
101512111Sralph 	if ((SD = pgetstr("sd", &bp)) == NULL)
101612111Sralph 		SD = DEFSPOOL;
101712111Sralph 	if ((DU = pgetnum("du")) < 0)
101812111Sralph 		DU = DEFUID;
101912111Sralph 	if ((FF = pgetstr("ff", &bp)) == NULL)
102012111Sralph 		FF = DEFFF;
102112111Sralph 	if ((PW = pgetnum("pw")) < 0)
102212111Sralph 		PW = DEFWIDTH;
102312111Sralph 	sprintf(&width[2], "%d", PW);
102412111Sralph 	if ((PL = pgetnum("pl")) < 0)
102512111Sralph 		PL = DEFLENGTH;
102612111Sralph 	sprintf(&length[2], "%d", PL);
102712463Sralph 	if ((PX = pgetnum("px")) < 0)
102812463Sralph 		PX = 0;
102912463Sralph 	sprintf(&pxwidth[2], "%d", PX);
103012463Sralph 	if ((PY = pgetnum("py")) < 0)
103112463Sralph 		PY = 0;
103212463Sralph 	sprintf(&pxlength[2], "%d", PY);
103312111Sralph 	RM = pgetstr("rm", &bp);
103412111Sralph 	AF = pgetstr("af", &bp);
103512111Sralph 	OF = pgetstr("of", &bp);
103612111Sralph 	IF = pgetstr("if", &bp);
103712463Sralph 	RF = pgetstr("rf", &bp);
103812111Sralph 	TF = pgetstr("tf", &bp);
103913233Sralph 	NF = pgetstr("nf", &bp);
104012111Sralph 	DF = pgetstr("df", &bp);
104112111Sralph 	GF = pgetstr("gf", &bp);
104212111Sralph 	VF = pgetstr("vf", &bp);
104312111Sralph 	CF = pgetstr("cf", &bp);
104412111Sralph 	TR = pgetstr("tr", &bp);
104512463Sralph 	RS = pgetflag("rs");
104612111Sralph 	SF = pgetflag("sf");
104712111Sralph 	SH = pgetflag("sh");
104812111Sralph 	SB = pgetflag("sb");
1049*18127Sralph 	HL = pgetflag("hl");
105012111Sralph 	RW = pgetflag("rw");
105112111Sralph 	BR = pgetnum("br");
105212111Sralph 	if ((FC = pgetnum("fc")) < 0)
105312111Sralph 		FC = 0;
105412111Sralph 	if ((FS = pgetnum("fs")) < 0)
105512111Sralph 		FS = 0;
105612111Sralph 	if ((XC = pgetnum("xc")) < 0)
105712111Sralph 		XC = 0;
105812111Sralph 	if ((XS = pgetnum("xs")) < 0)
105912111Sralph 		XS = 0;
106012581Sralph 	tof = !pgetflag("fo");
106112111Sralph }
106212111Sralph 
106312463Sralph /*
106412463Sralph  * Acquire line printer or remote connection.
106512463Sralph  */
106612463Sralph openpr()
106712463Sralph {
106812463Sralph 	register int i, n;
106916762Sralph 	int resp;
107012463Sralph 
107112463Sralph 	if (*LP) {
107212463Sralph 		for (i = 1; ; i = i < 32 ? i << 1 : i) {
107313148Ssam 			pfd = open(LP, RW ? O_RDWR : O_WRONLY);
107412463Sralph 			if (pfd >= 0)
107512463Sralph 				break;
107612463Sralph 			if (errno == ENOENT) {
107716762Sralph 				syslog(LOG_ERR, "%s: %m", LP);
107812463Sralph 				exit(1);
107912463Sralph 			}
108012463Sralph 			if (i == 1)
108112463Sralph 				status("waiting for %s to become ready (offline ?)", printer);
108212463Sralph 			sleep(i);
108312463Sralph 		}
108412463Sralph 		if (isatty(pfd))
108512463Sralph 			setty();
108612463Sralph 		status("%s is ready and printing", printer);
108712463Sralph 	} else if (RM != NULL) {
108816762Sralph 		for (i = 1; ; i = i < 256 ? i << 1 : i) {
108916762Sralph 			resp = -1;
109012528Sralph 			pfd = getport(RM);
109112463Sralph 			if (pfd >= 0) {
109212463Sralph 				(void) sprintf(line, "\2%s\n", RP);
109312463Sralph 				n = strlen(line);
109416762Sralph 				if (write(pfd, line, n) == n &&
109516762Sralph 				    (resp = response()) == '\0')
109612463Sralph 					break;
109716031Sralph 				(void) close(pfd);
109812463Sralph 			}
109916031Sralph 			if (i == 1) {
110016762Sralph 				if (resp < 0)
110116031Sralph 					status("waiting for %s to come up", RM);
110216762Sralph 				else {
110316031Sralph 					status("waiting for queue to be enabled on %s", RM);
110416762Sralph 					i = 256;
110516762Sralph 				}
110616031Sralph 			}
110712463Sralph 			sleep(i);
110812463Sralph 		}
110912463Sralph 		status("sending to %s", RM);
111012463Sralph 		remote = 1;
111112463Sralph 	} else {
111216762Sralph 		syslog(LOG_ERR, "%s: no line printer device or host name",
111316762Sralph 			printer);
111412463Sralph 		exit(1);
111512463Sralph 	}
111612463Sralph 	/*
111712463Sralph 	 * Start up an output filter, if needed.
111812463Sralph 	 */
111912463Sralph 	if (OF) {
112012463Sralph 		int p[2];
112112463Sralph 		char *cp;
112212463Sralph 
112312463Sralph 		pipe(p);
112412463Sralph 		if ((ofilter = dofork(DOABORT)) == 0) {	/* child */
112512463Sralph 			dup2(p[0], 0);		/* pipe is std in */
112612463Sralph 			dup2(pfd, 1);		/* printer is std out */
112712463Sralph 			for (i = 3; i < NOFILE; i++)
112812463Sralph 				(void) close(i);
112912463Sralph 			if ((cp = rindex(OF, '/')) == NULL)
113012463Sralph 				cp = OF;
113112463Sralph 			else
113212463Sralph 				cp++;
113312463Sralph 			execl(OF, cp, width, length, 0);
113416762Sralph 			syslog(LOG_ERR, "%s: %s: %m", printer, OF);
113512463Sralph 			exit(1);
113612463Sralph 		}
113712463Sralph 		(void) close(p[0]);		/* close input side */
113812463Sralph 		ofd = p[1];			/* use pipe for output */
113912463Sralph 	} else {
114012463Sralph 		ofd = pfd;
114112463Sralph 		ofilter = 0;
114212463Sralph 	}
114312463Sralph }
114412463Sralph 
114512111Sralph struct bauds {
114612111Sralph 	int	baud;
114712111Sralph 	int	speed;
114812111Sralph } bauds[] = {
114912111Sralph 	50,	B50,
115012111Sralph 	75,	B75,
115112111Sralph 	110,	B110,
115212111Sralph 	134,	B134,
115312111Sralph 	150,	B150,
115412111Sralph 	200,	B200,
115512111Sralph 	300,	B300,
115612111Sralph 	600,	B600,
115712111Sralph 	1200,	B1200,
115812111Sralph 	1800,	B1800,
115912111Sralph 	2400,	B2400,
116012111Sralph 	4800,	B4800,
116112111Sralph 	9600,	B9600,
116212111Sralph 	19200,	EXTA,
116312111Sralph 	38400,	EXTB,
116412111Sralph 	0,	0
116512111Sralph };
116612111Sralph 
116712111Sralph /*
116812111Sralph  * setup tty lines.
116912111Sralph  */
117012111Sralph setty()
117112111Sralph {
117212111Sralph 	struct sgttyb ttybuf;
117312111Sralph 	register struct bauds *bp;
117412111Sralph 
117512111Sralph 	if (ioctl(pfd, TIOCEXCL, (char *)0) < 0) {
117616762Sralph 		syslog(LOG_ERR, "%s: ioctl(TIOCEXCL): %m", printer);
117712111Sralph 		exit(1);
117812111Sralph 	}
117912111Sralph 	if (ioctl(pfd, TIOCGETP, (char *)&ttybuf) < 0) {
118016762Sralph 		syslog(LOG_ERR, "%s: ioctl(TIOCGETP): %m", printer);
118112111Sralph 		exit(1);
118212111Sralph 	}
118312111Sralph 	if (BR > 0) {
118412111Sralph 		for (bp = bauds; bp->baud; bp++)
118512111Sralph 			if (BR == bp->baud)
118612111Sralph 				break;
118712111Sralph 		if (!bp->baud) {
118816762Sralph 			syslog(LOG_ERR, "%s: illegal baud rate %d", printer, BR);
118912111Sralph 			exit(1);
119012111Sralph 		}
119112111Sralph 		ttybuf.sg_ispeed = ttybuf.sg_ospeed = bp->speed;
119212111Sralph 	}
119313169Sralph 	ttybuf.sg_flags &= ~FC;
119413169Sralph 	ttybuf.sg_flags |= FS;
119512111Sralph 	if (ioctl(pfd, TIOCSETP, (char *)&ttybuf) < 0) {
119616762Sralph 		syslog(LOG_ERR, "%s: ioctl(TIOCSETP): %m", printer);
119712111Sralph 		exit(1);
119812111Sralph 	}
119917168Sralph 	if (XC || XS) {
120017168Sralph 		int ldisc = NTTYDISC;
120117168Sralph 
120217168Sralph 		if (ioctl(pfd, TIOCSETD, &ldisc) < 0) {
120317168Sralph 			syslog(LOG_ERR, "%s: ioctl(TIOCSETD): %m", printer);
120417168Sralph 			exit(1);
120517168Sralph 		}
120617168Sralph 	}
120712111Sralph 	if (XC) {
120812111Sralph 		if (ioctl(pfd, TIOCLBIC, &XC) < 0) {
120916762Sralph 			syslog(LOG_ERR, "%s: ioctl(TIOCLBIC): %m", printer);
121012111Sralph 			exit(1);
121112111Sralph 		}
121212111Sralph 	}
121312111Sralph 	if (XS) {
121412111Sralph 		if (ioctl(pfd, TIOCLBIS, &XS) < 0) {
121516762Sralph 			syslog(LOG_ERR, "%s: ioctl(TIOCLBIS): %m", printer);
121612111Sralph 			exit(1);
121712111Sralph 		}
121812111Sralph 	}
121912111Sralph }
122012463Sralph 
122112463Sralph /*VARARGS1*/
122212463Sralph status(msg, a1, a2, a3)
122312463Sralph 	char *msg;
122412463Sralph {
122512463Sralph 	register int fd;
122612463Sralph 	char buf[BUFSIZ];
122712463Sralph 
122812463Sralph 	umask(0);
122913148Ssam 	fd = open(ST, O_WRONLY|O_CREAT, 0664);
123016762Sralph 	if (fd < 0 || flock(fd, LOCK_EX) < 0) {
123116762Sralph 		syslog(LOG_ERR, "%s: %s: %m", printer, ST);
123216762Sralph 		exit(1);
123316762Sralph 	}
123413148Ssam 	ftruncate(fd, 0);
123512463Sralph 	sprintf(buf, msg, a1, a2, a3);
123612463Sralph 	strcat(buf, "\n");
123712463Sralph 	(void) write(fd, buf, strlen(buf));
123812463Sralph 	(void) close(fd);
123912463Sralph }
1240