xref: /csrg-svn/usr.sbin/lpr/lpd/printjob.c (revision 17463)
113954Ssam #ifndef lint
2*17463Sralph static char sccsid[] = "@(#)printjob.c	4.23 (Berkeley) 12/05/84";
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 
17*17463Sralph /*
18*17463Sralph  * Error tokens
19*17463Sralph  */
20*17463Sralph #define REPRINT		-2
21*17463Sralph #define ERROR		-1
22*17463Sralph #define	OK		0
23*17463Sralph #define	FATALERR	1
24*17463Sralph #define	NOACCT		2
25*17463Sralph #define	FILTERERR	3
26*17463Sralph #define	ACCESS		4
27*17463Sralph 
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 */
39*17463Sralph dev_t	fdev;			/* device of file pointed to by symlink */
40*17463Sralph 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 		}
157*17463Sralph 		if (i == OK)		/* file ok and printed */
15814150Sralph 			count++;
159*17463Sralph 		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;
214*17463Sralph 	char *cp;
215*17463Sralph 	int bombed = OK;
21612111Sralph 
21712111Sralph 	/*
218*17463Sralph 	 * 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);
222*17463Sralph 		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 	 *
239*17463Sralph 	 *		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) {
282*17463Sralph 					bombed = NOACCT;
28315811Sralph 					sendmail(line+1, bombed);
28412463Sralph 					goto pass2;
28512463Sralph 				}
28612463Sralph 			}
28712111Sralph 			continue;
28812111Sralph 
289*17463Sralph 		case 'S':
290*17463Sralph 			cp = line+1;
291*17463Sralph 			i = 0;
292*17463Sralph 			while (*cp >= '0' && *cp <= '9')
293*17463Sralph 				i = i * 10 + (*cp++ - '0');
294*17463Sralph 			fdev = i;
295*17463Sralph 			cp++;
296*17463Sralph 			i = 0;
297*17463Sralph 			while (*cp >= '0' && *cp <= '9')
298*17463Sralph 				i = i * 10 + (*cp++ - '0');
299*17463Sralph 			fino = i;
300*17463Sralph 			continue;
301*17463Sralph 
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 */
32112111Sralph 			if (!SH)
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)) {
343*17463Sralph 			case ERROR:
344*17463Sralph 				if (bombed == OK)
345*17463Sralph 					bombed = FATALERR;
34615811Sralph 				break;
347*17463Sralph 			case REPRINT:
34812111Sralph 				(void) fclose(cfp);
349*17463Sralph 				return(REPRINT);
350*17463Sralph 			case FILTERERR:
351*17463Sralph 			case ACCESS:
352*17463Sralph 				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]) {
37012111Sralph 		case 'M':
371*17463Sralph 			if (bombed < NOACCT)	/* already sent if >= NOACCT */
37215811Sralph 				sendmail(line+1, bombed);
37312111Sralph 			continue;
37412111Sralph 
37512111Sralph 		case 'U':
37612111Sralph 			(void) unlink(line+1);
37712111Sralph 		}
37812111Sralph 	/*
37915811Sralph 	 * clean-up in case another control file exists
38012111Sralph 	 */
38112111Sralph 	(void) fclose(cfp);
38212111Sralph 	(void) unlink(file);
383*17463Sralph 	return(bombed == OK ? OK : ERROR);
38412111Sralph }
38512111Sralph 
38612111Sralph /*
38712111Sralph  * Print a file.
38813233Sralph  * Set up the chain [ PR [ | {IF, OF} ] ] or {IF, RF, TF, NF, DF, CF, VF}.
38915811Sralph  * Return -1 if a non-recoverable error occured,
39015811Sralph  * 2 if the filter detected some errors (but printed the job anyway),
39115811Sralph  * 1 if we should try to reprint this job and
39212111Sralph  * 0 if all is well.
39312111Sralph  * Note: all filters take stdin as the file, stdout as the printer,
39412111Sralph  * stderr as the log file, and must not ignore SIGINT.
39512111Sralph  */
39612111Sralph print(format, file)
39712111Sralph 	int format;
39812111Sralph 	char *file;
39912111Sralph {
40015811Sralph 	register int n;
40112111Sralph 	register char *prog;
40215811Sralph 	int fi, fo;
40312111Sralph 	char *av[15], buf[BUFSIZ];
40412111Sralph 	int pid, p[2], stopped = 0;
40512111Sralph 	union wait status;
406*17463Sralph 	struct stat stb;
40712111Sralph 
408*17463Sralph 	if (lstat(file, &stb) < 0 || (fi = open(file, O_RDONLY)) < 0)
409*17463Sralph 		return(ERROR);
410*17463Sralph 	/*
411*17463Sralph 	 * Check to see if data file is a symbolic link. If so, it should
412*17463Sralph 	 * still point to the same file or someone is trying to print
413*17463Sralph 	 * something he shouldn't.
414*17463Sralph 	 */
415*17463Sralph 	if ((stb.st_mode & S_IFMT) == S_IFLNK && fstat(fi, &stb) == 0 &&
416*17463Sralph 	    (stb.st_dev != fdev || stb.st_ino != fino))
417*17463Sralph 		return(ACCESS);
41812111Sralph 	if (!SF && !tof) {		/* start on a fresh page */
41912111Sralph 		(void) write(ofd, FF, strlen(FF));
42012111Sralph 		tof = 1;
42112111Sralph 	}
42212111Sralph 	if (IF == NULL && (format == 'f' || format == 'l')) {
42312111Sralph 		tof = 0;
42412111Sralph 		while ((n = read(fi, buf, BUFSIZ)) > 0)
42512111Sralph 			if (write(ofd, buf, n) != n) {
42612111Sralph 				(void) close(fi);
427*17463Sralph 				return(REPRINT);
42812111Sralph 			}
42912111Sralph 		(void) close(fi);
430*17463Sralph 		return(OK);
43112111Sralph 	}
43212111Sralph 	switch (format) {
43312111Sralph 	case 'p':	/* print file using 'pr' */
43412111Sralph 		if (IF == NULL) {	/* use output filter */
43512111Sralph 			prog = PR;
43612111Sralph 			av[0] = "pr";
43712111Sralph 			av[1] = width;
43812111Sralph 			av[2] = length;
43912111Sralph 			av[3] = "-h";
44012111Sralph 			av[4] = *title ? title : " ";
44112111Sralph 			av[5] = 0;
44212111Sralph 			fo = ofd;
44312111Sralph 			goto start;
44412111Sralph 		}
44512111Sralph 		pipe(p);
44612111Sralph 		if ((prchild = dofork(DORETURN)) == 0) {	/* child */
44712111Sralph 			dup2(fi, 0);		/* file is stdin */
44812111Sralph 			dup2(p[1], 1);		/* pipe is stdout */
44912111Sralph 			for (n = 3; n < NOFILE; n++)
45012111Sralph 				(void) close(n);
45112111Sralph 			execl(PR, "pr", width, length, "-h", *title ? title : " ", 0);
45216762Sralph 			syslog(LOG_ERR, "cannot execl %s", PR);
45312111Sralph 			exit(2);
45412111Sralph 		}
45512111Sralph 		(void) close(p[1]);		/* close output side */
45612111Sralph 		(void) close(fi);
45712111Sralph 		if (prchild < 0) {
45812111Sralph 			prchild = 0;
45912111Sralph 			(void) close(p[0]);
460*17463Sralph 			return(ERROR);
46112111Sralph 		}
46212111Sralph 		fi = p[0];			/* use pipe for input */
46312111Sralph 	case 'f':	/* print plain text file */
46412111Sralph 		prog = IF;
46512111Sralph 		av[1] = width;
46612111Sralph 		av[2] = length;
46712581Sralph 		av[3] = indent;
46812581Sralph 		n = 4;
46912111Sralph 		break;
47012111Sralph 	case 'l':	/* like 'f' but pass control characters */
47112111Sralph 		prog = IF;
47214325Sralph 		av[1] = "-c";
47312111Sralph 		av[2] = width;
47412111Sralph 		av[3] = length;
47512581Sralph 		av[4] = indent;
47612581Sralph 		n = 5;
47712111Sralph 		break;
47812463Sralph 	case 'r':	/* print a fortran text file */
47912463Sralph 		prog = RF;
48012463Sralph 		av[1] = width;
48112463Sralph 		av[2] = length;
48212463Sralph 		n = 3;
48312463Sralph 		break;
48412111Sralph 	case 't':	/* print troff output */
48513233Sralph 	case 'n':	/* print ditroff output */
48612463Sralph 	case 'd':	/* print tex output */
48712111Sralph 		(void) unlink(".railmag");
48812463Sralph 		if ((fo = creat(".railmag", FILMOD)) < 0) {
48916762Sralph 			syslog(LOG_ERR, "%s: cannot create .railmag", printer);
49012111Sralph 			(void) unlink(".railmag");
49112111Sralph 		} else {
49212111Sralph 			for (n = 0; n < 4; n++) {
49312111Sralph 				if (fonts[n][0] != '/')
49412111Sralph 					(void) write(fo, "/usr/lib/vfont/", 15);
49512111Sralph 				(void) write(fo, fonts[n], strlen(fonts[n]));
49612111Sralph 				(void) write(fo, "\n", 1);
49712111Sralph 			}
49812111Sralph 			(void) close(fo);
49912111Sralph 		}
50013233Sralph 		prog = (format == 't') ? TF : (format == 'n') ? NF : DF;
50112463Sralph 		av[1] = pxwidth;
50212463Sralph 		av[2] = pxlength;
50312463Sralph 		n = 3;
50412111Sralph 		break;
50512111Sralph 	case 'c':	/* print cifplot output */
50612111Sralph 		prog = CF;
50712463Sralph 		av[1] = pxwidth;
50812463Sralph 		av[2] = pxlength;
50912463Sralph 		n = 3;
51012111Sralph 		break;
51112111Sralph 	case 'g':	/* print plot(1G) output */
51212111Sralph 		prog = GF;
51312463Sralph 		av[1] = pxwidth;
51412463Sralph 		av[2] = pxlength;
51512463Sralph 		n = 3;
51612111Sralph 		break;
51712111Sralph 	case 'v':	/* print raster output */
51812111Sralph 		prog = VF;
51912463Sralph 		av[1] = pxwidth;
52012463Sralph 		av[2] = pxlength;
52112463Sralph 		n = 3;
52212111Sralph 		break;
52312111Sralph 	default:
52412111Sralph 		(void) close(fi);
52516762Sralph 		syslog(LOG_ERR, "%s: illegal format character '%c'",
52616762Sralph 			printer, format);
527*17463Sralph 		return(ERROR);
52812111Sralph 	}
52912111Sralph 	if ((av[0] = rindex(prog, '/')) != NULL)
53012111Sralph 		av[0]++;
53112111Sralph 	else
53212111Sralph 		av[0] = prog;
53312111Sralph 	av[n++] = "-n";
53412111Sralph 	av[n++] = logname;
53512111Sralph 	av[n++] = "-h";
53614150Sralph 	av[n++] = fromhost;
53712111Sralph 	av[n++] = AF;
53812111Sralph 	av[n] = 0;
53912111Sralph 	fo = pfd;
54012111Sralph 	if (ofilter > 0) {		/* stop output filter */
54112111Sralph 		write(ofd, "\031\1", 2);
54212111Sralph 		while ((pid = wait3(&status, WUNTRACED, 0)) > 0 && pid != ofilter)
54312111Sralph 			;
54412111Sralph 		if (status.w_stopval != WSTOPPED) {
54512111Sralph 			(void) close(fi);
54616762Sralph 			syslog(LOG_WARNING, "%s: output filter died (%d)",
54716762Sralph 				printer, status.w_retcode);
548*17463Sralph 			return(REPRINT);
54912111Sralph 		}
55012111Sralph 		stopped++;
55112111Sralph 	}
55212111Sralph start:
55312111Sralph 	if ((child = dofork(DORETURN)) == 0) {	/* child */
55412111Sralph 		dup2(fi, 0);
55512111Sralph 		dup2(fo, 1);
55617304Sralph 		n = open(tmpfile, O_WRONLY|O_CREAT|O_TRUNC, 0664);
55715811Sralph 		if (n >= 0)
55815811Sralph 			dup2(n, 2);
55912111Sralph 		for (n = 3; n < NOFILE; n++)
56012111Sralph 			(void) close(n);
56112111Sralph 		execv(prog, av);
56216762Sralph 		syslog(LOG_ERR, "cannot execv %s", prog);
56312111Sralph 		exit(2);
56412111Sralph 	}
56512111Sralph 	(void) close(fi);
56612111Sralph 	if (child < 0)
56712111Sralph 		status.w_retcode = 100;
56812111Sralph 	else
56912111Sralph 		while ((pid = wait(&status)) > 0 && pid != child)
57012111Sralph 			;
57112111Sralph 	child = 0;
57212111Sralph 	prchild = 0;
57312111Sralph 	if (stopped) {		/* restart output filter */
57412111Sralph 		if (kill(ofilter, SIGCONT) < 0) {
57516762Sralph 			syslog(LOG_ERR, "cannot restart output filter");
57612111Sralph 			exit(1);
57712111Sralph 		}
57812111Sralph 	}
57912111Sralph 	tof = 0;
58015811Sralph 	if (!WIFEXITED(status)) {
58116762Sralph 		syslog(LOG_WARNING, "%s: Daemon filter '%c' terminated (%d)",
58216762Sralph 			printer, format, status.w_termsig);
583*17463Sralph 		return(ERROR);
584*17463Sralph 	}
585*17463Sralph 	switch (status.w_retcode) {
586*17463Sralph 	case 0:
587*17463Sralph 		tof = 1;
588*17463Sralph 		return(OK);
589*17463Sralph 	case 1:
590*17463Sralph 		return(REPRINT);
591*17463Sralph 	default:
59216762Sralph 		syslog(LOG_WARNING, "%s: Daemon filter '%c' exited (%d)",
59316762Sralph 			printer, format, status.w_retcode);
594*17463Sralph 	case 2:
595*17463Sralph 		return(ERROR);
596*17463Sralph 	}
59712111Sralph }
59812111Sralph 
59912111Sralph /*
60012111Sralph  * Send the daemon control file (cf) and any data files.
60112111Sralph  * Return -1 if a non-recoverable error occured, 1 if a recoverable error and
60212111Sralph  * 0 if all is well.
60312111Sralph  */
60412111Sralph sendit(file)
60512111Sralph 	char *file;
60612111Sralph {
607*17463Sralph 	register int i, err = OK;
608*17463Sralph 	char *cp, last[BUFSIZ];
60912111Sralph 
61012111Sralph 	/*
61112111Sralph 	 * open control file
61212111Sralph 	 */
61316762Sralph 	if ((cfp = fopen(file, "r")) == NULL)
614*17463Sralph 		return(OK);
61512111Sralph 	/*
61612111Sralph 	 *      read the control file for work to do
61712111Sralph 	 *
61812111Sralph 	 *      file format -- first character in the line is a command
61912111Sralph 	 *      rest of the line is the argument.
62012111Sralph 	 *      commands of interest are:
62112111Sralph 	 *
62212111Sralph 	 *            a-z -- "file name" name of file to print
62312111Sralph 	 *              U -- "unlink" name of file to remove
62412111Sralph 	 *                    (after we print it. (Pass 2 only)).
62512111Sralph 	 */
62612111Sralph 
62712111Sralph 	/*
62812111Sralph 	 * pass 1
62912111Sralph 	 */
63012111Sralph 	while (getline(cfp)) {
63112111Sralph 	again:
632*17463Sralph 		if (line[0] == 'S') {
633*17463Sralph 			cp = line+1;
634*17463Sralph 			i = 0;
635*17463Sralph 			while (*cp >= '0' && *cp <= '9')
636*17463Sralph 				i = i * 10 + (*cp++ - '0');
637*17463Sralph 			fdev = i;
638*17463Sralph 			cp++;
639*17463Sralph 			i = 0;
640*17463Sralph 			while (*cp >= '0' && *cp <= '9')
641*17463Sralph 				i = i * 10 + (*cp++ - '0');
642*17463Sralph 			fino = i;
643*17463Sralph 			continue;
644*17463Sralph 		}
64512111Sralph 		if (line[0] >= 'a' && line[0] <= 'z') {
64612111Sralph 			strcpy(last, line);
647*17463Sralph 			while (i = getline(cfp))
64812111Sralph 				if (strcmp(last, line))
64912111Sralph 					break;
650*17463Sralph 			switch (sendfile('\3', last+1)) {
651*17463Sralph 			case OK:
652*17463Sralph 				if (i)
653*17463Sralph 					goto again;
654*17463Sralph 				break;
655*17463Sralph 			case REPRINT:
65612111Sralph 				(void) fclose(cfp);
657*17463Sralph 				return(REPRINT);
658*17463Sralph 			case ACCESS:
659*17463Sralph 				sendmail(logname, ACCESS);
660*17463Sralph 			case ERROR:
661*17463Sralph 				err = ERROR;
662*17463Sralph 			}
66312111Sralph 			break;
66412111Sralph 		}
66512111Sralph 	}
666*17463Sralph 	if (err == OK && sendfile('\2', file) > 0) {
66712111Sralph 		(void) fclose(cfp);
668*17463Sralph 		return(REPRINT);
66912111Sralph 	}
67012111Sralph 	/*
67112111Sralph 	 * pass 2
67212111Sralph 	 */
67312111Sralph 	fseek(cfp, 0L, 0);
67412111Sralph 	while (getline(cfp))
67512111Sralph 		if (line[0] == 'U')
67612111Sralph 			(void) unlink(line+1);
67712111Sralph 	/*
678*17463Sralph 	 * clean-up in case another control file exists
67912111Sralph 	 */
68012111Sralph 	(void) fclose(cfp);
68112111Sralph 	(void) unlink(file);
682*17463Sralph 	return(err);
68312111Sralph }
68412111Sralph 
68512111Sralph /*
68612111Sralph  * Send a data file to the remote machine and spool it.
68712111Sralph  * Return positive if we should try resending.
68812111Sralph  */
68912111Sralph sendfile(type, file)
69012111Sralph 	char type, *file;
69112111Sralph {
69212111Sralph 	register int f, i, amt;
69312111Sralph 	struct stat stb;
69412111Sralph 	char buf[BUFSIZ];
69516762Sralph 	int sizerr, resp;
69612111Sralph 
697*17463Sralph 	if (lstat(file, &stb) < 0 || (f = open(file, O_RDONLY)) < 0)
698*17463Sralph 		return(ERROR);
699*17463Sralph 	/*
700*17463Sralph 	 * Check to see if data file is a symbolic link. If so, it should
701*17463Sralph 	 * still point to the same file or someone is trying to print something
702*17463Sralph 	 * he shouldn't.
703*17463Sralph 	 */
704*17463Sralph 	if ((stb.st_mode & S_IFMT) == S_IFLNK && fstat(f, &stb) == 0 &&
705*17463Sralph 	    (stb.st_dev != fdev || stb.st_ino != fino))
706*17463Sralph 		return(ACCESS);
70712111Sralph 	(void) sprintf(buf, "%c%d %s\n", type, stb.st_size, file);
70812111Sralph 	amt = strlen(buf);
70916762Sralph 	for (i = 0;  ; i++) {
71016762Sralph 		if (write(pfd, buf, amt) != amt ||
71116762Sralph 		    (resp = response()) < 0 || resp == '\1') {
71216762Sralph 			(void) close(f);
713*17463Sralph 			return(REPRINT);
71416762Sralph 		} else if (resp == '\0')
71516762Sralph 			break;
71616762Sralph 		if (i == 0)
71716762Sralph 			status("no space on remote; waiting for queue to drain");
71816762Sralph 		if (i == 10)
71916762Sralph 			syslog(LOG_SALERT, "%s: can't send to %s; queue full",
72016762Sralph 				printer, RM);
72116762Sralph 		sleep(5 * 60);
72212692Sralph 	}
72316762Sralph 	if (i)
72416762Sralph 		status("sending to %s", RM);
72512111Sralph 	sizerr = 0;
72612111Sralph 	for (i = 0; i < stb.st_size; i += BUFSIZ) {
72712111Sralph 		amt = BUFSIZ;
72812111Sralph 		if (i + amt > stb.st_size)
72912111Sralph 			amt = stb.st_size - i;
73012111Sralph 		if (sizerr == 0 && read(f, buf, amt) != amt)
73112111Sralph 			sizerr = 1;
73212692Sralph 		if (write(pfd, buf, amt) != amt) {
73312692Sralph 			(void) close(f);
734*17463Sralph 			return(REPRINT);
73512692Sralph 		}
73612111Sralph 	}
73712111Sralph 	(void) close(f);
73812111Sralph 	if (sizerr) {
73916762Sralph 		syslog(LOG_INFO, "%s: %s: changed size", printer, file);
740*17463Sralph 		/* tell recvjob to ignore this file */
741*17463Sralph 		(void) write(pfd, "\1", 1);
742*17463Sralph 		return(ERROR);
743*17463Sralph 	}
744*17463Sralph 	if (write(pfd, "", 1) != 1 || response())
745*17463Sralph 		return(REPRINT);
746*17463Sralph 	return(OK);
74712111Sralph }
74812111Sralph 
74912111Sralph /*
75012111Sralph  * Check to make sure there have been no errors and that both programs
75112111Sralph  * are in sync with eachother.
75212111Sralph  * Return non-zero if the connection was lost.
75312111Sralph  */
75416762Sralph response()
75512111Sralph {
75612111Sralph 	char resp;
75712111Sralph 
75816762Sralph 	if (read(pfd, &resp, 1) != 1) {
75916762Sralph 		syslog(LOG_INFO, "%s: lost connection", printer);
76016762Sralph 		return(-1);
76112111Sralph 	}
76216762Sralph 	return(resp);
76312111Sralph }
76412111Sralph 
76512111Sralph /*
76612111Sralph  * Banner printing stuff
76712111Sralph  */
76812111Sralph banner(name1, name2)
76912111Sralph 	char *name1, *name2;
77012111Sralph {
77112111Sralph 	time_t tvec;
77212111Sralph 	extern char *ctime();
77312111Sralph 
77412111Sralph 	time(&tvec);
77512111Sralph 	if (!SF && !tof)
77612111Sralph 		(void) write(ofd, FF, strlen(FF));
77712111Sralph 	if (SB) {	/* short banner only */
77812111Sralph 		if (class[0]) {
77912111Sralph 			(void) write(ofd, class, strlen(class));
78012111Sralph 			(void) write(ofd, ":", 1);
78112111Sralph 		}
78212111Sralph 		(void) write(ofd, name1, strlen(name1));
78312111Sralph 		(void) write(ofd, "  Job: ", 7);
78412111Sralph 		(void) write(ofd, name2, strlen(name2));
78512111Sralph 		(void) write(ofd, "  Date: ", 8);
78612111Sralph 		(void) write(ofd, ctime(&tvec), 24);
78712111Sralph 		(void) write(ofd, "\n", 1);
78812111Sralph 	} else {	/* normal banner */
78912111Sralph 		(void) write(ofd, "\n\n\n", 3);
79012111Sralph 		scan_out(ofd, name1, '\0');
79112111Sralph 		(void) write(ofd, "\n\n", 2);
79212111Sralph 		scan_out(ofd, name2, '\0');
79312111Sralph 		if (class[0]) {
79412111Sralph 			(void) write(ofd,"\n\n\n",3);
79512111Sralph 			scan_out(ofd, class, '\0');
79612111Sralph 		}
79712111Sralph 		(void) write(ofd, "\n\n\n\n\t\t\t\t\tJob:  ", 15);
79812111Sralph 		(void) write(ofd, name2, strlen(name2));
79912111Sralph 		(void) write(ofd, "\n\t\t\t\t\tDate: ", 12);
80012111Sralph 		(void) write(ofd, ctime(&tvec), 24);
80112111Sralph 		(void) write(ofd, "\n", 1);
80212111Sralph 	}
80312111Sralph 	if (!SF)
80412111Sralph 		(void) write(ofd, FF, strlen(FF));
80512111Sralph 	tof = 1;
80612111Sralph }
80712111Sralph 
80816762Sralph char *
80912111Sralph scnline(key, p, c)
81012111Sralph 	register char key, *p;
81112111Sralph 	char c;
81212111Sralph {
81312111Sralph 	register scnwidth;
81412111Sralph 
81512111Sralph 	for (scnwidth = WIDTH; --scnwidth;) {
81612111Sralph 		key <<= 1;
81712111Sralph 		*p++ = key & 0200 ? c : BACKGND;
81812111Sralph 	}
81912111Sralph 	return (p);
82012111Sralph }
82112111Sralph 
82212111Sralph #define TRC(q)	(((q)-' ')&0177)
82312111Sralph 
82412111Sralph scan_out(scfd, scsp, dlm)
82512111Sralph 	int scfd;
82612111Sralph 	char *scsp, dlm;
82712111Sralph {
82812111Sralph 	register char *strp;
82912111Sralph 	register nchrs, j;
83012111Sralph 	char outbuf[LINELEN+1], *sp, c, cc;
83112111Sralph 	int d, scnhgt;
83212111Sralph 	extern char scnkey[][HEIGHT];	/* in lpdchar.c */
83312111Sralph 
83412111Sralph 	for (scnhgt = 0; scnhgt++ < HEIGHT+DROP; ) {
83512111Sralph 		strp = &outbuf[0];
83612111Sralph 		sp = scsp;
83712111Sralph 		for (nchrs = 0; ; ) {
83812111Sralph 			d = dropit(c = TRC(cc = *sp++));
83912111Sralph 			if ((!d && scnhgt > HEIGHT) || (scnhgt <= DROP && d))
84012111Sralph 				for (j = WIDTH; --j;)
84112111Sralph 					*strp++ = BACKGND;
84212111Sralph 			else
84312111Sralph 				strp = scnline(scnkey[c][scnhgt-1-d], strp, cc);
84412111Sralph 			if (*sp == dlm || *sp == '\0' || nchrs++ >= PW/(WIDTH+1)-1)
84512111Sralph 				break;
84612111Sralph 			*strp++ = BACKGND;
84712111Sralph 			*strp++ = BACKGND;
84812111Sralph 		}
84912111Sralph 		while (*--strp == BACKGND && strp >= outbuf)
85012111Sralph 			;
85112111Sralph 		strp++;
85212111Sralph 		*strp++ = '\n';
85312111Sralph 		(void) write(scfd, outbuf, strp-outbuf);
85412111Sralph 	}
85512111Sralph }
85612111Sralph 
85712111Sralph dropit(c)
85812111Sralph 	char c;
85912111Sralph {
86012111Sralph 	switch(c) {
86112111Sralph 
86212111Sralph 	case TRC('_'):
86312111Sralph 	case TRC(';'):
86412111Sralph 	case TRC(','):
86512111Sralph 	case TRC('g'):
86612111Sralph 	case TRC('j'):
86712111Sralph 	case TRC('p'):
86812111Sralph 	case TRC('q'):
86912111Sralph 	case TRC('y'):
87012111Sralph 		return (DROP);
87112111Sralph 
87212111Sralph 	default:
87312111Sralph 		return (0);
87412111Sralph 	}
87512111Sralph }
87612111Sralph 
87712111Sralph /*
87812111Sralph  * sendmail ---
87912111Sralph  *   tell people about job completion
88012111Sralph  */
88115811Sralph sendmail(user, bombed)
88215811Sralph 	char *user;
88312111Sralph 	int bombed;
88412111Sralph {
88512111Sralph 	register int i;
88615811Sralph 	int p[2], s;
88712111Sralph 	register char *cp;
88812111Sralph 	char buf[100];
88915811Sralph 	struct stat stb;
89015811Sralph 	FILE *fp;
89112111Sralph 
89212111Sralph 	pipe(p);
89315811Sralph 	if ((s = dofork(DORETURN)) == 0) {		/* child */
89412111Sralph 		dup2(p[0], 0);
89512111Sralph 		for (i = 3; i < NOFILE; i++)
89612111Sralph 			(void) close(i);
89712111Sralph 		if ((cp = rindex(MAIL, '/')) != NULL)
89812111Sralph 			cp++;
89912111Sralph 		else
90012111Sralph 			cp = MAIL;
90115811Sralph 		sprintf(buf, "%s@%s", user, fromhost);
90212111Sralph 		execl(MAIL, cp, buf, 0);
90312111Sralph 		exit(0);
90415811Sralph 	} else if (s > 0) {				/* parent */
90512111Sralph 		dup2(p[1], 1);
90615811Sralph 		printf("To: %s@%s\n", user, fromhost);
90712111Sralph 		printf("Subject: printer job\n\n");
90812111Sralph 		printf("Your printer job ");
90912111Sralph 		if (*jobname)
91012111Sralph 			printf("(%s) ", jobname);
91112463Sralph 		switch (bombed) {
912*17463Sralph 		case OK:
91312463Sralph 			printf("\ncompleted successfully\n");
91412463Sralph 			break;
91512463Sralph 		default:
916*17463Sralph 		case FATALERR:
91712463Sralph 			printf("\ncould not be printed\n");
91812463Sralph 			break;
919*17463Sralph 		case NOACCT:
92012463Sralph 			printf("\ncould not be printed without an account on %s\n", host);
92112463Sralph 			break;
922*17463Sralph 		case FILTERERR:
92315811Sralph 			if (stat(tmpfile, &stb) < 0 || stb.st_size == 0 ||
92415811Sralph 			    (fp = fopen(tmpfile, "r")) == NULL) {
92515811Sralph 				printf("\nwas printed but had some errors\n");
92615811Sralph 				break;
92715811Sralph 			}
92815811Sralph 			printf("\nwas printed but had the following errors:\n");
92915811Sralph 			while ((i = getc(fp)) != EOF)
93015811Sralph 				putchar(i);
93115811Sralph 			(void) fclose(fp);
932*17463Sralph 			break;
933*17463Sralph 		case ACCESS:
934*17463Sralph 			printf("\nwas not printed because it was not linked to the original file\n");
93512463Sralph 		}
93612111Sralph 		fflush(stdout);
93712111Sralph 		(void) close(1);
93812111Sralph 	}
93912111Sralph 	(void) close(p[0]);
94012111Sralph 	(void) close(p[1]);
94115811Sralph 	wait(&s);
94212111Sralph }
94312111Sralph 
94412111Sralph /*
94512111Sralph  * dofork - fork with retries on failure
94612111Sralph  */
94712111Sralph dofork(action)
94812111Sralph 	int action;
94912111Sralph {
95012111Sralph 	register int i, pid;
95112111Sralph 
95212111Sralph 	for (i = 0; i < 20; i++) {
95312463Sralph 		if ((pid = fork()) < 0) {
95412111Sralph 			sleep((unsigned)(i*i));
95512463Sralph 			continue;
95612463Sralph 		}
95712463Sralph 		/*
95812463Sralph 		 * Child should run as daemon instead of root
95912463Sralph 		 */
96012463Sralph 		if (pid == 0)
96112463Sralph 			setuid(DU);
96212463Sralph 		return(pid);
96312111Sralph 	}
96416762Sralph 	syslog(LOG_ERR, "can't fork");
96512111Sralph 
96612111Sralph 	switch (action) {
96712111Sralph 	case DORETURN:
96812111Sralph 		return (-1);
96912111Sralph 	default:
97016762Sralph 		syslog(LOG_ERR, "bad action (%d) to dofork", action);
97112111Sralph 		/*FALL THRU*/
97212111Sralph 	case DOABORT:
97312111Sralph 		exit(1);
97412111Sralph 	}
97512111Sralph 	/*NOTREACHED*/
97612111Sralph }
97712111Sralph 
97812111Sralph /*
97916762Sralph  * Kill child processes to abort current job.
98012111Sralph  */
98116762Sralph abortpr()
98212111Sralph {
98315811Sralph 	(void) unlink(tmpfile);
98412111Sralph 	kill(0, SIGINT);
98512111Sralph 	if (ofilter > 0)
98612111Sralph 		kill(ofilter, SIGCONT);
98712111Sralph 	while (wait(0) > 0)
98812111Sralph 		;
98912111Sralph 	exit(0);
99012111Sralph }
99112111Sralph 
99212111Sralph init()
99312111Sralph {
99412111Sralph 	int status;
99512111Sralph 
99613169Sralph 	if ((status = pgetent(line, printer)) < 0)
99713169Sralph 		fatal("can't open printer description file");
99813169Sralph 	else if (status == 0)
99913169Sralph 		fatal("unknown printer");
100012111Sralph 	if ((LP = pgetstr("lp", &bp)) == NULL)
100112111Sralph 		LP = DEFDEVLP;
100212111Sralph 	if ((RP = pgetstr("rp", &bp)) == NULL)
100312463Sralph 		RP = DEFLP;
100412111Sralph 	if ((LO = pgetstr("lo", &bp)) == NULL)
100512111Sralph 		LO = DEFLOCK;
100612111Sralph 	if ((ST = pgetstr("st", &bp)) == NULL)
100712111Sralph 		ST = DEFSTAT;
100812111Sralph 	if ((LF = pgetstr("lf", &bp)) == NULL)
100912111Sralph 		LF = DEFLOGF;
101012111Sralph 	if ((SD = pgetstr("sd", &bp)) == NULL)
101112111Sralph 		SD = DEFSPOOL;
101212111Sralph 	if ((DU = pgetnum("du")) < 0)
101312111Sralph 		DU = DEFUID;
101412111Sralph 	if ((FF = pgetstr("ff", &bp)) == NULL)
101512111Sralph 		FF = DEFFF;
101612111Sralph 	if ((PW = pgetnum("pw")) < 0)
101712111Sralph 		PW = DEFWIDTH;
101812111Sralph 	sprintf(&width[2], "%d", PW);
101912111Sralph 	if ((PL = pgetnum("pl")) < 0)
102012111Sralph 		PL = DEFLENGTH;
102112111Sralph 	sprintf(&length[2], "%d", PL);
102212463Sralph 	if ((PX = pgetnum("px")) < 0)
102312463Sralph 		PX = 0;
102412463Sralph 	sprintf(&pxwidth[2], "%d", PX);
102512463Sralph 	if ((PY = pgetnum("py")) < 0)
102612463Sralph 		PY = 0;
102712463Sralph 	sprintf(&pxlength[2], "%d", PY);
102812111Sralph 	RM = pgetstr("rm", &bp);
102912111Sralph 	AF = pgetstr("af", &bp);
103012111Sralph 	OF = pgetstr("of", &bp);
103112111Sralph 	IF = pgetstr("if", &bp);
103212463Sralph 	RF = pgetstr("rf", &bp);
103312111Sralph 	TF = pgetstr("tf", &bp);
103413233Sralph 	NF = pgetstr("nf", &bp);
103512111Sralph 	DF = pgetstr("df", &bp);
103612111Sralph 	GF = pgetstr("gf", &bp);
103712111Sralph 	VF = pgetstr("vf", &bp);
103812111Sralph 	CF = pgetstr("cf", &bp);
103912111Sralph 	TR = pgetstr("tr", &bp);
104012463Sralph 	RS = pgetflag("rs");
104112111Sralph 	SF = pgetflag("sf");
104212111Sralph 	SH = pgetflag("sh");
104312111Sralph 	SB = pgetflag("sb");
104412111Sralph 	RW = pgetflag("rw");
104512111Sralph 	BR = pgetnum("br");
104612111Sralph 	if ((FC = pgetnum("fc")) < 0)
104712111Sralph 		FC = 0;
104812111Sralph 	if ((FS = pgetnum("fs")) < 0)
104912111Sralph 		FS = 0;
105012111Sralph 	if ((XC = pgetnum("xc")) < 0)
105112111Sralph 		XC = 0;
105212111Sralph 	if ((XS = pgetnum("xs")) < 0)
105312111Sralph 		XS = 0;
105412581Sralph 	tof = !pgetflag("fo");
105512111Sralph }
105612111Sralph 
105712463Sralph /*
105812463Sralph  * Acquire line printer or remote connection.
105912463Sralph  */
106012463Sralph openpr()
106112463Sralph {
106212463Sralph 	register int i, n;
106316762Sralph 	int resp;
106412463Sralph 
106512463Sralph 	if (*LP) {
106612463Sralph 		for (i = 1; ; i = i < 32 ? i << 1 : i) {
106713148Ssam 			pfd = open(LP, RW ? O_RDWR : O_WRONLY);
106812463Sralph 			if (pfd >= 0)
106912463Sralph 				break;
107012463Sralph 			if (errno == ENOENT) {
107116762Sralph 				syslog(LOG_ERR, "%s: %m", LP);
107212463Sralph 				exit(1);
107312463Sralph 			}
107412463Sralph 			if (i == 1)
107512463Sralph 				status("waiting for %s to become ready (offline ?)", printer);
107612463Sralph 			sleep(i);
107712463Sralph 		}
107812463Sralph 		if (isatty(pfd))
107912463Sralph 			setty();
108012463Sralph 		status("%s is ready and printing", printer);
108112463Sralph 	} else if (RM != NULL) {
108216762Sralph 		for (i = 1; ; i = i < 256 ? i << 1 : i) {
108316762Sralph 			resp = -1;
108412528Sralph 			pfd = getport(RM);
108512463Sralph 			if (pfd >= 0) {
108612463Sralph 				(void) sprintf(line, "\2%s\n", RP);
108712463Sralph 				n = strlen(line);
108816762Sralph 				if (write(pfd, line, n) == n &&
108916762Sralph 				    (resp = response()) == '\0')
109012463Sralph 					break;
109116031Sralph 				(void) close(pfd);
109212463Sralph 			}
109316031Sralph 			if (i == 1) {
109416762Sralph 				if (resp < 0)
109516031Sralph 					status("waiting for %s to come up", RM);
109616762Sralph 				else {
109716031Sralph 					status("waiting for queue to be enabled on %s", RM);
109816762Sralph 					i = 256;
109916762Sralph 				}
110016031Sralph 			}
110112463Sralph 			sleep(i);
110212463Sralph 		}
110312463Sralph 		status("sending to %s", RM);
110412463Sralph 		remote = 1;
110512463Sralph 	} else {
110616762Sralph 		syslog(LOG_ERR, "%s: no line printer device or host name",
110716762Sralph 			printer);
110812463Sralph 		exit(1);
110912463Sralph 	}
111012463Sralph 	/*
111112463Sralph 	 * Start up an output filter, if needed.
111212463Sralph 	 */
111312463Sralph 	if (OF) {
111412463Sralph 		int p[2];
111512463Sralph 		char *cp;
111612463Sralph 
111712463Sralph 		pipe(p);
111812463Sralph 		if ((ofilter = dofork(DOABORT)) == 0) {	/* child */
111912463Sralph 			dup2(p[0], 0);		/* pipe is std in */
112012463Sralph 			dup2(pfd, 1);		/* printer is std out */
112112463Sralph 			for (i = 3; i < NOFILE; i++)
112212463Sralph 				(void) close(i);
112312463Sralph 			if ((cp = rindex(OF, '/')) == NULL)
112412463Sralph 				cp = OF;
112512463Sralph 			else
112612463Sralph 				cp++;
112712463Sralph 			execl(OF, cp, width, length, 0);
112816762Sralph 			syslog(LOG_ERR, "%s: %s: %m", printer, OF);
112912463Sralph 			exit(1);
113012463Sralph 		}
113112463Sralph 		(void) close(p[0]);		/* close input side */
113212463Sralph 		ofd = p[1];			/* use pipe for output */
113312463Sralph 	} else {
113412463Sralph 		ofd = pfd;
113512463Sralph 		ofilter = 0;
113612463Sralph 	}
113712463Sralph }
113812463Sralph 
113912111Sralph struct bauds {
114012111Sralph 	int	baud;
114112111Sralph 	int	speed;
114212111Sralph } bauds[] = {
114312111Sralph 	50,	B50,
114412111Sralph 	75,	B75,
114512111Sralph 	110,	B110,
114612111Sralph 	134,	B134,
114712111Sralph 	150,	B150,
114812111Sralph 	200,	B200,
114912111Sralph 	300,	B300,
115012111Sralph 	600,	B600,
115112111Sralph 	1200,	B1200,
115212111Sralph 	1800,	B1800,
115312111Sralph 	2400,	B2400,
115412111Sralph 	4800,	B4800,
115512111Sralph 	9600,	B9600,
115612111Sralph 	19200,	EXTA,
115712111Sralph 	38400,	EXTB,
115812111Sralph 	0,	0
115912111Sralph };
116012111Sralph 
116112111Sralph /*
116212111Sralph  * setup tty lines.
116312111Sralph  */
116412111Sralph setty()
116512111Sralph {
116612111Sralph 	struct sgttyb ttybuf;
116712111Sralph 	register struct bauds *bp;
116812111Sralph 
116912111Sralph 	if (ioctl(pfd, TIOCEXCL, (char *)0) < 0) {
117016762Sralph 		syslog(LOG_ERR, "%s: ioctl(TIOCEXCL): %m", printer);
117112111Sralph 		exit(1);
117212111Sralph 	}
117312111Sralph 	if (ioctl(pfd, TIOCGETP, (char *)&ttybuf) < 0) {
117416762Sralph 		syslog(LOG_ERR, "%s: ioctl(TIOCGETP): %m", printer);
117512111Sralph 		exit(1);
117612111Sralph 	}
117712111Sralph 	if (BR > 0) {
117812111Sralph 		for (bp = bauds; bp->baud; bp++)
117912111Sralph 			if (BR == bp->baud)
118012111Sralph 				break;
118112111Sralph 		if (!bp->baud) {
118216762Sralph 			syslog(LOG_ERR, "%s: illegal baud rate %d", printer, BR);
118312111Sralph 			exit(1);
118412111Sralph 		}
118512111Sralph 		ttybuf.sg_ispeed = ttybuf.sg_ospeed = bp->speed;
118612111Sralph 	}
118713169Sralph 	ttybuf.sg_flags &= ~FC;
118813169Sralph 	ttybuf.sg_flags |= FS;
118912111Sralph 	if (ioctl(pfd, TIOCSETP, (char *)&ttybuf) < 0) {
119016762Sralph 		syslog(LOG_ERR, "%s: ioctl(TIOCSETP): %m", printer);
119112111Sralph 		exit(1);
119212111Sralph 	}
119317168Sralph 	if (XC || XS) {
119417168Sralph 		int ldisc = NTTYDISC;
119517168Sralph 
119617168Sralph 		if (ioctl(pfd, TIOCSETD, &ldisc) < 0) {
119717168Sralph 			syslog(LOG_ERR, "%s: ioctl(TIOCSETD): %m", printer);
119817168Sralph 			exit(1);
119917168Sralph 		}
120017168Sralph 	}
120112111Sralph 	if (XC) {
120212111Sralph 		if (ioctl(pfd, TIOCLBIC, &XC) < 0) {
120316762Sralph 			syslog(LOG_ERR, "%s: ioctl(TIOCLBIC): %m", printer);
120412111Sralph 			exit(1);
120512111Sralph 		}
120612111Sralph 	}
120712111Sralph 	if (XS) {
120812111Sralph 		if (ioctl(pfd, TIOCLBIS, &XS) < 0) {
120916762Sralph 			syslog(LOG_ERR, "%s: ioctl(TIOCLBIS): %m", printer);
121012111Sralph 			exit(1);
121112111Sralph 		}
121212111Sralph 	}
121312111Sralph }
121412463Sralph 
121512463Sralph /*VARARGS1*/
121612463Sralph status(msg, a1, a2, a3)
121712463Sralph 	char *msg;
121812463Sralph {
121912463Sralph 	register int fd;
122012463Sralph 	char buf[BUFSIZ];
122112463Sralph 
122212463Sralph 	umask(0);
122313148Ssam 	fd = open(ST, O_WRONLY|O_CREAT, 0664);
122416762Sralph 	if (fd < 0 || flock(fd, LOCK_EX) < 0) {
122516762Sralph 		syslog(LOG_ERR, "%s: %s: %m", printer, ST);
122616762Sralph 		exit(1);
122716762Sralph 	}
122813148Ssam 	ftruncate(fd, 0);
122912463Sralph 	sprintf(buf, msg, a1, a2, a3);
123012463Sralph 	strcat(buf, "\n");
123112463Sralph 	(void) write(fd, buf, strlen(buf));
123212463Sralph 	(void) close(fd);
123312463Sralph }
1234