xref: /csrg-svn/usr.sbin/lpr/lpd/printjob.c (revision 22437)
1*22437Sdist /*
2*22437Sdist  * Copyright (c) 1983 Regents of the University of California.
3*22437Sdist  * All rights reserved.  The Berkeley software License Agreement
4*22437Sdist  * specifies the terms and conditions for redistribution.
5*22437Sdist  */
6*22437Sdist 
713954Ssam #ifndef lint
8*22437Sdist static char sccsid[] = "@(#)printjob.c	5.1 (Berkeley) 06/06/85";
9*22437Sdist #endif not lint
1013954Ssam 
1112111Sralph /*
1212111Sralph  * printjob -- print jobs in the queue.
1312111Sralph  *
1412111Sralph  *	NOTE: the lock file is used to pass information to lpq and lprm.
1512111Sralph  *	it does not need to be removed because file locks are dynamic.
1612111Sralph  */
1712111Sralph 
1812111Sralph #include "lp.h"
1912111Sralph 
2016762Sralph #define DORETURN	0	/* absorb fork error */
2116762Sralph #define DOABORT		1	/* abort if dofork fails */
2212111Sralph 
2317463Sralph /*
2417463Sralph  * Error tokens
2517463Sralph  */
2617463Sralph #define REPRINT		-2
2717463Sralph #define ERROR		-1
2817463Sralph #define	OK		0
2917463Sralph #define	FATALERR	1
3017463Sralph #define	NOACCT		2
3117463Sralph #define	FILTERERR	3
3217463Sralph #define	ACCESS		4
3317463Sralph 
3416762Sralph char	title[80];		/* ``pr'' title */
3516762Sralph FILE	*cfp;			/* control file */
3616762Sralph int	pfd;			/* printer file descriptor */
3716762Sralph int	ofd;			/* output filter file descriptor */
3816762Sralph int	lfd;			/* lock file descriptor */
3916762Sralph int	pid;			/* pid of lpd process */
4016762Sralph int	prchild;		/* id of pr process */
4116762Sralph int	child;			/* id of any filters */
4216762Sralph int	ofilter;		/* id of output filter, if any */
4316762Sralph int	tof;			/* true if at top of form */
4416762Sralph int	remote;			/* true if sending files to remote */
4517463Sralph dev_t	fdev;			/* device of file pointed to by symlink */
4617463Sralph ino_t	fino;			/* inode of file pointed to by symlink */
4712111Sralph 
4816762Sralph char	fromhost[32];		/* user's host machine */
4916762Sralph char	logname[32];		/* user's login name */
5016762Sralph char	jobname[100];		/* job or file name */
5116762Sralph char	class[32];		/* classification field */
5216762Sralph char	width[10] = "-w";	/* page width in characters */
5316762Sralph char	length[10] = "-l";	/* page length in lines */
5416762Sralph char	pxwidth[10] = "-x";	/* page width in pixels */
5516762Sralph char	pxlength[10] = "-y";	/* page length in pixels */
5616762Sralph char	indent[10] = "-i0";	/* indentation size in characters */
5716762Sralph char	tmpfile[] = "errsXXXXXX"; /* file name for filter output */
5812111Sralph 
5912111Sralph printjob()
6012111Sralph {
6112111Sralph 	struct stat stb;
6212111Sralph 	register struct queue *q, **qp;
6312111Sralph 	struct queue **queue;
6412111Sralph 	register int i, nitems;
6512111Sralph 	long pidoff;
6616762Sralph 	int count = 0;
6716762Sralph 	extern int abortpr();
6812111Sralph 
6912111Sralph 	init();					/* set up capabilities */
7013442Sralph 	(void) write(1, "", 1);			/* ack that daemon is started */
7116762Sralph 	setgid(getegid());
7212463Sralph 	pid = getpid();				/* for use with lprm */
7312111Sralph 	setpgrp(0, pid);
7416762Sralph 	signal(SIGHUP, abortpr);
7516762Sralph 	signal(SIGINT, abortpr);
7616762Sralph 	signal(SIGQUIT, abortpr);
7716762Sralph 	signal(SIGTERM, abortpr);
7812111Sralph 
7915811Sralph 	(void) mktemp(tmpfile);
8015811Sralph 
8112111Sralph 	/*
8212111Sralph 	 * uses short form file names
8312111Sralph 	 */
8412111Sralph 	if (chdir(SD) < 0) {
8516762Sralph 		syslog(LOG_ERR, "%s: %m", SD);
8612111Sralph 		exit(1);
8712111Sralph 	}
8812463Sralph 	if (stat(LO, &stb) == 0 && (stb.st_mode & 0100))
8912463Sralph 		exit(0);		/* printing disabled */
9014150Sralph 	lfd = open(LO, O_WRONLY|O_CREAT, 0644);
9113169Sralph 	if (lfd < 0) {
9216762Sralph 		syslog(LOG_ERR, "%s: %s: %m", printer, LO);
9313169Sralph 		exit(1);
9413169Sralph 	}
9513169Sralph 	if (flock(lfd, LOCK_EX|LOCK_NB) < 0) {
9612111Sralph 		if (errno == EWOULDBLOCK)	/* active deamon present */
9712111Sralph 			exit(0);
9816762Sralph 		syslog(LOG_ERR, "%s: %s: %m", printer, LO);
9912111Sralph 		exit(1);
10012111Sralph 	}
10113148Ssam 	ftruncate(lfd, 0);
10212111Sralph 	/*
10312111Sralph 	 * write process id for others to know
10412111Sralph 	 */
10512111Sralph 	sprintf(line, "%u\n", pid);
10612111Sralph 	pidoff = i = strlen(line);
10712463Sralph 	if (write(lfd, line, i) != i) {
10816762Sralph 		syslog(LOG_ERR, "%s: %s: %m", printer, LO);
10912111Sralph 		exit(1);
11012111Sralph 	}
11112111Sralph 	/*
11212111Sralph 	 * search the spool directory for work and sort by queue order.
11312111Sralph 	 */
11412111Sralph 	if ((nitems = getq(&queue)) < 0) {
11516762Sralph 		syslog(LOG_ERR, "%s: can't scan %s", printer, SD);
11612111Sralph 		exit(1);
11712111Sralph 	}
11812463Sralph 	if (nitems == 0)		/* no work to do */
11912111Sralph 		exit(0);
12013169Sralph 	if (stb.st_mode & 01) {		/* reset queue flag */
12113169Sralph 		if (fchmod(lfd, stb.st_mode & 0776) < 0)
12216762Sralph 			syslog(LOG_ERR, "%s: %s: %m", printer, LO);
12313169Sralph 	}
12412463Sralph 	openpr();			/* open printer or remote */
12512463Sralph again:
12612111Sralph 	/*
12712111Sralph 	 * we found something to do now do it --
12812111Sralph 	 *    write the name of the current control file into the lock file
12912111Sralph 	 *    so the spool queue program can tell what we're working on
13012111Sralph 	 */
13112111Sralph 	for (qp = queue; nitems--; free((char *) q)) {
13212111Sralph 		q = *qp++;
13312111Sralph 		if (stat(q->q_name, &stb) < 0)
13412111Sralph 			continue;
13512463Sralph 	restart:
13612111Sralph 		(void) lseek(lfd, pidoff, 0);
13712111Sralph 		(void) sprintf(line, "%s\n", q->q_name);
13812111Sralph 		i = strlen(line);
13912111Sralph 		if (write(lfd, line, i) != i)
14016762Sralph 			syslog(LOG_ERR, "%s: %s: %m", printer, LO);
14112111Sralph 		if (!remote)
14212111Sralph 			i = printit(q->q_name);
14312111Sralph 		else
14412111Sralph 			i = sendit(q->q_name);
14512463Sralph 		/*
14613169Sralph 		 * Check to see if we are supposed to stop printing or
14713169Sralph 		 * if we are to rebuild the queue.
14812463Sralph 		 */
14913169Sralph 		if (fstat(lfd, &stb) == 0) {
15016762Sralph 			/* stop printing before starting next job? */
15113169Sralph 			if (stb.st_mode & 0100)
15213169Sralph 				goto done;
15316762Sralph 			/* rebuild queue (after lpc topq) */
15413169Sralph 			if (stb.st_mode & 01) {
15513169Sralph 				for (free((char *) q); nitems--; free((char *) q))
15613169Sralph 					q = *qp++;
15713169Sralph 				if (fchmod(lfd, stb.st_mode & 0776) < 0)
15816762Sralph 					syslog(LOG_WARNING, "%s: %s: %m",
15916762Sralph 						printer, LO);
16013169Sralph 				break;
16113169Sralph 			}
16213169Sralph 		}
16317463Sralph 		if (i == OK)		/* file ok and printed */
16414150Sralph 			count++;
16517463Sralph 		else if (i == REPRINT) { /* try reprinting the job */
16616762Sralph 			syslog(LOG_INFO, "restarting %s", printer);
16712111Sralph 			if (ofilter > 0) {
16812111Sralph 				kill(ofilter, SIGCONT);	/* to be sure */
16912111Sralph 				(void) close(ofd);
17012111Sralph 				while ((i = wait(0)) > 0 && i != ofilter)
17112111Sralph 					;
17212111Sralph 				ofilter = 0;
17312111Sralph 			}
17412463Sralph 			(void) close(pfd);	/* close printer */
17515811Sralph 			if (ftruncate(lfd, pidoff) < 0)
17616762Sralph 				syslog(LOG_WARNING, "%s: %s: %m", printer, LO);
17712463Sralph 			openpr();		/* try to reopen printer */
17812111Sralph 			goto restart;
17912111Sralph 		}
18012111Sralph 	}
18112111Sralph 	free((char *) queue);
18212463Sralph 	/*
18312463Sralph 	 * search the spool directory for more work.
18412463Sralph 	 */
18512463Sralph 	if ((nitems = getq(&queue)) < 0) {
18616762Sralph 		syslog(LOG_ERR, "%s: can't scan %s", printer, SD);
18712463Sralph 		exit(1);
18812463Sralph 	}
18912463Sralph 	if (nitems == 0) {		/* no more work to do */
19012463Sralph 	done:
19114150Sralph 		if (count > 0) {	/* Files actually printed */
19214150Sralph 			if (!SF && !tof)
19314150Sralph 				(void) write(ofd, FF, strlen(FF));
19414150Sralph 			if (TR != NULL)		/* output trailer */
19514150Sralph 				(void) write(ofd, TR, strlen(TR));
19614150Sralph 		}
19715811Sralph 		(void) unlink(tmpfile);
19812463Sralph 		exit(0);
19912463Sralph 	}
20012111Sralph 	goto again;
20112111Sralph }
20212111Sralph 
20312111Sralph char	fonts[4][50];	/* fonts for troff */
20412111Sralph 
20516762Sralph char ifonts[4][18] = {
20612111Sralph 	"/usr/lib/vfont/R",
20712111Sralph 	"/usr/lib/vfont/I",
20812111Sralph 	"/usr/lib/vfont/B",
20912111Sralph 	"/usr/lib/vfont/S"
21012111Sralph };
21112111Sralph 
21212111Sralph /*
21312111Sralph  * The remaining part is the reading of the control file (cf)
21412111Sralph  * and performing the various actions.
21512111Sralph  */
21612111Sralph printit(file)
21712111Sralph 	char *file;
21812111Sralph {
21912111Sralph 	register int i;
22017463Sralph 	char *cp;
22117463Sralph 	int bombed = OK;
22212111Sralph 
22312111Sralph 	/*
22417463Sralph 	 * open control file; ignore if no longer there.
22512111Sralph 	 */
22612111Sralph 	if ((cfp = fopen(file, "r")) == NULL) {
22716762Sralph 		syslog(LOG_INFO, "%s: %s: %m", printer, file);
22817463Sralph 		return(OK);
22912111Sralph 	}
23012111Sralph 	/*
23112111Sralph 	 * Reset troff fonts.
23212111Sralph 	 */
23312111Sralph 	for (i = 0; i < 4; i++)
23412111Sralph 		strcpy(fonts[i], ifonts[i]);
23517339Sralph 	strcpy(width+2, "0");
23617302Sralph 	strcpy(indent+2, "0");
23712111Sralph 
23812111Sralph 	/*
23912111Sralph 	 *      read the control file for work to do
24012111Sralph 	 *
24112111Sralph 	 *      file format -- first character in the line is a command
24212111Sralph 	 *      rest of the line is the argument.
24312111Sralph 	 *      valid commands are:
24412111Sralph 	 *
24517463Sralph 	 *		S -- "stat info" for symbolic link protection
24612111Sralph 	 *		J -- "job name" on banner page
24712111Sralph 	 *		C -- "class name" on banner page
24812111Sralph 	 *              L -- "literal" user's name to print on banner
24912111Sralph 	 *		T -- "title" for pr
25012111Sralph 	 *		H -- "host name" of machine where lpr was done
25112111Sralph 	 *              P -- "person" user's login name
25212581Sralph 	 *              I -- "indent" amount to indent output
25312111Sralph 	 *              f -- "file name" name of text file to print
25412111Sralph 	 *		l -- "file name" text file with control chars
25512111Sralph 	 *		p -- "file name" text file to print with pr(1)
25612111Sralph 	 *		t -- "file name" troff(1) file to print
25713233Sralph 	 *		n -- "file name" ditroff(1) file to print
25812111Sralph 	 *		d -- "file name" dvi file to print
25912111Sralph 	 *		g -- "file name" plot(1G) file to print
26012111Sralph 	 *		v -- "file name" plain raster file to print
26112111Sralph 	 *		c -- "file name" cifplot file to print
26212111Sralph 	 *		1 -- "R font file" for troff
26312111Sralph 	 *		2 -- "I font file" for troff
26412111Sralph 	 *		3 -- "B font file" for troff
26512111Sralph 	 *		4 -- "S font file" for troff
26612111Sralph 	 *		N -- "name" of file (used by lpq)
26712111Sralph 	 *              U -- "unlink" name of file to remove
26812111Sralph 	 *                    (after we print it. (Pass 2 only)).
26912111Sralph 	 *		M -- "mail" to user when done printing
27012111Sralph 	 *
27112111Sralph 	 *      getline reads a line and expands tabs to blanks
27212111Sralph 	 */
27312111Sralph 
27412111Sralph 	/* pass 1 */
27512111Sralph 
27612111Sralph 	while (getline(cfp))
27712111Sralph 		switch (line[0]) {
27812111Sralph 		case 'H':
27914150Sralph 			strcpy(fromhost, line+1);
28012111Sralph 			if (class[0] == '\0')
28115552Sralph 				strncpy(class, line+1, sizeof(class)-1);
28212111Sralph 			continue;
28312111Sralph 
28412111Sralph 		case 'P':
28515552Sralph 			strncpy(logname, line+1, sizeof(logname)-1);
28612463Sralph 			if (RS) {			/* restricted */
28712463Sralph 				if (getpwnam(logname) == (struct passwd *)0) {
28817463Sralph 					bombed = NOACCT;
28915811Sralph 					sendmail(line+1, bombed);
29012463Sralph 					goto pass2;
29112463Sralph 				}
29212463Sralph 			}
29312111Sralph 			continue;
29412111Sralph 
29517463Sralph 		case 'S':
29617463Sralph 			cp = line+1;
29717463Sralph 			i = 0;
29817463Sralph 			while (*cp >= '0' && *cp <= '9')
29917463Sralph 				i = i * 10 + (*cp++ - '0');
30017463Sralph 			fdev = i;
30117463Sralph 			cp++;
30217463Sralph 			i = 0;
30317463Sralph 			while (*cp >= '0' && *cp <= '9')
30417463Sralph 				i = i * 10 + (*cp++ - '0');
30517463Sralph 			fino = i;
30617463Sralph 			continue;
30717463Sralph 
30812111Sralph 		case 'J':
30912111Sralph 			if (line[1] != '\0')
31015552Sralph 				strncpy(jobname, line+1, sizeof(jobname)-1);
31112111Sralph 			else
31212111Sralph 				strcpy(jobname, " ");
31312111Sralph 			continue;
31412111Sralph 
31512111Sralph 		case 'C':
31612111Sralph 			if (line[1] != '\0')
31715552Sralph 				strncpy(class, line+1, sizeof(class)-1);
31812111Sralph 			else if (class[0] == '\0')
31915811Sralph 				gethostname(class, sizeof(class));
32012111Sralph 			continue;
32112111Sralph 
32212111Sralph 		case 'T':	/* header title for pr */
32315552Sralph 			strncpy(title, line+1, sizeof(title)-1);
32412111Sralph 			continue;
32512111Sralph 
32612111Sralph 		case 'L':	/* identification line */
32718127Sralph 			if (!SH && !HL)
32812111Sralph 				banner(line+1, jobname);
32912111Sralph 			continue;
33012111Sralph 
33112111Sralph 		case '1':	/* troff fonts */
33212111Sralph 		case '2':
33312111Sralph 		case '3':
33412111Sralph 		case '4':
33512111Sralph 			if (line[1] != '\0')
33612111Sralph 				strcpy(fonts[line[0]-'1'], line+1);
33712111Sralph 			continue;
33812111Sralph 
33912111Sralph 		case 'W':	/* page width */
34015552Sralph 			strncpy(width+2, line+1, sizeof(width)-3);
34112111Sralph 			continue;
34212111Sralph 
34312581Sralph 		case 'I':	/* indent amount */
34415552Sralph 			strncpy(indent+2, line+1, sizeof(indent)-3);
34512581Sralph 			continue;
34612581Sralph 
34712111Sralph 		default:	/* some file to print */
34815811Sralph 			switch (i = print(line[0], line+1)) {
34917463Sralph 			case ERROR:
35017463Sralph 				if (bombed == OK)
35117463Sralph 					bombed = FATALERR;
35215811Sralph 				break;
35317463Sralph 			case REPRINT:
35412111Sralph 				(void) fclose(cfp);
35517463Sralph 				return(REPRINT);
35617463Sralph 			case FILTERERR:
35717463Sralph 			case ACCESS:
35817463Sralph 				bombed = i;
35915811Sralph 				sendmail(logname, bombed);
36015811Sralph 			}
36112111Sralph 			title[0] = '\0';
36212111Sralph 			continue;
36312111Sralph 
36412111Sralph 		case 'N':
36512111Sralph 		case 'U':
36612111Sralph 		case 'M':
36712111Sralph 			continue;
36812111Sralph 		}
36912111Sralph 
37012111Sralph 	/* pass 2 */
37112111Sralph 
37212463Sralph pass2:
37312111Sralph 	fseek(cfp, 0L, 0);
37412111Sralph 	while (getline(cfp))
37512111Sralph 		switch (line[0]) {
37618127Sralph 		case 'L':	/* identification line */
37718127Sralph 			if (!SH && HL)
37818127Sralph 				banner(line+1, jobname);
37918127Sralph 			continue;
38018127Sralph 
38112111Sralph 		case 'M':
38217463Sralph 			if (bombed < NOACCT)	/* already sent if >= NOACCT */
38315811Sralph 				sendmail(line+1, bombed);
38412111Sralph 			continue;
38512111Sralph 
38612111Sralph 		case 'U':
38712111Sralph 			(void) unlink(line+1);
38812111Sralph 		}
38912111Sralph 	/*
39015811Sralph 	 * clean-up in case another control file exists
39112111Sralph 	 */
39212111Sralph 	(void) fclose(cfp);
39312111Sralph 	(void) unlink(file);
39417463Sralph 	return(bombed == OK ? OK : ERROR);
39512111Sralph }
39612111Sralph 
39712111Sralph /*
39812111Sralph  * Print a file.
39913233Sralph  * Set up the chain [ PR [ | {IF, OF} ] ] or {IF, RF, TF, NF, DF, CF, VF}.
40015811Sralph  * Return -1 if a non-recoverable error occured,
40115811Sralph  * 2 if the filter detected some errors (but printed the job anyway),
40215811Sralph  * 1 if we should try to reprint this job and
40312111Sralph  * 0 if all is well.
40412111Sralph  * Note: all filters take stdin as the file, stdout as the printer,
40512111Sralph  * stderr as the log file, and must not ignore SIGINT.
40612111Sralph  */
40712111Sralph print(format, file)
40812111Sralph 	int format;
40912111Sralph 	char *file;
41012111Sralph {
41115811Sralph 	register int n;
41212111Sralph 	register char *prog;
41315811Sralph 	int fi, fo;
41412111Sralph 	char *av[15], buf[BUFSIZ];
41512111Sralph 	int pid, p[2], stopped = 0;
41612111Sralph 	union wait status;
41717463Sralph 	struct stat stb;
41812111Sralph 
41917463Sralph 	if (lstat(file, &stb) < 0 || (fi = open(file, O_RDONLY)) < 0)
42017463Sralph 		return(ERROR);
42117463Sralph 	/*
42217463Sralph 	 * Check to see if data file is a symbolic link. If so, it should
42317463Sralph 	 * still point to the same file or someone is trying to print
42417463Sralph 	 * something he shouldn't.
42517463Sralph 	 */
42617463Sralph 	if ((stb.st_mode & S_IFMT) == S_IFLNK && fstat(fi, &stb) == 0 &&
42717463Sralph 	    (stb.st_dev != fdev || stb.st_ino != fino))
42817463Sralph 		return(ACCESS);
42912111Sralph 	if (!SF && !tof) {		/* start on a fresh page */
43012111Sralph 		(void) write(ofd, FF, strlen(FF));
43112111Sralph 		tof = 1;
43212111Sralph 	}
43312111Sralph 	if (IF == NULL && (format == 'f' || format == 'l')) {
43412111Sralph 		tof = 0;
43512111Sralph 		while ((n = read(fi, buf, BUFSIZ)) > 0)
43612111Sralph 			if (write(ofd, buf, n) != n) {
43712111Sralph 				(void) close(fi);
43817463Sralph 				return(REPRINT);
43912111Sralph 			}
44012111Sralph 		(void) close(fi);
44117463Sralph 		return(OK);
44212111Sralph 	}
44312111Sralph 	switch (format) {
44412111Sralph 	case 'p':	/* print file using 'pr' */
44512111Sralph 		if (IF == NULL) {	/* use output filter */
44612111Sralph 			prog = PR;
44712111Sralph 			av[0] = "pr";
44812111Sralph 			av[1] = width;
44912111Sralph 			av[2] = length;
45012111Sralph 			av[3] = "-h";
45112111Sralph 			av[4] = *title ? title : " ";
45212111Sralph 			av[5] = 0;
45312111Sralph 			fo = ofd;
45412111Sralph 			goto start;
45512111Sralph 		}
45612111Sralph 		pipe(p);
45712111Sralph 		if ((prchild = dofork(DORETURN)) == 0) {	/* child */
45812111Sralph 			dup2(fi, 0);		/* file is stdin */
45912111Sralph 			dup2(p[1], 1);		/* pipe is stdout */
46012111Sralph 			for (n = 3; n < NOFILE; n++)
46112111Sralph 				(void) close(n);
46212111Sralph 			execl(PR, "pr", width, length, "-h", *title ? title : " ", 0);
46316762Sralph 			syslog(LOG_ERR, "cannot execl %s", PR);
46412111Sralph 			exit(2);
46512111Sralph 		}
46612111Sralph 		(void) close(p[1]);		/* close output side */
46712111Sralph 		(void) close(fi);
46812111Sralph 		if (prchild < 0) {
46912111Sralph 			prchild = 0;
47012111Sralph 			(void) close(p[0]);
47117463Sralph 			return(ERROR);
47212111Sralph 		}
47312111Sralph 		fi = p[0];			/* use pipe for input */
47412111Sralph 	case 'f':	/* print plain text file */
47512111Sralph 		prog = IF;
47612111Sralph 		av[1] = width;
47712111Sralph 		av[2] = length;
47812581Sralph 		av[3] = indent;
47912581Sralph 		n = 4;
48012111Sralph 		break;
48112111Sralph 	case 'l':	/* like 'f' but pass control characters */
48212111Sralph 		prog = IF;
48314325Sralph 		av[1] = "-c";
48412111Sralph 		av[2] = width;
48512111Sralph 		av[3] = length;
48612581Sralph 		av[4] = indent;
48712581Sralph 		n = 5;
48812111Sralph 		break;
48912463Sralph 	case 'r':	/* print a fortran text file */
49012463Sralph 		prog = RF;
49112463Sralph 		av[1] = width;
49212463Sralph 		av[2] = length;
49312463Sralph 		n = 3;
49412463Sralph 		break;
49512111Sralph 	case 't':	/* print troff output */
49613233Sralph 	case 'n':	/* print ditroff output */
49712463Sralph 	case 'd':	/* print tex output */
49812111Sralph 		(void) unlink(".railmag");
49912463Sralph 		if ((fo = creat(".railmag", FILMOD)) < 0) {
50016762Sralph 			syslog(LOG_ERR, "%s: cannot create .railmag", printer);
50112111Sralph 			(void) unlink(".railmag");
50212111Sralph 		} else {
50312111Sralph 			for (n = 0; n < 4; n++) {
50412111Sralph 				if (fonts[n][0] != '/')
50512111Sralph 					(void) write(fo, "/usr/lib/vfont/", 15);
50612111Sralph 				(void) write(fo, fonts[n], strlen(fonts[n]));
50712111Sralph 				(void) write(fo, "\n", 1);
50812111Sralph 			}
50912111Sralph 			(void) close(fo);
51012111Sralph 		}
51113233Sralph 		prog = (format == 't') ? TF : (format == 'n') ? NF : DF;
51212463Sralph 		av[1] = pxwidth;
51312463Sralph 		av[2] = pxlength;
51412463Sralph 		n = 3;
51512111Sralph 		break;
51612111Sralph 	case 'c':	/* print cifplot output */
51712111Sralph 		prog = CF;
51812463Sralph 		av[1] = pxwidth;
51912463Sralph 		av[2] = pxlength;
52012463Sralph 		n = 3;
52112111Sralph 		break;
52212111Sralph 	case 'g':	/* print plot(1G) output */
52312111Sralph 		prog = GF;
52412463Sralph 		av[1] = pxwidth;
52512463Sralph 		av[2] = pxlength;
52612463Sralph 		n = 3;
52712111Sralph 		break;
52812111Sralph 	case 'v':	/* print raster output */
52912111Sralph 		prog = VF;
53012463Sralph 		av[1] = pxwidth;
53112463Sralph 		av[2] = pxlength;
53212463Sralph 		n = 3;
53312111Sralph 		break;
53412111Sralph 	default:
53512111Sralph 		(void) close(fi);
53616762Sralph 		syslog(LOG_ERR, "%s: illegal format character '%c'",
53716762Sralph 			printer, format);
53817463Sralph 		return(ERROR);
53912111Sralph 	}
54012111Sralph 	if ((av[0] = rindex(prog, '/')) != NULL)
54112111Sralph 		av[0]++;
54212111Sralph 	else
54312111Sralph 		av[0] = prog;
54412111Sralph 	av[n++] = "-n";
54512111Sralph 	av[n++] = logname;
54612111Sralph 	av[n++] = "-h";
54714150Sralph 	av[n++] = fromhost;
54812111Sralph 	av[n++] = AF;
54912111Sralph 	av[n] = 0;
55012111Sralph 	fo = pfd;
55112111Sralph 	if (ofilter > 0) {		/* stop output filter */
55212111Sralph 		write(ofd, "\031\1", 2);
55312111Sralph 		while ((pid = wait3(&status, WUNTRACED, 0)) > 0 && pid != ofilter)
55412111Sralph 			;
55512111Sralph 		if (status.w_stopval != WSTOPPED) {
55612111Sralph 			(void) close(fi);
55716762Sralph 			syslog(LOG_WARNING, "%s: output filter died (%d)",
55816762Sralph 				printer, status.w_retcode);
55917463Sralph 			return(REPRINT);
56012111Sralph 		}
56112111Sralph 		stopped++;
56212111Sralph 	}
56312111Sralph start:
56412111Sralph 	if ((child = dofork(DORETURN)) == 0) {	/* child */
56512111Sralph 		dup2(fi, 0);
56612111Sralph 		dup2(fo, 1);
56717304Sralph 		n = open(tmpfile, O_WRONLY|O_CREAT|O_TRUNC, 0664);
56815811Sralph 		if (n >= 0)
56915811Sralph 			dup2(n, 2);
57012111Sralph 		for (n = 3; n < NOFILE; n++)
57112111Sralph 			(void) close(n);
57212111Sralph 		execv(prog, av);
57316762Sralph 		syslog(LOG_ERR, "cannot execv %s", prog);
57412111Sralph 		exit(2);
57512111Sralph 	}
57612111Sralph 	(void) close(fi);
57712111Sralph 	if (child < 0)
57812111Sralph 		status.w_retcode = 100;
57912111Sralph 	else
58012111Sralph 		while ((pid = wait(&status)) > 0 && pid != child)
58112111Sralph 			;
58212111Sralph 	child = 0;
58312111Sralph 	prchild = 0;
58412111Sralph 	if (stopped) {		/* restart output filter */
58512111Sralph 		if (kill(ofilter, SIGCONT) < 0) {
58616762Sralph 			syslog(LOG_ERR, "cannot restart output filter");
58712111Sralph 			exit(1);
58812111Sralph 		}
58912111Sralph 	}
59012111Sralph 	tof = 0;
59115811Sralph 	if (!WIFEXITED(status)) {
59216762Sralph 		syslog(LOG_WARNING, "%s: Daemon filter '%c' terminated (%d)",
59316762Sralph 			printer, format, status.w_termsig);
59417463Sralph 		return(ERROR);
59517463Sralph 	}
59617463Sralph 	switch (status.w_retcode) {
59717463Sralph 	case 0:
59817463Sralph 		tof = 1;
59917463Sralph 		return(OK);
60017463Sralph 	case 1:
60117463Sralph 		return(REPRINT);
60217463Sralph 	default:
60316762Sralph 		syslog(LOG_WARNING, "%s: Daemon filter '%c' exited (%d)",
60416762Sralph 			printer, format, status.w_retcode);
60517463Sralph 	case 2:
60617463Sralph 		return(ERROR);
60717463Sralph 	}
60812111Sralph }
60912111Sralph 
61012111Sralph /*
61112111Sralph  * Send the daemon control file (cf) and any data files.
61212111Sralph  * Return -1 if a non-recoverable error occured, 1 if a recoverable error and
61312111Sralph  * 0 if all is well.
61412111Sralph  */
61512111Sralph sendit(file)
61612111Sralph 	char *file;
61712111Sralph {
61817463Sralph 	register int i, err = OK;
61917463Sralph 	char *cp, last[BUFSIZ];
62012111Sralph 
62112111Sralph 	/*
62212111Sralph 	 * open control file
62312111Sralph 	 */
62416762Sralph 	if ((cfp = fopen(file, "r")) == NULL)
62517463Sralph 		return(OK);
62612111Sralph 	/*
62712111Sralph 	 *      read the control file for work to do
62812111Sralph 	 *
62912111Sralph 	 *      file format -- first character in the line is a command
63012111Sralph 	 *      rest of the line is the argument.
63112111Sralph 	 *      commands of interest are:
63212111Sralph 	 *
63312111Sralph 	 *            a-z -- "file name" name of file to print
63412111Sralph 	 *              U -- "unlink" name of file to remove
63512111Sralph 	 *                    (after we print it. (Pass 2 only)).
63612111Sralph 	 */
63712111Sralph 
63812111Sralph 	/*
63912111Sralph 	 * pass 1
64012111Sralph 	 */
64112111Sralph 	while (getline(cfp)) {
64212111Sralph 	again:
64317463Sralph 		if (line[0] == 'S') {
64417463Sralph 			cp = line+1;
64517463Sralph 			i = 0;
64617463Sralph 			while (*cp >= '0' && *cp <= '9')
64717463Sralph 				i = i * 10 + (*cp++ - '0');
64817463Sralph 			fdev = i;
64917463Sralph 			cp++;
65017463Sralph 			i = 0;
65117463Sralph 			while (*cp >= '0' && *cp <= '9')
65217463Sralph 				i = i * 10 + (*cp++ - '0');
65317463Sralph 			fino = i;
65417463Sralph 			continue;
65517463Sralph 		}
65612111Sralph 		if (line[0] >= 'a' && line[0] <= 'z') {
65712111Sralph 			strcpy(last, line);
65817463Sralph 			while (i = getline(cfp))
65912111Sralph 				if (strcmp(last, line))
66012111Sralph 					break;
66117463Sralph 			switch (sendfile('\3', last+1)) {
66217463Sralph 			case OK:
66317463Sralph 				if (i)
66417463Sralph 					goto again;
66517463Sralph 				break;
66617463Sralph 			case REPRINT:
66712111Sralph 				(void) fclose(cfp);
66817463Sralph 				return(REPRINT);
66917463Sralph 			case ACCESS:
67017463Sralph 				sendmail(logname, ACCESS);
67117463Sralph 			case ERROR:
67217463Sralph 				err = ERROR;
67317463Sralph 			}
67412111Sralph 			break;
67512111Sralph 		}
67612111Sralph 	}
67717463Sralph 	if (err == OK && sendfile('\2', file) > 0) {
67812111Sralph 		(void) fclose(cfp);
67917463Sralph 		return(REPRINT);
68012111Sralph 	}
68112111Sralph 	/*
68212111Sralph 	 * pass 2
68312111Sralph 	 */
68412111Sralph 	fseek(cfp, 0L, 0);
68512111Sralph 	while (getline(cfp))
68612111Sralph 		if (line[0] == 'U')
68712111Sralph 			(void) unlink(line+1);
68812111Sralph 	/*
68917463Sralph 	 * clean-up in case another control file exists
69012111Sralph 	 */
69112111Sralph 	(void) fclose(cfp);
69212111Sralph 	(void) unlink(file);
69317463Sralph 	return(err);
69412111Sralph }
69512111Sralph 
69612111Sralph /*
69712111Sralph  * Send a data file to the remote machine and spool it.
69812111Sralph  * Return positive if we should try resending.
69912111Sralph  */
70012111Sralph sendfile(type, file)
70112111Sralph 	char type, *file;
70212111Sralph {
70312111Sralph 	register int f, i, amt;
70412111Sralph 	struct stat stb;
70512111Sralph 	char buf[BUFSIZ];
70616762Sralph 	int sizerr, resp;
70712111Sralph 
70817463Sralph 	if (lstat(file, &stb) < 0 || (f = open(file, O_RDONLY)) < 0)
70917463Sralph 		return(ERROR);
71017463Sralph 	/*
71117463Sralph 	 * Check to see if data file is a symbolic link. If so, it should
71217463Sralph 	 * still point to the same file or someone is trying to print something
71317463Sralph 	 * he shouldn't.
71417463Sralph 	 */
71517463Sralph 	if ((stb.st_mode & S_IFMT) == S_IFLNK && fstat(f, &stb) == 0 &&
71617463Sralph 	    (stb.st_dev != fdev || stb.st_ino != fino))
71717463Sralph 		return(ACCESS);
71812111Sralph 	(void) sprintf(buf, "%c%d %s\n", type, stb.st_size, file);
71912111Sralph 	amt = strlen(buf);
72016762Sralph 	for (i = 0;  ; i++) {
72116762Sralph 		if (write(pfd, buf, amt) != amt ||
72216762Sralph 		    (resp = response()) < 0 || resp == '\1') {
72316762Sralph 			(void) close(f);
72417463Sralph 			return(REPRINT);
72516762Sralph 		} else if (resp == '\0')
72616762Sralph 			break;
72716762Sralph 		if (i == 0)
72816762Sralph 			status("no space on remote; waiting for queue to drain");
72916762Sralph 		if (i == 10)
73016762Sralph 			syslog(LOG_SALERT, "%s: can't send to %s; queue full",
73116762Sralph 				printer, RM);
73216762Sralph 		sleep(5 * 60);
73312692Sralph 	}
73416762Sralph 	if (i)
73516762Sralph 		status("sending to %s", RM);
73612111Sralph 	sizerr = 0;
73712111Sralph 	for (i = 0; i < stb.st_size; i += BUFSIZ) {
73812111Sralph 		amt = BUFSIZ;
73912111Sralph 		if (i + amt > stb.st_size)
74012111Sralph 			amt = stb.st_size - i;
74112111Sralph 		if (sizerr == 0 && read(f, buf, amt) != amt)
74212111Sralph 			sizerr = 1;
74312692Sralph 		if (write(pfd, buf, amt) != amt) {
74412692Sralph 			(void) close(f);
74517463Sralph 			return(REPRINT);
74612692Sralph 		}
74712111Sralph 	}
74812111Sralph 	(void) close(f);
74912111Sralph 	if (sizerr) {
75016762Sralph 		syslog(LOG_INFO, "%s: %s: changed size", printer, file);
75117463Sralph 		/* tell recvjob to ignore this file */
75217463Sralph 		(void) write(pfd, "\1", 1);
75317463Sralph 		return(ERROR);
75417463Sralph 	}
75517463Sralph 	if (write(pfd, "", 1) != 1 || response())
75617463Sralph 		return(REPRINT);
75717463Sralph 	return(OK);
75812111Sralph }
75912111Sralph 
76012111Sralph /*
76112111Sralph  * Check to make sure there have been no errors and that both programs
76212111Sralph  * are in sync with eachother.
76312111Sralph  * Return non-zero if the connection was lost.
76412111Sralph  */
76516762Sralph response()
76612111Sralph {
76712111Sralph 	char resp;
76812111Sralph 
76916762Sralph 	if (read(pfd, &resp, 1) != 1) {
77016762Sralph 		syslog(LOG_INFO, "%s: lost connection", printer);
77116762Sralph 		return(-1);
77212111Sralph 	}
77316762Sralph 	return(resp);
77412111Sralph }
77512111Sralph 
77612111Sralph /*
77712111Sralph  * Banner printing stuff
77812111Sralph  */
77912111Sralph banner(name1, name2)
78012111Sralph 	char *name1, *name2;
78112111Sralph {
78212111Sralph 	time_t tvec;
78312111Sralph 	extern char *ctime();
78412111Sralph 
78512111Sralph 	time(&tvec);
78612111Sralph 	if (!SF && !tof)
78712111Sralph 		(void) write(ofd, FF, strlen(FF));
78812111Sralph 	if (SB) {	/* short banner only */
78912111Sralph 		if (class[0]) {
79012111Sralph 			(void) write(ofd, class, strlen(class));
79112111Sralph 			(void) write(ofd, ":", 1);
79212111Sralph 		}
79312111Sralph 		(void) write(ofd, name1, strlen(name1));
79412111Sralph 		(void) write(ofd, "  Job: ", 7);
79512111Sralph 		(void) write(ofd, name2, strlen(name2));
79612111Sralph 		(void) write(ofd, "  Date: ", 8);
79712111Sralph 		(void) write(ofd, ctime(&tvec), 24);
79812111Sralph 		(void) write(ofd, "\n", 1);
79912111Sralph 	} else {	/* normal banner */
80012111Sralph 		(void) write(ofd, "\n\n\n", 3);
80112111Sralph 		scan_out(ofd, name1, '\0');
80212111Sralph 		(void) write(ofd, "\n\n", 2);
80312111Sralph 		scan_out(ofd, name2, '\0');
80412111Sralph 		if (class[0]) {
80512111Sralph 			(void) write(ofd,"\n\n\n",3);
80612111Sralph 			scan_out(ofd, class, '\0');
80712111Sralph 		}
80812111Sralph 		(void) write(ofd, "\n\n\n\n\t\t\t\t\tJob:  ", 15);
80912111Sralph 		(void) write(ofd, name2, strlen(name2));
81012111Sralph 		(void) write(ofd, "\n\t\t\t\t\tDate: ", 12);
81112111Sralph 		(void) write(ofd, ctime(&tvec), 24);
81212111Sralph 		(void) write(ofd, "\n", 1);
81312111Sralph 	}
81412111Sralph 	if (!SF)
81512111Sralph 		(void) write(ofd, FF, strlen(FF));
81612111Sralph 	tof = 1;
81712111Sralph }
81812111Sralph 
81916762Sralph char *
82012111Sralph scnline(key, p, c)
82112111Sralph 	register char key, *p;
82212111Sralph 	char c;
82312111Sralph {
82412111Sralph 	register scnwidth;
82512111Sralph 
82612111Sralph 	for (scnwidth = WIDTH; --scnwidth;) {
82712111Sralph 		key <<= 1;
82812111Sralph 		*p++ = key & 0200 ? c : BACKGND;
82912111Sralph 	}
83012111Sralph 	return (p);
83112111Sralph }
83212111Sralph 
83312111Sralph #define TRC(q)	(((q)-' ')&0177)
83412111Sralph 
83512111Sralph scan_out(scfd, scsp, dlm)
83612111Sralph 	int scfd;
83712111Sralph 	char *scsp, dlm;
83812111Sralph {
83912111Sralph 	register char *strp;
84012111Sralph 	register nchrs, j;
84112111Sralph 	char outbuf[LINELEN+1], *sp, c, cc;
84212111Sralph 	int d, scnhgt;
84312111Sralph 	extern char scnkey[][HEIGHT];	/* in lpdchar.c */
84412111Sralph 
84512111Sralph 	for (scnhgt = 0; scnhgt++ < HEIGHT+DROP; ) {
84612111Sralph 		strp = &outbuf[0];
84712111Sralph 		sp = scsp;
84812111Sralph 		for (nchrs = 0; ; ) {
84912111Sralph 			d = dropit(c = TRC(cc = *sp++));
85012111Sralph 			if ((!d && scnhgt > HEIGHT) || (scnhgt <= DROP && d))
85112111Sralph 				for (j = WIDTH; --j;)
85212111Sralph 					*strp++ = BACKGND;
85312111Sralph 			else
85412111Sralph 				strp = scnline(scnkey[c][scnhgt-1-d], strp, cc);
85512111Sralph 			if (*sp == dlm || *sp == '\0' || nchrs++ >= PW/(WIDTH+1)-1)
85612111Sralph 				break;
85712111Sralph 			*strp++ = BACKGND;
85812111Sralph 			*strp++ = BACKGND;
85912111Sralph 		}
86012111Sralph 		while (*--strp == BACKGND && strp >= outbuf)
86112111Sralph 			;
86212111Sralph 		strp++;
86312111Sralph 		*strp++ = '\n';
86412111Sralph 		(void) write(scfd, outbuf, strp-outbuf);
86512111Sralph 	}
86612111Sralph }
86712111Sralph 
86812111Sralph dropit(c)
86912111Sralph 	char c;
87012111Sralph {
87112111Sralph 	switch(c) {
87212111Sralph 
87312111Sralph 	case TRC('_'):
87412111Sralph 	case TRC(';'):
87512111Sralph 	case TRC(','):
87612111Sralph 	case TRC('g'):
87712111Sralph 	case TRC('j'):
87812111Sralph 	case TRC('p'):
87912111Sralph 	case TRC('q'):
88012111Sralph 	case TRC('y'):
88112111Sralph 		return (DROP);
88212111Sralph 
88312111Sralph 	default:
88412111Sralph 		return (0);
88512111Sralph 	}
88612111Sralph }
88712111Sralph 
88812111Sralph /*
88912111Sralph  * sendmail ---
89012111Sralph  *   tell people about job completion
89112111Sralph  */
89215811Sralph sendmail(user, bombed)
89315811Sralph 	char *user;
89412111Sralph 	int bombed;
89512111Sralph {
89612111Sralph 	register int i;
89715811Sralph 	int p[2], s;
89812111Sralph 	register char *cp;
89912111Sralph 	char buf[100];
90015811Sralph 	struct stat stb;
90115811Sralph 	FILE *fp;
90212111Sralph 
90312111Sralph 	pipe(p);
90415811Sralph 	if ((s = dofork(DORETURN)) == 0) {		/* child */
90512111Sralph 		dup2(p[0], 0);
90612111Sralph 		for (i = 3; i < NOFILE; i++)
90712111Sralph 			(void) close(i);
90812111Sralph 		if ((cp = rindex(MAIL, '/')) != NULL)
90912111Sralph 			cp++;
91012111Sralph 		else
91112111Sralph 			cp = MAIL;
91215811Sralph 		sprintf(buf, "%s@%s", user, fromhost);
91312111Sralph 		execl(MAIL, cp, buf, 0);
91412111Sralph 		exit(0);
91515811Sralph 	} else if (s > 0) {				/* parent */
91612111Sralph 		dup2(p[1], 1);
91715811Sralph 		printf("To: %s@%s\n", user, fromhost);
91812111Sralph 		printf("Subject: printer job\n\n");
91912111Sralph 		printf("Your printer job ");
92012111Sralph 		if (*jobname)
92112111Sralph 			printf("(%s) ", jobname);
92212463Sralph 		switch (bombed) {
92317463Sralph 		case OK:
92412463Sralph 			printf("\ncompleted successfully\n");
92512463Sralph 			break;
92612463Sralph 		default:
92717463Sralph 		case FATALERR:
92812463Sralph 			printf("\ncould not be printed\n");
92912463Sralph 			break;
93017463Sralph 		case NOACCT:
93112463Sralph 			printf("\ncould not be printed without an account on %s\n", host);
93212463Sralph 			break;
93317463Sralph 		case FILTERERR:
93415811Sralph 			if (stat(tmpfile, &stb) < 0 || stb.st_size == 0 ||
93515811Sralph 			    (fp = fopen(tmpfile, "r")) == NULL) {
93615811Sralph 				printf("\nwas printed but had some errors\n");
93715811Sralph 				break;
93815811Sralph 			}
93915811Sralph 			printf("\nwas printed but had the following errors:\n");
94015811Sralph 			while ((i = getc(fp)) != EOF)
94115811Sralph 				putchar(i);
94215811Sralph 			(void) fclose(fp);
94317463Sralph 			break;
94417463Sralph 		case ACCESS:
94517463Sralph 			printf("\nwas not printed because it was not linked to the original file\n");
94612463Sralph 		}
94712111Sralph 		fflush(stdout);
94812111Sralph 		(void) close(1);
94912111Sralph 	}
95012111Sralph 	(void) close(p[0]);
95112111Sralph 	(void) close(p[1]);
95215811Sralph 	wait(&s);
95312111Sralph }
95412111Sralph 
95512111Sralph /*
95612111Sralph  * dofork - fork with retries on failure
95712111Sralph  */
95812111Sralph dofork(action)
95912111Sralph 	int action;
96012111Sralph {
96112111Sralph 	register int i, pid;
96212111Sralph 
96312111Sralph 	for (i = 0; i < 20; i++) {
96412463Sralph 		if ((pid = fork()) < 0) {
96512111Sralph 			sleep((unsigned)(i*i));
96612463Sralph 			continue;
96712463Sralph 		}
96812463Sralph 		/*
96912463Sralph 		 * Child should run as daemon instead of root
97012463Sralph 		 */
97112463Sralph 		if (pid == 0)
97212463Sralph 			setuid(DU);
97312463Sralph 		return(pid);
97412111Sralph 	}
97516762Sralph 	syslog(LOG_ERR, "can't fork");
97612111Sralph 
97712111Sralph 	switch (action) {
97812111Sralph 	case DORETURN:
97912111Sralph 		return (-1);
98012111Sralph 	default:
98116762Sralph 		syslog(LOG_ERR, "bad action (%d) to dofork", action);
98212111Sralph 		/*FALL THRU*/
98312111Sralph 	case DOABORT:
98412111Sralph 		exit(1);
98512111Sralph 	}
98612111Sralph 	/*NOTREACHED*/
98712111Sralph }
98812111Sralph 
98912111Sralph /*
99016762Sralph  * Kill child processes to abort current job.
99112111Sralph  */
99216762Sralph abortpr()
99312111Sralph {
99415811Sralph 	(void) unlink(tmpfile);
99512111Sralph 	kill(0, SIGINT);
99612111Sralph 	if (ofilter > 0)
99712111Sralph 		kill(ofilter, SIGCONT);
99812111Sralph 	while (wait(0) > 0)
99912111Sralph 		;
100012111Sralph 	exit(0);
100112111Sralph }
100212111Sralph 
100312111Sralph init()
100412111Sralph {
100512111Sralph 	int status;
100612111Sralph 
100713169Sralph 	if ((status = pgetent(line, printer)) < 0)
100813169Sralph 		fatal("can't open printer description file");
100913169Sralph 	else if (status == 0)
101013169Sralph 		fatal("unknown printer");
101112111Sralph 	if ((LP = pgetstr("lp", &bp)) == NULL)
101212111Sralph 		LP = DEFDEVLP;
101312111Sralph 	if ((RP = pgetstr("rp", &bp)) == NULL)
101412463Sralph 		RP = DEFLP;
101512111Sralph 	if ((LO = pgetstr("lo", &bp)) == NULL)
101612111Sralph 		LO = DEFLOCK;
101712111Sralph 	if ((ST = pgetstr("st", &bp)) == NULL)
101812111Sralph 		ST = DEFSTAT;
101912111Sralph 	if ((LF = pgetstr("lf", &bp)) == NULL)
102012111Sralph 		LF = DEFLOGF;
102112111Sralph 	if ((SD = pgetstr("sd", &bp)) == NULL)
102212111Sralph 		SD = DEFSPOOL;
102312111Sralph 	if ((DU = pgetnum("du")) < 0)
102412111Sralph 		DU = DEFUID;
102512111Sralph 	if ((FF = pgetstr("ff", &bp)) == NULL)
102612111Sralph 		FF = DEFFF;
102712111Sralph 	if ((PW = pgetnum("pw")) < 0)
102812111Sralph 		PW = DEFWIDTH;
102912111Sralph 	sprintf(&width[2], "%d", PW);
103012111Sralph 	if ((PL = pgetnum("pl")) < 0)
103112111Sralph 		PL = DEFLENGTH;
103212111Sralph 	sprintf(&length[2], "%d", PL);
103312463Sralph 	if ((PX = pgetnum("px")) < 0)
103412463Sralph 		PX = 0;
103512463Sralph 	sprintf(&pxwidth[2], "%d", PX);
103612463Sralph 	if ((PY = pgetnum("py")) < 0)
103712463Sralph 		PY = 0;
103812463Sralph 	sprintf(&pxlength[2], "%d", PY);
103912111Sralph 	RM = pgetstr("rm", &bp);
104012111Sralph 	AF = pgetstr("af", &bp);
104112111Sralph 	OF = pgetstr("of", &bp);
104212111Sralph 	IF = pgetstr("if", &bp);
104312463Sralph 	RF = pgetstr("rf", &bp);
104412111Sralph 	TF = pgetstr("tf", &bp);
104513233Sralph 	NF = pgetstr("nf", &bp);
104612111Sralph 	DF = pgetstr("df", &bp);
104712111Sralph 	GF = pgetstr("gf", &bp);
104812111Sralph 	VF = pgetstr("vf", &bp);
104912111Sralph 	CF = pgetstr("cf", &bp);
105012111Sralph 	TR = pgetstr("tr", &bp);
105112463Sralph 	RS = pgetflag("rs");
105212111Sralph 	SF = pgetflag("sf");
105312111Sralph 	SH = pgetflag("sh");
105412111Sralph 	SB = pgetflag("sb");
105518127Sralph 	HL = pgetflag("hl");
105612111Sralph 	RW = pgetflag("rw");
105712111Sralph 	BR = pgetnum("br");
105812111Sralph 	if ((FC = pgetnum("fc")) < 0)
105912111Sralph 		FC = 0;
106012111Sralph 	if ((FS = pgetnum("fs")) < 0)
106112111Sralph 		FS = 0;
106212111Sralph 	if ((XC = pgetnum("xc")) < 0)
106312111Sralph 		XC = 0;
106412111Sralph 	if ((XS = pgetnum("xs")) < 0)
106512111Sralph 		XS = 0;
106612581Sralph 	tof = !pgetflag("fo");
106712111Sralph }
106812111Sralph 
106912463Sralph /*
107012463Sralph  * Acquire line printer or remote connection.
107112463Sralph  */
107212463Sralph openpr()
107312463Sralph {
107412463Sralph 	register int i, n;
107516762Sralph 	int resp;
107612463Sralph 
107712463Sralph 	if (*LP) {
107812463Sralph 		for (i = 1; ; i = i < 32 ? i << 1 : i) {
107913148Ssam 			pfd = open(LP, RW ? O_RDWR : O_WRONLY);
108012463Sralph 			if (pfd >= 0)
108112463Sralph 				break;
108212463Sralph 			if (errno == ENOENT) {
108316762Sralph 				syslog(LOG_ERR, "%s: %m", LP);
108412463Sralph 				exit(1);
108512463Sralph 			}
108612463Sralph 			if (i == 1)
108712463Sralph 				status("waiting for %s to become ready (offline ?)", printer);
108812463Sralph 			sleep(i);
108912463Sralph 		}
109012463Sralph 		if (isatty(pfd))
109112463Sralph 			setty();
109212463Sralph 		status("%s is ready and printing", printer);
109312463Sralph 	} else if (RM != NULL) {
109416762Sralph 		for (i = 1; ; i = i < 256 ? i << 1 : i) {
109516762Sralph 			resp = -1;
109612528Sralph 			pfd = getport(RM);
109712463Sralph 			if (pfd >= 0) {
109812463Sralph 				(void) sprintf(line, "\2%s\n", RP);
109912463Sralph 				n = strlen(line);
110016762Sralph 				if (write(pfd, line, n) == n &&
110116762Sralph 				    (resp = response()) == '\0')
110212463Sralph 					break;
110316031Sralph 				(void) close(pfd);
110412463Sralph 			}
110516031Sralph 			if (i == 1) {
110616762Sralph 				if (resp < 0)
110716031Sralph 					status("waiting for %s to come up", RM);
110816762Sralph 				else {
110916031Sralph 					status("waiting for queue to be enabled on %s", RM);
111016762Sralph 					i = 256;
111116762Sralph 				}
111216031Sralph 			}
111312463Sralph 			sleep(i);
111412463Sralph 		}
111512463Sralph 		status("sending to %s", RM);
111612463Sralph 		remote = 1;
111712463Sralph 	} else {
111816762Sralph 		syslog(LOG_ERR, "%s: no line printer device or host name",
111916762Sralph 			printer);
112012463Sralph 		exit(1);
112112463Sralph 	}
112212463Sralph 	/*
112312463Sralph 	 * Start up an output filter, if needed.
112412463Sralph 	 */
112512463Sralph 	if (OF) {
112612463Sralph 		int p[2];
112712463Sralph 		char *cp;
112812463Sralph 
112912463Sralph 		pipe(p);
113012463Sralph 		if ((ofilter = dofork(DOABORT)) == 0) {	/* child */
113112463Sralph 			dup2(p[0], 0);		/* pipe is std in */
113212463Sralph 			dup2(pfd, 1);		/* printer is std out */
113312463Sralph 			for (i = 3; i < NOFILE; i++)
113412463Sralph 				(void) close(i);
113512463Sralph 			if ((cp = rindex(OF, '/')) == NULL)
113612463Sralph 				cp = OF;
113712463Sralph 			else
113812463Sralph 				cp++;
113912463Sralph 			execl(OF, cp, width, length, 0);
114016762Sralph 			syslog(LOG_ERR, "%s: %s: %m", printer, OF);
114112463Sralph 			exit(1);
114212463Sralph 		}
114312463Sralph 		(void) close(p[0]);		/* close input side */
114412463Sralph 		ofd = p[1];			/* use pipe for output */
114512463Sralph 	} else {
114612463Sralph 		ofd = pfd;
114712463Sralph 		ofilter = 0;
114812463Sralph 	}
114912463Sralph }
115012463Sralph 
115112111Sralph struct bauds {
115212111Sralph 	int	baud;
115312111Sralph 	int	speed;
115412111Sralph } bauds[] = {
115512111Sralph 	50,	B50,
115612111Sralph 	75,	B75,
115712111Sralph 	110,	B110,
115812111Sralph 	134,	B134,
115912111Sralph 	150,	B150,
116012111Sralph 	200,	B200,
116112111Sralph 	300,	B300,
116212111Sralph 	600,	B600,
116312111Sralph 	1200,	B1200,
116412111Sralph 	1800,	B1800,
116512111Sralph 	2400,	B2400,
116612111Sralph 	4800,	B4800,
116712111Sralph 	9600,	B9600,
116812111Sralph 	19200,	EXTA,
116912111Sralph 	38400,	EXTB,
117012111Sralph 	0,	0
117112111Sralph };
117212111Sralph 
117312111Sralph /*
117412111Sralph  * setup tty lines.
117512111Sralph  */
117612111Sralph setty()
117712111Sralph {
117812111Sralph 	struct sgttyb ttybuf;
117912111Sralph 	register struct bauds *bp;
118012111Sralph 
118112111Sralph 	if (ioctl(pfd, TIOCEXCL, (char *)0) < 0) {
118216762Sralph 		syslog(LOG_ERR, "%s: ioctl(TIOCEXCL): %m", printer);
118312111Sralph 		exit(1);
118412111Sralph 	}
118512111Sralph 	if (ioctl(pfd, TIOCGETP, (char *)&ttybuf) < 0) {
118616762Sralph 		syslog(LOG_ERR, "%s: ioctl(TIOCGETP): %m", printer);
118712111Sralph 		exit(1);
118812111Sralph 	}
118912111Sralph 	if (BR > 0) {
119012111Sralph 		for (bp = bauds; bp->baud; bp++)
119112111Sralph 			if (BR == bp->baud)
119212111Sralph 				break;
119312111Sralph 		if (!bp->baud) {
119416762Sralph 			syslog(LOG_ERR, "%s: illegal baud rate %d", printer, BR);
119512111Sralph 			exit(1);
119612111Sralph 		}
119712111Sralph 		ttybuf.sg_ispeed = ttybuf.sg_ospeed = bp->speed;
119812111Sralph 	}
119913169Sralph 	ttybuf.sg_flags &= ~FC;
120013169Sralph 	ttybuf.sg_flags |= FS;
120112111Sralph 	if (ioctl(pfd, TIOCSETP, (char *)&ttybuf) < 0) {
120216762Sralph 		syslog(LOG_ERR, "%s: ioctl(TIOCSETP): %m", printer);
120312111Sralph 		exit(1);
120412111Sralph 	}
120517168Sralph 	if (XC || XS) {
120617168Sralph 		int ldisc = NTTYDISC;
120717168Sralph 
120817168Sralph 		if (ioctl(pfd, TIOCSETD, &ldisc) < 0) {
120917168Sralph 			syslog(LOG_ERR, "%s: ioctl(TIOCSETD): %m", printer);
121017168Sralph 			exit(1);
121117168Sralph 		}
121217168Sralph 	}
121312111Sralph 	if (XC) {
121412111Sralph 		if (ioctl(pfd, TIOCLBIC, &XC) < 0) {
121516762Sralph 			syslog(LOG_ERR, "%s: ioctl(TIOCLBIC): %m", printer);
121612111Sralph 			exit(1);
121712111Sralph 		}
121812111Sralph 	}
121912111Sralph 	if (XS) {
122012111Sralph 		if (ioctl(pfd, TIOCLBIS, &XS) < 0) {
122116762Sralph 			syslog(LOG_ERR, "%s: ioctl(TIOCLBIS): %m", printer);
122212111Sralph 			exit(1);
122312111Sralph 		}
122412111Sralph 	}
122512111Sralph }
122612463Sralph 
122712463Sralph /*VARARGS1*/
122812463Sralph status(msg, a1, a2, a3)
122912463Sralph 	char *msg;
123012463Sralph {
123112463Sralph 	register int fd;
123212463Sralph 	char buf[BUFSIZ];
123312463Sralph 
123412463Sralph 	umask(0);
123513148Ssam 	fd = open(ST, O_WRONLY|O_CREAT, 0664);
123616762Sralph 	if (fd < 0 || flock(fd, LOCK_EX) < 0) {
123716762Sralph 		syslog(LOG_ERR, "%s: %s: %m", printer, ST);
123816762Sralph 		exit(1);
123916762Sralph 	}
124013148Ssam 	ftruncate(fd, 0);
124112463Sralph 	sprintf(buf, msg, a1, a2, a3);
124212463Sralph 	strcat(buf, "\n");
124312463Sralph 	(void) write(fd, buf, strlen(buf));
124412463Sralph 	(void) close(fd);
124512463Sralph }
1246