xref: /csrg-svn/usr.sbin/lpr/lpd/printjob.c (revision 25468)
122437Sdist /*
222437Sdist  * Copyright (c) 1983 Regents of the University of California.
322437Sdist  * All rights reserved.  The Berkeley software License Agreement
422437Sdist  * specifies the terms and conditions for redistribution.
522437Sdist  */
622437Sdist 
713954Ssam #ifndef lint
8*25468Stef static char sccsid[] = "@(#)printjob.c	5.2 (Berkeley) 9/17/85";
922437Sdist #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)
73024861Seric 			syslog(LOG_ALERT, "%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 
1007*25468Stef 	if ((status = pgetent(line, printer)) < 0) {
1008*25468Stef 		syslog(LOG_ERR, "can't open printer description file");
1009*25468Stef 		exit(1);
1010*25468Stef 	} else if (status == 0) {
1011*25468Stef 		syslog(LOG_ERR, "unknown printer: %s", printer);
1012*25468Stef 		exit(1);
1013*25468Stef 	}
101412111Sralph 	if ((LP = pgetstr("lp", &bp)) == NULL)
101512111Sralph 		LP = DEFDEVLP;
101612111Sralph 	if ((RP = pgetstr("rp", &bp)) == NULL)
101712463Sralph 		RP = DEFLP;
101812111Sralph 	if ((LO = pgetstr("lo", &bp)) == NULL)
101912111Sralph 		LO = DEFLOCK;
102012111Sralph 	if ((ST = pgetstr("st", &bp)) == NULL)
102112111Sralph 		ST = DEFSTAT;
102212111Sralph 	if ((LF = pgetstr("lf", &bp)) == NULL)
102312111Sralph 		LF = DEFLOGF;
102412111Sralph 	if ((SD = pgetstr("sd", &bp)) == NULL)
102512111Sralph 		SD = DEFSPOOL;
102612111Sralph 	if ((DU = pgetnum("du")) < 0)
102712111Sralph 		DU = DEFUID;
102812111Sralph 	if ((FF = pgetstr("ff", &bp)) == NULL)
102912111Sralph 		FF = DEFFF;
103012111Sralph 	if ((PW = pgetnum("pw")) < 0)
103112111Sralph 		PW = DEFWIDTH;
103212111Sralph 	sprintf(&width[2], "%d", PW);
103312111Sralph 	if ((PL = pgetnum("pl")) < 0)
103412111Sralph 		PL = DEFLENGTH;
103512111Sralph 	sprintf(&length[2], "%d", PL);
103612463Sralph 	if ((PX = pgetnum("px")) < 0)
103712463Sralph 		PX = 0;
103812463Sralph 	sprintf(&pxwidth[2], "%d", PX);
103912463Sralph 	if ((PY = pgetnum("py")) < 0)
104012463Sralph 		PY = 0;
104112463Sralph 	sprintf(&pxlength[2], "%d", PY);
104212111Sralph 	RM = pgetstr("rm", &bp);
1043*25468Stef 	/*
1044*25468Stef 	 * Figure out whether the local machine is the same as the remote
1045*25468Stef 	 * machine entry (if it exists).  If not, then ignore the local
1046*25468Stef 	 * queue information.
1047*25468Stef 	 */
1048*25468Stef 	 if (RM != (char *) NULL) {
1049*25468Stef 		char name[256];
1050*25468Stef 		struct hostent *hp;
1051*25468Stef 
1052*25468Stef 		/* get the standard network name of the local host */
1053*25468Stef 		gethostname(name, sizeof(name));
1054*25468Stef 		name[sizeof(name)-1] = '\0';
1055*25468Stef 		hp = gethostbyname(name);
1056*25468Stef 		if (hp == (struct hostent *) NULL) {
1057*25468Stef 		    syslog(LOG_ERR,
1058*25468Stef 			"unable to get network name for local machine %s",
1059*25468Stef 			name);
1060*25468Stef 		    goto localcheck_done;
1061*25468Stef 		} else strcpy(name, hp->h_name);
1062*25468Stef 
1063*25468Stef 		/* get the standard network name of RM */
1064*25468Stef 		hp = gethostbyname(RM);
1065*25468Stef 		if (hp == (struct hostent *) NULL) {
1066*25468Stef 		    syslog(LOG_ERR,
1067*25468Stef 			"unable to get hostname for remote machine %s", RM);
1068*25468Stef 		    goto localcheck_done;
1069*25468Stef 		}
1070*25468Stef 
1071*25468Stef 		/* if printer is not on local machine, ignore LP */
1072*25468Stef 		if (strcmp(name, hp->h_name) != 0) *LP = '\0';
1073*25468Stef 	}
1074*25468Stef localcheck_done:
1075*25468Stef 
107612111Sralph 	AF = pgetstr("af", &bp);
107712111Sralph 	OF = pgetstr("of", &bp);
107812111Sralph 	IF = pgetstr("if", &bp);
107912463Sralph 	RF = pgetstr("rf", &bp);
108012111Sralph 	TF = pgetstr("tf", &bp);
108113233Sralph 	NF = pgetstr("nf", &bp);
108212111Sralph 	DF = pgetstr("df", &bp);
108312111Sralph 	GF = pgetstr("gf", &bp);
108412111Sralph 	VF = pgetstr("vf", &bp);
108512111Sralph 	CF = pgetstr("cf", &bp);
108612111Sralph 	TR = pgetstr("tr", &bp);
108712463Sralph 	RS = pgetflag("rs");
108812111Sralph 	SF = pgetflag("sf");
108912111Sralph 	SH = pgetflag("sh");
109012111Sralph 	SB = pgetflag("sb");
109118127Sralph 	HL = pgetflag("hl");
109212111Sralph 	RW = pgetflag("rw");
109312111Sralph 	BR = pgetnum("br");
109412111Sralph 	if ((FC = pgetnum("fc")) < 0)
109512111Sralph 		FC = 0;
109612111Sralph 	if ((FS = pgetnum("fs")) < 0)
109712111Sralph 		FS = 0;
109812111Sralph 	if ((XC = pgetnum("xc")) < 0)
109912111Sralph 		XC = 0;
110012111Sralph 	if ((XS = pgetnum("xs")) < 0)
110112111Sralph 		XS = 0;
110212581Sralph 	tof = !pgetflag("fo");
110312111Sralph }
110412111Sralph 
110512463Sralph /*
110612463Sralph  * Acquire line printer or remote connection.
110712463Sralph  */
110812463Sralph openpr()
110912463Sralph {
111012463Sralph 	register int i, n;
111116762Sralph 	int resp;
111212463Sralph 
111312463Sralph 	if (*LP) {
111412463Sralph 		for (i = 1; ; i = i < 32 ? i << 1 : i) {
111513148Ssam 			pfd = open(LP, RW ? O_RDWR : O_WRONLY);
111612463Sralph 			if (pfd >= 0)
111712463Sralph 				break;
111812463Sralph 			if (errno == ENOENT) {
111916762Sralph 				syslog(LOG_ERR, "%s: %m", LP);
112012463Sralph 				exit(1);
112112463Sralph 			}
112212463Sralph 			if (i == 1)
112312463Sralph 				status("waiting for %s to become ready (offline ?)", printer);
112412463Sralph 			sleep(i);
112512463Sralph 		}
112612463Sralph 		if (isatty(pfd))
112712463Sralph 			setty();
112812463Sralph 		status("%s is ready and printing", printer);
112912463Sralph 	} else if (RM != NULL) {
113016762Sralph 		for (i = 1; ; i = i < 256 ? i << 1 : i) {
113116762Sralph 			resp = -1;
113212528Sralph 			pfd = getport(RM);
113312463Sralph 			if (pfd >= 0) {
113412463Sralph 				(void) sprintf(line, "\2%s\n", RP);
113512463Sralph 				n = strlen(line);
113616762Sralph 				if (write(pfd, line, n) == n &&
113716762Sralph 				    (resp = response()) == '\0')
113812463Sralph 					break;
113916031Sralph 				(void) close(pfd);
114012463Sralph 			}
114116031Sralph 			if (i == 1) {
114216762Sralph 				if (resp < 0)
114316031Sralph 					status("waiting for %s to come up", RM);
114416762Sralph 				else {
114516031Sralph 					status("waiting for queue to be enabled on %s", RM);
114616762Sralph 					i = 256;
114716762Sralph 				}
114816031Sralph 			}
114912463Sralph 			sleep(i);
115012463Sralph 		}
115112463Sralph 		status("sending to %s", RM);
115212463Sralph 		remote = 1;
115312463Sralph 	} else {
115416762Sralph 		syslog(LOG_ERR, "%s: no line printer device or host name",
115516762Sralph 			printer);
115612463Sralph 		exit(1);
115712463Sralph 	}
115812463Sralph 	/*
115912463Sralph 	 * Start up an output filter, if needed.
116012463Sralph 	 */
116112463Sralph 	if (OF) {
116212463Sralph 		int p[2];
116312463Sralph 		char *cp;
116412463Sralph 
116512463Sralph 		pipe(p);
116612463Sralph 		if ((ofilter = dofork(DOABORT)) == 0) {	/* child */
116712463Sralph 			dup2(p[0], 0);		/* pipe is std in */
116812463Sralph 			dup2(pfd, 1);		/* printer is std out */
116912463Sralph 			for (i = 3; i < NOFILE; i++)
117012463Sralph 				(void) close(i);
117112463Sralph 			if ((cp = rindex(OF, '/')) == NULL)
117212463Sralph 				cp = OF;
117312463Sralph 			else
117412463Sralph 				cp++;
117512463Sralph 			execl(OF, cp, width, length, 0);
117616762Sralph 			syslog(LOG_ERR, "%s: %s: %m", printer, OF);
117712463Sralph 			exit(1);
117812463Sralph 		}
117912463Sralph 		(void) close(p[0]);		/* close input side */
118012463Sralph 		ofd = p[1];			/* use pipe for output */
118112463Sralph 	} else {
118212463Sralph 		ofd = pfd;
118312463Sralph 		ofilter = 0;
118412463Sralph 	}
118512463Sralph }
118612463Sralph 
118712111Sralph struct bauds {
118812111Sralph 	int	baud;
118912111Sralph 	int	speed;
119012111Sralph } bauds[] = {
119112111Sralph 	50,	B50,
119212111Sralph 	75,	B75,
119312111Sralph 	110,	B110,
119412111Sralph 	134,	B134,
119512111Sralph 	150,	B150,
119612111Sralph 	200,	B200,
119712111Sralph 	300,	B300,
119812111Sralph 	600,	B600,
119912111Sralph 	1200,	B1200,
120012111Sralph 	1800,	B1800,
120112111Sralph 	2400,	B2400,
120212111Sralph 	4800,	B4800,
120312111Sralph 	9600,	B9600,
120412111Sralph 	19200,	EXTA,
120512111Sralph 	38400,	EXTB,
120612111Sralph 	0,	0
120712111Sralph };
120812111Sralph 
120912111Sralph /*
121012111Sralph  * setup tty lines.
121112111Sralph  */
121212111Sralph setty()
121312111Sralph {
121412111Sralph 	struct sgttyb ttybuf;
121512111Sralph 	register struct bauds *bp;
121612111Sralph 
121712111Sralph 	if (ioctl(pfd, TIOCEXCL, (char *)0) < 0) {
121816762Sralph 		syslog(LOG_ERR, "%s: ioctl(TIOCEXCL): %m", printer);
121912111Sralph 		exit(1);
122012111Sralph 	}
122112111Sralph 	if (ioctl(pfd, TIOCGETP, (char *)&ttybuf) < 0) {
122216762Sralph 		syslog(LOG_ERR, "%s: ioctl(TIOCGETP): %m", printer);
122312111Sralph 		exit(1);
122412111Sralph 	}
122512111Sralph 	if (BR > 0) {
122612111Sralph 		for (bp = bauds; bp->baud; bp++)
122712111Sralph 			if (BR == bp->baud)
122812111Sralph 				break;
122912111Sralph 		if (!bp->baud) {
123016762Sralph 			syslog(LOG_ERR, "%s: illegal baud rate %d", printer, BR);
123112111Sralph 			exit(1);
123212111Sralph 		}
123312111Sralph 		ttybuf.sg_ispeed = ttybuf.sg_ospeed = bp->speed;
123412111Sralph 	}
123513169Sralph 	ttybuf.sg_flags &= ~FC;
123613169Sralph 	ttybuf.sg_flags |= FS;
123712111Sralph 	if (ioctl(pfd, TIOCSETP, (char *)&ttybuf) < 0) {
123816762Sralph 		syslog(LOG_ERR, "%s: ioctl(TIOCSETP): %m", printer);
123912111Sralph 		exit(1);
124012111Sralph 	}
124117168Sralph 	if (XC || XS) {
124217168Sralph 		int ldisc = NTTYDISC;
124317168Sralph 
124417168Sralph 		if (ioctl(pfd, TIOCSETD, &ldisc) < 0) {
124517168Sralph 			syslog(LOG_ERR, "%s: ioctl(TIOCSETD): %m", printer);
124617168Sralph 			exit(1);
124717168Sralph 		}
124817168Sralph 	}
124912111Sralph 	if (XC) {
125012111Sralph 		if (ioctl(pfd, TIOCLBIC, &XC) < 0) {
125116762Sralph 			syslog(LOG_ERR, "%s: ioctl(TIOCLBIC): %m", printer);
125212111Sralph 			exit(1);
125312111Sralph 		}
125412111Sralph 	}
125512111Sralph 	if (XS) {
125612111Sralph 		if (ioctl(pfd, TIOCLBIS, &XS) < 0) {
125716762Sralph 			syslog(LOG_ERR, "%s: ioctl(TIOCLBIS): %m", printer);
125812111Sralph 			exit(1);
125912111Sralph 		}
126012111Sralph 	}
126112111Sralph }
126212463Sralph 
126312463Sralph /*VARARGS1*/
126412463Sralph status(msg, a1, a2, a3)
126512463Sralph 	char *msg;
126612463Sralph {
126712463Sralph 	register int fd;
126812463Sralph 	char buf[BUFSIZ];
126912463Sralph 
127012463Sralph 	umask(0);
127113148Ssam 	fd = open(ST, O_WRONLY|O_CREAT, 0664);
127216762Sralph 	if (fd < 0 || flock(fd, LOCK_EX) < 0) {
127316762Sralph 		syslog(LOG_ERR, "%s: %s: %m", printer, ST);
127416762Sralph 		exit(1);
127516762Sralph 	}
127613148Ssam 	ftruncate(fd, 0);
127712463Sralph 	sprintf(buf, msg, a1, a2, a3);
127812463Sralph 	strcat(buf, "\n");
127912463Sralph 	(void) write(fd, buf, strlen(buf));
128012463Sralph 	(void) close(fd);
128112463Sralph }
1282