xref: /csrg-svn/usr.sbin/lpr/lpd/printjob.c (revision 34203)
122437Sdist /*
222437Sdist  * Copyright (c) 1983 Regents of the University of California.
3*34203Sbostic  * All rights reserved.
4*34203Sbostic  *
5*34203Sbostic  * Redistribution and use in source and binary forms are permitted
6*34203Sbostic  * provided that this notice is preserved and that due credit is given
7*34203Sbostic  * to the University of California at Berkeley. The name of the University
8*34203Sbostic  * may not be used to endorse or promote products derived from this
9*34203Sbostic  * software without specific prior written permission. This software
10*34203Sbostic  * is provided ``as is'' without express or implied warranty.
1122437Sdist  */
1222437Sdist 
1313954Ssam #ifndef lint
14*34203Sbostic static char sccsid[] = "@(#)printjob.c	5.5 (Berkeley) 05/05/88";
15*34203Sbostic #endif /* not lint */
1613954Ssam 
1712111Sralph /*
1812111Sralph  * printjob -- print jobs in the queue.
1912111Sralph  *
2012111Sralph  *	NOTE: the lock file is used to pass information to lpq and lprm.
2112111Sralph  *	it does not need to be removed because file locks are dynamic.
2212111Sralph  */
2312111Sralph 
2412111Sralph #include "lp.h"
2512111Sralph 
2616762Sralph #define DORETURN	0	/* absorb fork error */
2716762Sralph #define DOABORT		1	/* abort if dofork fails */
2812111Sralph 
2917463Sralph /*
3017463Sralph  * Error tokens
3117463Sralph  */
3217463Sralph #define REPRINT		-2
3317463Sralph #define ERROR		-1
3417463Sralph #define	OK		0
3517463Sralph #define	FATALERR	1
3617463Sralph #define	NOACCT		2
3717463Sralph #define	FILTERERR	3
3817463Sralph #define	ACCESS		4
3917463Sralph 
4016762Sralph char	title[80];		/* ``pr'' title */
4116762Sralph FILE	*cfp;			/* control file */
4216762Sralph int	pfd;			/* printer file descriptor */
4316762Sralph int	ofd;			/* output filter file descriptor */
4416762Sralph int	lfd;			/* lock file descriptor */
4516762Sralph int	pid;			/* pid of lpd process */
4616762Sralph int	prchild;		/* id of pr process */
4716762Sralph int	child;			/* id of any filters */
4816762Sralph int	ofilter;		/* id of output filter, if any */
4916762Sralph int	tof;			/* true if at top of form */
5016762Sralph int	remote;			/* true if sending files to remote */
5117463Sralph dev_t	fdev;			/* device of file pointed to by symlink */
5217463Sralph ino_t	fino;			/* inode of file pointed to by symlink */
5312111Sralph 
5416762Sralph char	fromhost[32];		/* user's host machine */
5516762Sralph char	logname[32];		/* user's login name */
5616762Sralph char	jobname[100];		/* job or file name */
5716762Sralph char	class[32];		/* classification field */
5816762Sralph char	width[10] = "-w";	/* page width in characters */
5916762Sralph char	length[10] = "-l";	/* page length in lines */
6016762Sralph char	pxwidth[10] = "-x";	/* page width in pixels */
6116762Sralph char	pxlength[10] = "-y";	/* page length in pixels */
6216762Sralph char	indent[10] = "-i0";	/* indentation size in characters */
6316762Sralph char	tmpfile[] = "errsXXXXXX"; /* file name for filter output */
6412111Sralph 
6512111Sralph printjob()
6612111Sralph {
6712111Sralph 	struct stat stb;
6812111Sralph 	register struct queue *q, **qp;
6912111Sralph 	struct queue **queue;
7012111Sralph 	register int i, nitems;
7112111Sralph 	long pidoff;
7216762Sralph 	int count = 0;
7316762Sralph 	extern int abortpr();
7412111Sralph 
7512111Sralph 	init();					/* set up capabilities */
7613442Sralph 	(void) write(1, "", 1);			/* ack that daemon is started */
7725496Seric 	(void) close(2);			/* set up log file */
7825496Seric 	if (open(LF, O_WRONLY|O_APPEND, 0664) < 0) {
7925496Seric 		syslog(LOG_ERR, "%s: %m", LF);
8025496Seric 		(void) open("/dev/null", O_WRONLY);
8125496Seric 	}
8216762Sralph 	setgid(getegid());
8312463Sralph 	pid = getpid();				/* for use with lprm */
8412111Sralph 	setpgrp(0, pid);
8516762Sralph 	signal(SIGHUP, abortpr);
8616762Sralph 	signal(SIGINT, abortpr);
8716762Sralph 	signal(SIGQUIT, abortpr);
8816762Sralph 	signal(SIGTERM, abortpr);
8912111Sralph 
9015811Sralph 	(void) mktemp(tmpfile);
9115811Sralph 
9212111Sralph 	/*
9312111Sralph 	 * uses short form file names
9412111Sralph 	 */
9512111Sralph 	if (chdir(SD) < 0) {
9616762Sralph 		syslog(LOG_ERR, "%s: %m", SD);
9712111Sralph 		exit(1);
9812111Sralph 	}
9912463Sralph 	if (stat(LO, &stb) == 0 && (stb.st_mode & 0100))
10012463Sralph 		exit(0);		/* printing disabled */
10114150Sralph 	lfd = open(LO, O_WRONLY|O_CREAT, 0644);
10213169Sralph 	if (lfd < 0) {
10316762Sralph 		syslog(LOG_ERR, "%s: %s: %m", printer, LO);
10413169Sralph 		exit(1);
10513169Sralph 	}
10613169Sralph 	if (flock(lfd, LOCK_EX|LOCK_NB) < 0) {
10712111Sralph 		if (errno == EWOULDBLOCK)	/* active deamon present */
10812111Sralph 			exit(0);
10916762Sralph 		syslog(LOG_ERR, "%s: %s: %m", printer, LO);
11012111Sralph 		exit(1);
11112111Sralph 	}
11213148Ssam 	ftruncate(lfd, 0);
11312111Sralph 	/*
11412111Sralph 	 * write process id for others to know
11512111Sralph 	 */
11612111Sralph 	sprintf(line, "%u\n", pid);
11712111Sralph 	pidoff = i = strlen(line);
11812463Sralph 	if (write(lfd, line, i) != i) {
11916762Sralph 		syslog(LOG_ERR, "%s: %s: %m", printer, LO);
12012111Sralph 		exit(1);
12112111Sralph 	}
12212111Sralph 	/*
12312111Sralph 	 * search the spool directory for work and sort by queue order.
12412111Sralph 	 */
12512111Sralph 	if ((nitems = getq(&queue)) < 0) {
12616762Sralph 		syslog(LOG_ERR, "%s: can't scan %s", printer, SD);
12712111Sralph 		exit(1);
12812111Sralph 	}
12912463Sralph 	if (nitems == 0)		/* no work to do */
13012111Sralph 		exit(0);
13113169Sralph 	if (stb.st_mode & 01) {		/* reset queue flag */
13213169Sralph 		if (fchmod(lfd, stb.st_mode & 0776) < 0)
13316762Sralph 			syslog(LOG_ERR, "%s: %s: %m", printer, LO);
13413169Sralph 	}
13512463Sralph 	openpr();			/* open printer or remote */
13612463Sralph again:
13712111Sralph 	/*
13812111Sralph 	 * we found something to do now do it --
13912111Sralph 	 *    write the name of the current control file into the lock file
14012111Sralph 	 *    so the spool queue program can tell what we're working on
14112111Sralph 	 */
14212111Sralph 	for (qp = queue; nitems--; free((char *) q)) {
14312111Sralph 		q = *qp++;
14412111Sralph 		if (stat(q->q_name, &stb) < 0)
14512111Sralph 			continue;
14612463Sralph 	restart:
14712111Sralph 		(void) lseek(lfd, pidoff, 0);
14812111Sralph 		(void) sprintf(line, "%s\n", q->q_name);
14912111Sralph 		i = strlen(line);
15012111Sralph 		if (write(lfd, line, i) != i)
15116762Sralph 			syslog(LOG_ERR, "%s: %s: %m", printer, LO);
15212111Sralph 		if (!remote)
15312111Sralph 			i = printit(q->q_name);
15412111Sralph 		else
15512111Sralph 			i = sendit(q->q_name);
15612463Sralph 		/*
15713169Sralph 		 * Check to see if we are supposed to stop printing or
15813169Sralph 		 * if we are to rebuild the queue.
15912463Sralph 		 */
16013169Sralph 		if (fstat(lfd, &stb) == 0) {
16116762Sralph 			/* stop printing before starting next job? */
16213169Sralph 			if (stb.st_mode & 0100)
16313169Sralph 				goto done;
16416762Sralph 			/* rebuild queue (after lpc topq) */
16513169Sralph 			if (stb.st_mode & 01) {
16613169Sralph 				for (free((char *) q); nitems--; free((char *) q))
16713169Sralph 					q = *qp++;
16813169Sralph 				if (fchmod(lfd, stb.st_mode & 0776) < 0)
16916762Sralph 					syslog(LOG_WARNING, "%s: %s: %m",
17016762Sralph 						printer, LO);
17113169Sralph 				break;
17213169Sralph 			}
17313169Sralph 		}
17417463Sralph 		if (i == OK)		/* file ok and printed */
17514150Sralph 			count++;
17617463Sralph 		else if (i == REPRINT) { /* try reprinting the job */
17716762Sralph 			syslog(LOG_INFO, "restarting %s", printer);
17812111Sralph 			if (ofilter > 0) {
17912111Sralph 				kill(ofilter, SIGCONT);	/* to be sure */
18012111Sralph 				(void) close(ofd);
18112111Sralph 				while ((i = wait(0)) > 0 && i != ofilter)
18212111Sralph 					;
18312111Sralph 				ofilter = 0;
18412111Sralph 			}
18512463Sralph 			(void) close(pfd);	/* close printer */
18615811Sralph 			if (ftruncate(lfd, pidoff) < 0)
18716762Sralph 				syslog(LOG_WARNING, "%s: %s: %m", printer, LO);
18812463Sralph 			openpr();		/* try to reopen printer */
18912111Sralph 			goto restart;
19012111Sralph 		}
19112111Sralph 	}
19212111Sralph 	free((char *) queue);
19312463Sralph 	/*
19412463Sralph 	 * search the spool directory for more work.
19512463Sralph 	 */
19612463Sralph 	if ((nitems = getq(&queue)) < 0) {
19716762Sralph 		syslog(LOG_ERR, "%s: can't scan %s", printer, SD);
19812463Sralph 		exit(1);
19912463Sralph 	}
20012463Sralph 	if (nitems == 0) {		/* no more work to do */
20112463Sralph 	done:
20214150Sralph 		if (count > 0) {	/* Files actually printed */
20314150Sralph 			if (!SF && !tof)
20414150Sralph 				(void) write(ofd, FF, strlen(FF));
20514150Sralph 			if (TR != NULL)		/* output trailer */
20614150Sralph 				(void) write(ofd, TR, strlen(TR));
20714150Sralph 		}
20815811Sralph 		(void) unlink(tmpfile);
20912463Sralph 		exit(0);
21012463Sralph 	}
21112111Sralph 	goto again;
21212111Sralph }
21312111Sralph 
21412111Sralph char	fonts[4][50];	/* fonts for troff */
21512111Sralph 
21616762Sralph char ifonts[4][18] = {
21712111Sralph 	"/usr/lib/vfont/R",
21812111Sralph 	"/usr/lib/vfont/I",
21912111Sralph 	"/usr/lib/vfont/B",
22012111Sralph 	"/usr/lib/vfont/S"
22112111Sralph };
22212111Sralph 
22312111Sralph /*
22412111Sralph  * The remaining part is the reading of the control file (cf)
22512111Sralph  * and performing the various actions.
22612111Sralph  */
22712111Sralph printit(file)
22812111Sralph 	char *file;
22912111Sralph {
23012111Sralph 	register int i;
23117463Sralph 	char *cp;
23217463Sralph 	int bombed = OK;
23312111Sralph 
23412111Sralph 	/*
23517463Sralph 	 * open control file; ignore if no longer there.
23612111Sralph 	 */
23712111Sralph 	if ((cfp = fopen(file, "r")) == NULL) {
23816762Sralph 		syslog(LOG_INFO, "%s: %s: %m", printer, file);
23917463Sralph 		return(OK);
24012111Sralph 	}
24112111Sralph 	/*
24212111Sralph 	 * Reset troff fonts.
24312111Sralph 	 */
24412111Sralph 	for (i = 0; i < 4; i++)
24512111Sralph 		strcpy(fonts[i], ifonts[i]);
24617339Sralph 	strcpy(width+2, "0");
24717302Sralph 	strcpy(indent+2, "0");
24812111Sralph 
24912111Sralph 	/*
25012111Sralph 	 *      read the control file for work to do
25112111Sralph 	 *
25212111Sralph 	 *      file format -- first character in the line is a command
25312111Sralph 	 *      rest of the line is the argument.
25412111Sralph 	 *      valid commands are:
25512111Sralph 	 *
25617463Sralph 	 *		S -- "stat info" for symbolic link protection
25712111Sralph 	 *		J -- "job name" on banner page
25812111Sralph 	 *		C -- "class name" on banner page
25912111Sralph 	 *              L -- "literal" user's name to print on banner
26012111Sralph 	 *		T -- "title" for pr
26112111Sralph 	 *		H -- "host name" of machine where lpr was done
26212111Sralph 	 *              P -- "person" user's login name
26312581Sralph 	 *              I -- "indent" amount to indent output
26412111Sralph 	 *              f -- "file name" name of text file to print
26512111Sralph 	 *		l -- "file name" text file with control chars
26612111Sralph 	 *		p -- "file name" text file to print with pr(1)
26712111Sralph 	 *		t -- "file name" troff(1) file to print
26813233Sralph 	 *		n -- "file name" ditroff(1) file to print
26912111Sralph 	 *		d -- "file name" dvi file to print
27012111Sralph 	 *		g -- "file name" plot(1G) file to print
27112111Sralph 	 *		v -- "file name" plain raster file to print
27212111Sralph 	 *		c -- "file name" cifplot file to print
27312111Sralph 	 *		1 -- "R font file" for troff
27412111Sralph 	 *		2 -- "I font file" for troff
27512111Sralph 	 *		3 -- "B font file" for troff
27612111Sralph 	 *		4 -- "S font file" for troff
27712111Sralph 	 *		N -- "name" of file (used by lpq)
27812111Sralph 	 *              U -- "unlink" name of file to remove
27912111Sralph 	 *                    (after we print it. (Pass 2 only)).
28012111Sralph 	 *		M -- "mail" to user when done printing
28112111Sralph 	 *
28212111Sralph 	 *      getline reads a line and expands tabs to blanks
28312111Sralph 	 */
28412111Sralph 
28512111Sralph 	/* pass 1 */
28612111Sralph 
28712111Sralph 	while (getline(cfp))
28812111Sralph 		switch (line[0]) {
28912111Sralph 		case 'H':
29014150Sralph 			strcpy(fromhost, line+1);
29112111Sralph 			if (class[0] == '\0')
29215552Sralph 				strncpy(class, line+1, sizeof(class)-1);
29312111Sralph 			continue;
29412111Sralph 
29512111Sralph 		case 'P':
29615552Sralph 			strncpy(logname, line+1, sizeof(logname)-1);
29712463Sralph 			if (RS) {			/* restricted */
29812463Sralph 				if (getpwnam(logname) == (struct passwd *)0) {
29917463Sralph 					bombed = NOACCT;
30015811Sralph 					sendmail(line+1, bombed);
30112463Sralph 					goto pass2;
30212463Sralph 				}
30312463Sralph 			}
30412111Sralph 			continue;
30512111Sralph 
30617463Sralph 		case 'S':
30717463Sralph 			cp = line+1;
30817463Sralph 			i = 0;
30917463Sralph 			while (*cp >= '0' && *cp <= '9')
31017463Sralph 				i = i * 10 + (*cp++ - '0');
31117463Sralph 			fdev = i;
31217463Sralph 			cp++;
31317463Sralph 			i = 0;
31417463Sralph 			while (*cp >= '0' && *cp <= '9')
31517463Sralph 				i = i * 10 + (*cp++ - '0');
31617463Sralph 			fino = i;
31717463Sralph 			continue;
31817463Sralph 
31912111Sralph 		case 'J':
32012111Sralph 			if (line[1] != '\0')
32115552Sralph 				strncpy(jobname, line+1, sizeof(jobname)-1);
32212111Sralph 			else
32312111Sralph 				strcpy(jobname, " ");
32412111Sralph 			continue;
32512111Sralph 
32612111Sralph 		case 'C':
32712111Sralph 			if (line[1] != '\0')
32815552Sralph 				strncpy(class, line+1, sizeof(class)-1);
32912111Sralph 			else if (class[0] == '\0')
33015811Sralph 				gethostname(class, sizeof(class));
33112111Sralph 			continue;
33212111Sralph 
33312111Sralph 		case 'T':	/* header title for pr */
33415552Sralph 			strncpy(title, line+1, sizeof(title)-1);
33512111Sralph 			continue;
33612111Sralph 
33712111Sralph 		case 'L':	/* identification line */
33818127Sralph 			if (!SH && !HL)
33912111Sralph 				banner(line+1, jobname);
34012111Sralph 			continue;
34112111Sralph 
34212111Sralph 		case '1':	/* troff fonts */
34312111Sralph 		case '2':
34412111Sralph 		case '3':
34512111Sralph 		case '4':
34612111Sralph 			if (line[1] != '\0')
34712111Sralph 				strcpy(fonts[line[0]-'1'], line+1);
34812111Sralph 			continue;
34912111Sralph 
35012111Sralph 		case 'W':	/* page width */
35115552Sralph 			strncpy(width+2, line+1, sizeof(width)-3);
35212111Sralph 			continue;
35312111Sralph 
35412581Sralph 		case 'I':	/* indent amount */
35515552Sralph 			strncpy(indent+2, line+1, sizeof(indent)-3);
35612581Sralph 			continue;
35712581Sralph 
35812111Sralph 		default:	/* some file to print */
35915811Sralph 			switch (i = print(line[0], line+1)) {
36017463Sralph 			case ERROR:
36117463Sralph 				if (bombed == OK)
36217463Sralph 					bombed = FATALERR;
36315811Sralph 				break;
36417463Sralph 			case REPRINT:
36512111Sralph 				(void) fclose(cfp);
36617463Sralph 				return(REPRINT);
36717463Sralph 			case FILTERERR:
36817463Sralph 			case ACCESS:
36917463Sralph 				bombed = i;
37015811Sralph 				sendmail(logname, bombed);
37115811Sralph 			}
37212111Sralph 			title[0] = '\0';
37312111Sralph 			continue;
37412111Sralph 
37512111Sralph 		case 'N':
37612111Sralph 		case 'U':
37712111Sralph 		case 'M':
37812111Sralph 			continue;
37912111Sralph 		}
38012111Sralph 
38112111Sralph 	/* pass 2 */
38212111Sralph 
38312463Sralph pass2:
38412111Sralph 	fseek(cfp, 0L, 0);
38512111Sralph 	while (getline(cfp))
38612111Sralph 		switch (line[0]) {
38718127Sralph 		case 'L':	/* identification line */
38818127Sralph 			if (!SH && HL)
38918127Sralph 				banner(line+1, jobname);
39018127Sralph 			continue;
39118127Sralph 
39212111Sralph 		case 'M':
39317463Sralph 			if (bombed < NOACCT)	/* already sent if >= NOACCT */
39415811Sralph 				sendmail(line+1, bombed);
39512111Sralph 			continue;
39612111Sralph 
39712111Sralph 		case 'U':
39812111Sralph 			(void) unlink(line+1);
39912111Sralph 		}
40012111Sralph 	/*
40115811Sralph 	 * clean-up in case another control file exists
40212111Sralph 	 */
40312111Sralph 	(void) fclose(cfp);
40412111Sralph 	(void) unlink(file);
40517463Sralph 	return(bombed == OK ? OK : ERROR);
40612111Sralph }
40712111Sralph 
40812111Sralph /*
40912111Sralph  * Print a file.
41013233Sralph  * Set up the chain [ PR [ | {IF, OF} ] ] or {IF, RF, TF, NF, DF, CF, VF}.
41115811Sralph  * Return -1 if a non-recoverable error occured,
41215811Sralph  * 2 if the filter detected some errors (but printed the job anyway),
41315811Sralph  * 1 if we should try to reprint this job and
41412111Sralph  * 0 if all is well.
41512111Sralph  * Note: all filters take stdin as the file, stdout as the printer,
41612111Sralph  * stderr as the log file, and must not ignore SIGINT.
41712111Sralph  */
41812111Sralph print(format, file)
41912111Sralph 	int format;
42012111Sralph 	char *file;
42112111Sralph {
42215811Sralph 	register int n;
42312111Sralph 	register char *prog;
42415811Sralph 	int fi, fo;
42512111Sralph 	char *av[15], buf[BUFSIZ];
42612111Sralph 	int pid, p[2], stopped = 0;
42712111Sralph 	union wait status;
42817463Sralph 	struct stat stb;
42912111Sralph 
43017463Sralph 	if (lstat(file, &stb) < 0 || (fi = open(file, O_RDONLY)) < 0)
43117463Sralph 		return(ERROR);
43217463Sralph 	/*
43317463Sralph 	 * Check to see if data file is a symbolic link. If so, it should
43417463Sralph 	 * still point to the same file or someone is trying to print
43517463Sralph 	 * something he shouldn't.
43617463Sralph 	 */
43717463Sralph 	if ((stb.st_mode & S_IFMT) == S_IFLNK && fstat(fi, &stb) == 0 &&
43817463Sralph 	    (stb.st_dev != fdev || stb.st_ino != fino))
43917463Sralph 		return(ACCESS);
44012111Sralph 	if (!SF && !tof) {		/* start on a fresh page */
44112111Sralph 		(void) write(ofd, FF, strlen(FF));
44212111Sralph 		tof = 1;
44312111Sralph 	}
44412111Sralph 	if (IF == NULL && (format == 'f' || format == 'l')) {
44512111Sralph 		tof = 0;
44612111Sralph 		while ((n = read(fi, buf, BUFSIZ)) > 0)
44712111Sralph 			if (write(ofd, buf, n) != n) {
44812111Sralph 				(void) close(fi);
44917463Sralph 				return(REPRINT);
45012111Sralph 			}
45112111Sralph 		(void) close(fi);
45217463Sralph 		return(OK);
45312111Sralph 	}
45412111Sralph 	switch (format) {
45512111Sralph 	case 'p':	/* print file using 'pr' */
45612111Sralph 		if (IF == NULL) {	/* use output filter */
45712111Sralph 			prog = PR;
45812111Sralph 			av[0] = "pr";
45912111Sralph 			av[1] = width;
46012111Sralph 			av[2] = length;
46112111Sralph 			av[3] = "-h";
46212111Sralph 			av[4] = *title ? title : " ";
46312111Sralph 			av[5] = 0;
46412111Sralph 			fo = ofd;
46512111Sralph 			goto start;
46612111Sralph 		}
46712111Sralph 		pipe(p);
46812111Sralph 		if ((prchild = dofork(DORETURN)) == 0) {	/* child */
46912111Sralph 			dup2(fi, 0);		/* file is stdin */
47012111Sralph 			dup2(p[1], 1);		/* pipe is stdout */
47112111Sralph 			for (n = 3; n < NOFILE; n++)
47212111Sralph 				(void) close(n);
47312111Sralph 			execl(PR, "pr", width, length, "-h", *title ? title : " ", 0);
47416762Sralph 			syslog(LOG_ERR, "cannot execl %s", PR);
47512111Sralph 			exit(2);
47612111Sralph 		}
47712111Sralph 		(void) close(p[1]);		/* close output side */
47812111Sralph 		(void) close(fi);
47912111Sralph 		if (prchild < 0) {
48012111Sralph 			prchild = 0;
48112111Sralph 			(void) close(p[0]);
48217463Sralph 			return(ERROR);
48312111Sralph 		}
48412111Sralph 		fi = p[0];			/* use pipe for input */
48512111Sralph 	case 'f':	/* print plain text file */
48612111Sralph 		prog = IF;
48712111Sralph 		av[1] = width;
48812111Sralph 		av[2] = length;
48912581Sralph 		av[3] = indent;
49012581Sralph 		n = 4;
49112111Sralph 		break;
49212111Sralph 	case 'l':	/* like 'f' but pass control characters */
49312111Sralph 		prog = IF;
49414325Sralph 		av[1] = "-c";
49512111Sralph 		av[2] = width;
49612111Sralph 		av[3] = length;
49712581Sralph 		av[4] = indent;
49812581Sralph 		n = 5;
49912111Sralph 		break;
50012463Sralph 	case 'r':	/* print a fortran text file */
50112463Sralph 		prog = RF;
50212463Sralph 		av[1] = width;
50312463Sralph 		av[2] = length;
50412463Sralph 		n = 3;
50512463Sralph 		break;
50612111Sralph 	case 't':	/* print troff output */
50713233Sralph 	case 'n':	/* print ditroff output */
50812463Sralph 	case 'd':	/* print tex output */
50912111Sralph 		(void) unlink(".railmag");
51012463Sralph 		if ((fo = creat(".railmag", FILMOD)) < 0) {
51116762Sralph 			syslog(LOG_ERR, "%s: cannot create .railmag", printer);
51212111Sralph 			(void) unlink(".railmag");
51312111Sralph 		} else {
51412111Sralph 			for (n = 0; n < 4; n++) {
51512111Sralph 				if (fonts[n][0] != '/')
51612111Sralph 					(void) write(fo, "/usr/lib/vfont/", 15);
51712111Sralph 				(void) write(fo, fonts[n], strlen(fonts[n]));
51812111Sralph 				(void) write(fo, "\n", 1);
51912111Sralph 			}
52012111Sralph 			(void) close(fo);
52112111Sralph 		}
52213233Sralph 		prog = (format == 't') ? TF : (format == 'n') ? NF : DF;
52312463Sralph 		av[1] = pxwidth;
52412463Sralph 		av[2] = pxlength;
52512463Sralph 		n = 3;
52612111Sralph 		break;
52712111Sralph 	case 'c':	/* print cifplot output */
52812111Sralph 		prog = CF;
52912463Sralph 		av[1] = pxwidth;
53012463Sralph 		av[2] = pxlength;
53112463Sralph 		n = 3;
53212111Sralph 		break;
53312111Sralph 	case 'g':	/* print plot(1G) output */
53412111Sralph 		prog = GF;
53512463Sralph 		av[1] = pxwidth;
53612463Sralph 		av[2] = pxlength;
53712463Sralph 		n = 3;
53812111Sralph 		break;
53912111Sralph 	case 'v':	/* print raster output */
54012111Sralph 		prog = VF;
54112463Sralph 		av[1] = pxwidth;
54212463Sralph 		av[2] = pxlength;
54312463Sralph 		n = 3;
54412111Sralph 		break;
54512111Sralph 	default:
54612111Sralph 		(void) close(fi);
54716762Sralph 		syslog(LOG_ERR, "%s: illegal format character '%c'",
54816762Sralph 			printer, format);
54917463Sralph 		return(ERROR);
55012111Sralph 	}
55112111Sralph 	if ((av[0] = rindex(prog, '/')) != NULL)
55212111Sralph 		av[0]++;
55312111Sralph 	else
55412111Sralph 		av[0] = prog;
55512111Sralph 	av[n++] = "-n";
55612111Sralph 	av[n++] = logname;
55712111Sralph 	av[n++] = "-h";
55814150Sralph 	av[n++] = fromhost;
55912111Sralph 	av[n++] = AF;
56012111Sralph 	av[n] = 0;
56112111Sralph 	fo = pfd;
56212111Sralph 	if (ofilter > 0) {		/* stop output filter */
56312111Sralph 		write(ofd, "\031\1", 2);
56412111Sralph 		while ((pid = wait3(&status, WUNTRACED, 0)) > 0 && pid != ofilter)
56512111Sralph 			;
56612111Sralph 		if (status.w_stopval != WSTOPPED) {
56712111Sralph 			(void) close(fi);
56816762Sralph 			syslog(LOG_WARNING, "%s: output filter died (%d)",
56916762Sralph 				printer, status.w_retcode);
57017463Sralph 			return(REPRINT);
57112111Sralph 		}
57212111Sralph 		stopped++;
57312111Sralph 	}
57412111Sralph start:
57512111Sralph 	if ((child = dofork(DORETURN)) == 0) {	/* child */
57612111Sralph 		dup2(fi, 0);
57712111Sralph 		dup2(fo, 1);
57817304Sralph 		n = open(tmpfile, O_WRONLY|O_CREAT|O_TRUNC, 0664);
57915811Sralph 		if (n >= 0)
58015811Sralph 			dup2(n, 2);
58112111Sralph 		for (n = 3; n < NOFILE; n++)
58212111Sralph 			(void) close(n);
58312111Sralph 		execv(prog, av);
58416762Sralph 		syslog(LOG_ERR, "cannot execv %s", prog);
58512111Sralph 		exit(2);
58612111Sralph 	}
58712111Sralph 	(void) close(fi);
58812111Sralph 	if (child < 0)
58912111Sralph 		status.w_retcode = 100;
59012111Sralph 	else
59112111Sralph 		while ((pid = wait(&status)) > 0 && pid != child)
59212111Sralph 			;
59312111Sralph 	child = 0;
59412111Sralph 	prchild = 0;
59512111Sralph 	if (stopped) {		/* restart output filter */
59612111Sralph 		if (kill(ofilter, SIGCONT) < 0) {
59716762Sralph 			syslog(LOG_ERR, "cannot restart output filter");
59812111Sralph 			exit(1);
59912111Sralph 		}
60012111Sralph 	}
60112111Sralph 	tof = 0;
60215811Sralph 	if (!WIFEXITED(status)) {
60316762Sralph 		syslog(LOG_WARNING, "%s: Daemon filter '%c' terminated (%d)",
60416762Sralph 			printer, format, status.w_termsig);
60517463Sralph 		return(ERROR);
60617463Sralph 	}
60717463Sralph 	switch (status.w_retcode) {
60817463Sralph 	case 0:
60917463Sralph 		tof = 1;
61017463Sralph 		return(OK);
61117463Sralph 	case 1:
61217463Sralph 		return(REPRINT);
61317463Sralph 	default:
61416762Sralph 		syslog(LOG_WARNING, "%s: Daemon filter '%c' exited (%d)",
61516762Sralph 			printer, format, status.w_retcode);
61617463Sralph 	case 2:
61717463Sralph 		return(ERROR);
61817463Sralph 	}
61912111Sralph }
62012111Sralph 
62112111Sralph /*
62212111Sralph  * Send the daemon control file (cf) and any data files.
62312111Sralph  * Return -1 if a non-recoverable error occured, 1 if a recoverable error and
62412111Sralph  * 0 if all is well.
62512111Sralph  */
62612111Sralph sendit(file)
62712111Sralph 	char *file;
62812111Sralph {
62917463Sralph 	register int i, err = OK;
63017463Sralph 	char *cp, last[BUFSIZ];
63112111Sralph 
63212111Sralph 	/*
63312111Sralph 	 * open control file
63412111Sralph 	 */
63516762Sralph 	if ((cfp = fopen(file, "r")) == NULL)
63617463Sralph 		return(OK);
63712111Sralph 	/*
63812111Sralph 	 *      read the control file for work to do
63912111Sralph 	 *
64012111Sralph 	 *      file format -- first character in the line is a command
64112111Sralph 	 *      rest of the line is the argument.
64212111Sralph 	 *      commands of interest are:
64312111Sralph 	 *
64412111Sralph 	 *            a-z -- "file name" name of file to print
64512111Sralph 	 *              U -- "unlink" name of file to remove
64612111Sralph 	 *                    (after we print it. (Pass 2 only)).
64712111Sralph 	 */
64812111Sralph 
64912111Sralph 	/*
65012111Sralph 	 * pass 1
65112111Sralph 	 */
65212111Sralph 	while (getline(cfp)) {
65312111Sralph 	again:
65417463Sralph 		if (line[0] == 'S') {
65517463Sralph 			cp = line+1;
65617463Sralph 			i = 0;
65717463Sralph 			while (*cp >= '0' && *cp <= '9')
65817463Sralph 				i = i * 10 + (*cp++ - '0');
65917463Sralph 			fdev = i;
66017463Sralph 			cp++;
66117463Sralph 			i = 0;
66217463Sralph 			while (*cp >= '0' && *cp <= '9')
66317463Sralph 				i = i * 10 + (*cp++ - '0');
66417463Sralph 			fino = i;
66517463Sralph 			continue;
66617463Sralph 		}
66712111Sralph 		if (line[0] >= 'a' && line[0] <= 'z') {
66812111Sralph 			strcpy(last, line);
66917463Sralph 			while (i = getline(cfp))
67012111Sralph 				if (strcmp(last, line))
67112111Sralph 					break;
67217463Sralph 			switch (sendfile('\3', last+1)) {
67317463Sralph 			case OK:
67417463Sralph 				if (i)
67517463Sralph 					goto again;
67617463Sralph 				break;
67717463Sralph 			case REPRINT:
67812111Sralph 				(void) fclose(cfp);
67917463Sralph 				return(REPRINT);
68017463Sralph 			case ACCESS:
68117463Sralph 				sendmail(logname, ACCESS);
68217463Sralph 			case ERROR:
68317463Sralph 				err = ERROR;
68417463Sralph 			}
68512111Sralph 			break;
68612111Sralph 		}
68712111Sralph 	}
68817463Sralph 	if (err == OK && sendfile('\2', file) > 0) {
68912111Sralph 		(void) fclose(cfp);
69017463Sralph 		return(REPRINT);
69112111Sralph 	}
69212111Sralph 	/*
69312111Sralph 	 * pass 2
69412111Sralph 	 */
69512111Sralph 	fseek(cfp, 0L, 0);
69612111Sralph 	while (getline(cfp))
69712111Sralph 		if (line[0] == 'U')
69812111Sralph 			(void) unlink(line+1);
69912111Sralph 	/*
70017463Sralph 	 * clean-up in case another control file exists
70112111Sralph 	 */
70212111Sralph 	(void) fclose(cfp);
70312111Sralph 	(void) unlink(file);
70417463Sralph 	return(err);
70512111Sralph }
70612111Sralph 
70712111Sralph /*
70812111Sralph  * Send a data file to the remote machine and spool it.
70912111Sralph  * Return positive if we should try resending.
71012111Sralph  */
71112111Sralph sendfile(type, file)
71212111Sralph 	char type, *file;
71312111Sralph {
71412111Sralph 	register int f, i, amt;
71512111Sralph 	struct stat stb;
71612111Sralph 	char buf[BUFSIZ];
71716762Sralph 	int sizerr, resp;
71812111Sralph 
71917463Sralph 	if (lstat(file, &stb) < 0 || (f = open(file, O_RDONLY)) < 0)
72017463Sralph 		return(ERROR);
72117463Sralph 	/*
72217463Sralph 	 * Check to see if data file is a symbolic link. If so, it should
72317463Sralph 	 * still point to the same file or someone is trying to print something
72417463Sralph 	 * he shouldn't.
72517463Sralph 	 */
72617463Sralph 	if ((stb.st_mode & S_IFMT) == S_IFLNK && fstat(f, &stb) == 0 &&
72717463Sralph 	    (stb.st_dev != fdev || stb.st_ino != fino))
72817463Sralph 		return(ACCESS);
72912111Sralph 	(void) sprintf(buf, "%c%d %s\n", type, stb.st_size, file);
73012111Sralph 	amt = strlen(buf);
73116762Sralph 	for (i = 0;  ; i++) {
73216762Sralph 		if (write(pfd, buf, amt) != amt ||
73316762Sralph 		    (resp = response()) < 0 || resp == '\1') {
73416762Sralph 			(void) close(f);
73517463Sralph 			return(REPRINT);
73616762Sralph 		} else if (resp == '\0')
73716762Sralph 			break;
73816762Sralph 		if (i == 0)
73916762Sralph 			status("no space on remote; waiting for queue to drain");
74016762Sralph 		if (i == 10)
74124861Seric 			syslog(LOG_ALERT, "%s: can't send to %s; queue full",
74216762Sralph 				printer, RM);
74316762Sralph 		sleep(5 * 60);
74412692Sralph 	}
74516762Sralph 	if (i)
74616762Sralph 		status("sending to %s", RM);
74712111Sralph 	sizerr = 0;
74812111Sralph 	for (i = 0; i < stb.st_size; i += BUFSIZ) {
74912111Sralph 		amt = BUFSIZ;
75012111Sralph 		if (i + amt > stb.st_size)
75112111Sralph 			amt = stb.st_size - i;
75212111Sralph 		if (sizerr == 0 && read(f, buf, amt) != amt)
75312111Sralph 			sizerr = 1;
75412692Sralph 		if (write(pfd, buf, amt) != amt) {
75512692Sralph 			(void) close(f);
75617463Sralph 			return(REPRINT);
75712692Sralph 		}
75812111Sralph 	}
75912111Sralph 	(void) close(f);
76012111Sralph 	if (sizerr) {
76116762Sralph 		syslog(LOG_INFO, "%s: %s: changed size", printer, file);
76217463Sralph 		/* tell recvjob to ignore this file */
76317463Sralph 		(void) write(pfd, "\1", 1);
76417463Sralph 		return(ERROR);
76517463Sralph 	}
76617463Sralph 	if (write(pfd, "", 1) != 1 || response())
76717463Sralph 		return(REPRINT);
76817463Sralph 	return(OK);
76912111Sralph }
77012111Sralph 
77112111Sralph /*
77212111Sralph  * Check to make sure there have been no errors and that both programs
77312111Sralph  * are in sync with eachother.
77412111Sralph  * Return non-zero if the connection was lost.
77512111Sralph  */
77616762Sralph response()
77712111Sralph {
77812111Sralph 	char resp;
77912111Sralph 
78016762Sralph 	if (read(pfd, &resp, 1) != 1) {
78116762Sralph 		syslog(LOG_INFO, "%s: lost connection", printer);
78216762Sralph 		return(-1);
78312111Sralph 	}
78416762Sralph 	return(resp);
78512111Sralph }
78612111Sralph 
78712111Sralph /*
78812111Sralph  * Banner printing stuff
78912111Sralph  */
79012111Sralph banner(name1, name2)
79112111Sralph 	char *name1, *name2;
79212111Sralph {
79312111Sralph 	time_t tvec;
79412111Sralph 	extern char *ctime();
79512111Sralph 
79612111Sralph 	time(&tvec);
79712111Sralph 	if (!SF && !tof)
79812111Sralph 		(void) write(ofd, FF, strlen(FF));
79912111Sralph 	if (SB) {	/* short banner only */
80012111Sralph 		if (class[0]) {
80112111Sralph 			(void) write(ofd, class, strlen(class));
80212111Sralph 			(void) write(ofd, ":", 1);
80312111Sralph 		}
80412111Sralph 		(void) write(ofd, name1, strlen(name1));
80512111Sralph 		(void) write(ofd, "  Job: ", 7);
80612111Sralph 		(void) write(ofd, name2, strlen(name2));
80712111Sralph 		(void) write(ofd, "  Date: ", 8);
80812111Sralph 		(void) write(ofd, ctime(&tvec), 24);
80912111Sralph 		(void) write(ofd, "\n", 1);
81012111Sralph 	} else {	/* normal banner */
81112111Sralph 		(void) write(ofd, "\n\n\n", 3);
81212111Sralph 		scan_out(ofd, name1, '\0');
81312111Sralph 		(void) write(ofd, "\n\n", 2);
81412111Sralph 		scan_out(ofd, name2, '\0');
81512111Sralph 		if (class[0]) {
81612111Sralph 			(void) write(ofd,"\n\n\n",3);
81712111Sralph 			scan_out(ofd, class, '\0');
81812111Sralph 		}
81912111Sralph 		(void) write(ofd, "\n\n\n\n\t\t\t\t\tJob:  ", 15);
82012111Sralph 		(void) write(ofd, name2, strlen(name2));
82112111Sralph 		(void) write(ofd, "\n\t\t\t\t\tDate: ", 12);
82212111Sralph 		(void) write(ofd, ctime(&tvec), 24);
82312111Sralph 		(void) write(ofd, "\n", 1);
82412111Sralph 	}
82512111Sralph 	if (!SF)
82612111Sralph 		(void) write(ofd, FF, strlen(FF));
82712111Sralph 	tof = 1;
82812111Sralph }
82912111Sralph 
83016762Sralph char *
83112111Sralph scnline(key, p, c)
83212111Sralph 	register char key, *p;
83312111Sralph 	char c;
83412111Sralph {
83512111Sralph 	register scnwidth;
83612111Sralph 
83712111Sralph 	for (scnwidth = WIDTH; --scnwidth;) {
83812111Sralph 		key <<= 1;
83912111Sralph 		*p++ = key & 0200 ? c : BACKGND;
84012111Sralph 	}
84112111Sralph 	return (p);
84212111Sralph }
84312111Sralph 
84412111Sralph #define TRC(q)	(((q)-' ')&0177)
84512111Sralph 
84612111Sralph scan_out(scfd, scsp, dlm)
84712111Sralph 	int scfd;
84812111Sralph 	char *scsp, dlm;
84912111Sralph {
85012111Sralph 	register char *strp;
85112111Sralph 	register nchrs, j;
85212111Sralph 	char outbuf[LINELEN+1], *sp, c, cc;
85312111Sralph 	int d, scnhgt;
85412111Sralph 	extern char scnkey[][HEIGHT];	/* in lpdchar.c */
85512111Sralph 
85612111Sralph 	for (scnhgt = 0; scnhgt++ < HEIGHT+DROP; ) {
85712111Sralph 		strp = &outbuf[0];
85812111Sralph 		sp = scsp;
85912111Sralph 		for (nchrs = 0; ; ) {
86012111Sralph 			d = dropit(c = TRC(cc = *sp++));
86112111Sralph 			if ((!d && scnhgt > HEIGHT) || (scnhgt <= DROP && d))
86212111Sralph 				for (j = WIDTH; --j;)
86312111Sralph 					*strp++ = BACKGND;
86412111Sralph 			else
86512111Sralph 				strp = scnline(scnkey[c][scnhgt-1-d], strp, cc);
86612111Sralph 			if (*sp == dlm || *sp == '\0' || nchrs++ >= PW/(WIDTH+1)-1)
86712111Sralph 				break;
86812111Sralph 			*strp++ = BACKGND;
86912111Sralph 			*strp++ = BACKGND;
87012111Sralph 		}
87112111Sralph 		while (*--strp == BACKGND && strp >= outbuf)
87212111Sralph 			;
87312111Sralph 		strp++;
87412111Sralph 		*strp++ = '\n';
87512111Sralph 		(void) write(scfd, outbuf, strp-outbuf);
87612111Sralph 	}
87712111Sralph }
87812111Sralph 
87912111Sralph dropit(c)
88012111Sralph 	char c;
88112111Sralph {
88212111Sralph 	switch(c) {
88312111Sralph 
88412111Sralph 	case TRC('_'):
88512111Sralph 	case TRC(';'):
88612111Sralph 	case TRC(','):
88712111Sralph 	case TRC('g'):
88812111Sralph 	case TRC('j'):
88912111Sralph 	case TRC('p'):
89012111Sralph 	case TRC('q'):
89112111Sralph 	case TRC('y'):
89212111Sralph 		return (DROP);
89312111Sralph 
89412111Sralph 	default:
89512111Sralph 		return (0);
89612111Sralph 	}
89712111Sralph }
89812111Sralph 
89912111Sralph /*
90012111Sralph  * sendmail ---
90112111Sralph  *   tell people about job completion
90212111Sralph  */
90315811Sralph sendmail(user, bombed)
90415811Sralph 	char *user;
90512111Sralph 	int bombed;
90612111Sralph {
90712111Sralph 	register int i;
90815811Sralph 	int p[2], s;
90912111Sralph 	register char *cp;
91012111Sralph 	char buf[100];
91115811Sralph 	struct stat stb;
91215811Sralph 	FILE *fp;
91312111Sralph 
91412111Sralph 	pipe(p);
91515811Sralph 	if ((s = dofork(DORETURN)) == 0) {		/* child */
91612111Sralph 		dup2(p[0], 0);
91712111Sralph 		for (i = 3; i < NOFILE; i++)
91812111Sralph 			(void) close(i);
91912111Sralph 		if ((cp = rindex(MAIL, '/')) != NULL)
92012111Sralph 			cp++;
92112111Sralph 		else
92212111Sralph 			cp = MAIL;
92315811Sralph 		sprintf(buf, "%s@%s", user, fromhost);
92412111Sralph 		execl(MAIL, cp, buf, 0);
92512111Sralph 		exit(0);
92615811Sralph 	} else if (s > 0) {				/* parent */
92712111Sralph 		dup2(p[1], 1);
92815811Sralph 		printf("To: %s@%s\n", user, fromhost);
92912111Sralph 		printf("Subject: printer job\n\n");
93012111Sralph 		printf("Your printer job ");
93112111Sralph 		if (*jobname)
93212111Sralph 			printf("(%s) ", jobname);
93312463Sralph 		switch (bombed) {
93417463Sralph 		case OK:
93512463Sralph 			printf("\ncompleted successfully\n");
93612463Sralph 			break;
93712463Sralph 		default:
93817463Sralph 		case FATALERR:
93912463Sralph 			printf("\ncould not be printed\n");
94012463Sralph 			break;
94117463Sralph 		case NOACCT:
94212463Sralph 			printf("\ncould not be printed without an account on %s\n", host);
94312463Sralph 			break;
94417463Sralph 		case FILTERERR:
94515811Sralph 			if (stat(tmpfile, &stb) < 0 || stb.st_size == 0 ||
94615811Sralph 			    (fp = fopen(tmpfile, "r")) == NULL) {
94715811Sralph 				printf("\nwas printed but had some errors\n");
94815811Sralph 				break;
94915811Sralph 			}
95015811Sralph 			printf("\nwas printed but had the following errors:\n");
95115811Sralph 			while ((i = getc(fp)) != EOF)
95215811Sralph 				putchar(i);
95315811Sralph 			(void) fclose(fp);
95417463Sralph 			break;
95517463Sralph 		case ACCESS:
95617463Sralph 			printf("\nwas not printed because it was not linked to the original file\n");
95712463Sralph 		}
95812111Sralph 		fflush(stdout);
95912111Sralph 		(void) close(1);
96012111Sralph 	}
96112111Sralph 	(void) close(p[0]);
96212111Sralph 	(void) close(p[1]);
96315811Sralph 	wait(&s);
96412111Sralph }
96512111Sralph 
96612111Sralph /*
96712111Sralph  * dofork - fork with retries on failure
96812111Sralph  */
96912111Sralph dofork(action)
97012111Sralph 	int action;
97112111Sralph {
97212111Sralph 	register int i, pid;
97312111Sralph 
97412111Sralph 	for (i = 0; i < 20; i++) {
97512463Sralph 		if ((pid = fork()) < 0) {
97612111Sralph 			sleep((unsigned)(i*i));
97712463Sralph 			continue;
97812463Sralph 		}
97912463Sralph 		/*
98012463Sralph 		 * Child should run as daemon instead of root
98112463Sralph 		 */
98212463Sralph 		if (pid == 0)
98312463Sralph 			setuid(DU);
98412463Sralph 		return(pid);
98512111Sralph 	}
98616762Sralph 	syslog(LOG_ERR, "can't fork");
98712111Sralph 
98812111Sralph 	switch (action) {
98912111Sralph 	case DORETURN:
99012111Sralph 		return (-1);
99112111Sralph 	default:
99216762Sralph 		syslog(LOG_ERR, "bad action (%d) to dofork", action);
99312111Sralph 		/*FALL THRU*/
99412111Sralph 	case DOABORT:
99512111Sralph 		exit(1);
99612111Sralph 	}
99712111Sralph 	/*NOTREACHED*/
99812111Sralph }
99912111Sralph 
100012111Sralph /*
100116762Sralph  * Kill child processes to abort current job.
100212111Sralph  */
100316762Sralph abortpr()
100412111Sralph {
100515811Sralph 	(void) unlink(tmpfile);
100612111Sralph 	kill(0, SIGINT);
100712111Sralph 	if (ofilter > 0)
100812111Sralph 		kill(ofilter, SIGCONT);
100912111Sralph 	while (wait(0) > 0)
101012111Sralph 		;
101112111Sralph 	exit(0);
101212111Sralph }
101312111Sralph 
101412111Sralph init()
101512111Sralph {
101612111Sralph 	int status;
101712111Sralph 
101825468Stef 	if ((status = pgetent(line, printer)) < 0) {
101925468Stef 		syslog(LOG_ERR, "can't open printer description file");
102025468Stef 		exit(1);
102125468Stef 	} else if (status == 0) {
102225468Stef 		syslog(LOG_ERR, "unknown printer: %s", printer);
102325468Stef 		exit(1);
102425468Stef 	}
102512111Sralph 	if ((LP = pgetstr("lp", &bp)) == NULL)
102612111Sralph 		LP = DEFDEVLP;
102712111Sralph 	if ((RP = pgetstr("rp", &bp)) == NULL)
102812463Sralph 		RP = DEFLP;
102912111Sralph 	if ((LO = pgetstr("lo", &bp)) == NULL)
103012111Sralph 		LO = DEFLOCK;
103112111Sralph 	if ((ST = pgetstr("st", &bp)) == NULL)
103212111Sralph 		ST = DEFSTAT;
103312111Sralph 	if ((LF = pgetstr("lf", &bp)) == NULL)
103412111Sralph 		LF = DEFLOGF;
103512111Sralph 	if ((SD = pgetstr("sd", &bp)) == NULL)
103612111Sralph 		SD = DEFSPOOL;
103712111Sralph 	if ((DU = pgetnum("du")) < 0)
103812111Sralph 		DU = DEFUID;
103912111Sralph 	if ((FF = pgetstr("ff", &bp)) == NULL)
104012111Sralph 		FF = DEFFF;
104112111Sralph 	if ((PW = pgetnum("pw")) < 0)
104212111Sralph 		PW = DEFWIDTH;
104312111Sralph 	sprintf(&width[2], "%d", PW);
104412111Sralph 	if ((PL = pgetnum("pl")) < 0)
104512111Sralph 		PL = DEFLENGTH;
104612111Sralph 	sprintf(&length[2], "%d", PL);
104712463Sralph 	if ((PX = pgetnum("px")) < 0)
104812463Sralph 		PX = 0;
104912463Sralph 	sprintf(&pxwidth[2], "%d", PX);
105012463Sralph 	if ((PY = pgetnum("py")) < 0)
105112463Sralph 		PY = 0;
105212463Sralph 	sprintf(&pxlength[2], "%d", PY);
105312111Sralph 	RM = pgetstr("rm", &bp);
105425468Stef 	/*
105525468Stef 	 * Figure out whether the local machine is the same as the remote
105625468Stef 	 * machine entry (if it exists).  If not, then ignore the local
105725468Stef 	 * queue information.
105825468Stef 	 */
105925468Stef 	 if (RM != (char *) NULL) {
106025468Stef 		char name[256];
106125468Stef 		struct hostent *hp;
106225468Stef 
106325468Stef 		/* get the standard network name of the local host */
106425468Stef 		gethostname(name, sizeof(name));
106525468Stef 		name[sizeof(name)-1] = '\0';
106625468Stef 		hp = gethostbyname(name);
106725468Stef 		if (hp == (struct hostent *) NULL) {
106825468Stef 		    syslog(LOG_ERR,
106925468Stef 			"unable to get network name for local machine %s",
107025468Stef 			name);
107125468Stef 		    goto localcheck_done;
107225468Stef 		} else strcpy(name, hp->h_name);
107325468Stef 
107425468Stef 		/* get the standard network name of RM */
107525468Stef 		hp = gethostbyname(RM);
107625468Stef 		if (hp == (struct hostent *) NULL) {
107725468Stef 		    syslog(LOG_ERR,
107825468Stef 			"unable to get hostname for remote machine %s", RM);
107925468Stef 		    goto localcheck_done;
108025468Stef 		}
108125468Stef 
108225468Stef 		/* if printer is not on local machine, ignore LP */
108325468Stef 		if (strcmp(name, hp->h_name) != 0) *LP = '\0';
108425468Stef 	}
108525468Stef localcheck_done:
108625468Stef 
108712111Sralph 	AF = pgetstr("af", &bp);
108812111Sralph 	OF = pgetstr("of", &bp);
108912111Sralph 	IF = pgetstr("if", &bp);
109012463Sralph 	RF = pgetstr("rf", &bp);
109112111Sralph 	TF = pgetstr("tf", &bp);
109213233Sralph 	NF = pgetstr("nf", &bp);
109312111Sralph 	DF = pgetstr("df", &bp);
109412111Sralph 	GF = pgetstr("gf", &bp);
109512111Sralph 	VF = pgetstr("vf", &bp);
109612111Sralph 	CF = pgetstr("cf", &bp);
109712111Sralph 	TR = pgetstr("tr", &bp);
109812463Sralph 	RS = pgetflag("rs");
109912111Sralph 	SF = pgetflag("sf");
110012111Sralph 	SH = pgetflag("sh");
110112111Sralph 	SB = pgetflag("sb");
110218127Sralph 	HL = pgetflag("hl");
110312111Sralph 	RW = pgetflag("rw");
110412111Sralph 	BR = pgetnum("br");
110512111Sralph 	if ((FC = pgetnum("fc")) < 0)
110612111Sralph 		FC = 0;
110712111Sralph 	if ((FS = pgetnum("fs")) < 0)
110812111Sralph 		FS = 0;
110912111Sralph 	if ((XC = pgetnum("xc")) < 0)
111012111Sralph 		XC = 0;
111112111Sralph 	if ((XS = pgetnum("xs")) < 0)
111212111Sralph 		XS = 0;
111312581Sralph 	tof = !pgetflag("fo");
111412111Sralph }
111512111Sralph 
111612463Sralph /*
111712463Sralph  * Acquire line printer or remote connection.
111812463Sralph  */
111912463Sralph openpr()
112012463Sralph {
112112463Sralph 	register int i, n;
112216762Sralph 	int resp;
112312463Sralph 
112412463Sralph 	if (*LP) {
112512463Sralph 		for (i = 1; ; i = i < 32 ? i << 1 : i) {
112613148Ssam 			pfd = open(LP, RW ? O_RDWR : O_WRONLY);
112712463Sralph 			if (pfd >= 0)
112812463Sralph 				break;
112912463Sralph 			if (errno == ENOENT) {
113016762Sralph 				syslog(LOG_ERR, "%s: %m", LP);
113112463Sralph 				exit(1);
113212463Sralph 			}
113312463Sralph 			if (i == 1)
113412463Sralph 				status("waiting for %s to become ready (offline ?)", printer);
113512463Sralph 			sleep(i);
113612463Sralph 		}
113712463Sralph 		if (isatty(pfd))
113812463Sralph 			setty();
113912463Sralph 		status("%s is ready and printing", printer);
114012463Sralph 	} else if (RM != NULL) {
114116762Sralph 		for (i = 1; ; i = i < 256 ? i << 1 : i) {
114216762Sralph 			resp = -1;
114312528Sralph 			pfd = getport(RM);
114412463Sralph 			if (pfd >= 0) {
114512463Sralph 				(void) sprintf(line, "\2%s\n", RP);
114612463Sralph 				n = strlen(line);
114716762Sralph 				if (write(pfd, line, n) == n &&
114816762Sralph 				    (resp = response()) == '\0')
114912463Sralph 					break;
115016031Sralph 				(void) close(pfd);
115112463Sralph 			}
115216031Sralph 			if (i == 1) {
115316762Sralph 				if (resp < 0)
115416031Sralph 					status("waiting for %s to come up", RM);
115516762Sralph 				else {
115616031Sralph 					status("waiting for queue to be enabled on %s", RM);
115716762Sralph 					i = 256;
115816762Sralph 				}
115916031Sralph 			}
116012463Sralph 			sleep(i);
116112463Sralph 		}
116212463Sralph 		status("sending to %s", RM);
116312463Sralph 		remote = 1;
116412463Sralph 	} else {
116516762Sralph 		syslog(LOG_ERR, "%s: no line printer device or host name",
116616762Sralph 			printer);
116712463Sralph 		exit(1);
116812463Sralph 	}
116912463Sralph 	/*
117012463Sralph 	 * Start up an output filter, if needed.
117112463Sralph 	 */
117212463Sralph 	if (OF) {
117312463Sralph 		int p[2];
117412463Sralph 		char *cp;
117512463Sralph 
117612463Sralph 		pipe(p);
117712463Sralph 		if ((ofilter = dofork(DOABORT)) == 0) {	/* child */
117812463Sralph 			dup2(p[0], 0);		/* pipe is std in */
117912463Sralph 			dup2(pfd, 1);		/* printer is std out */
118012463Sralph 			for (i = 3; i < NOFILE; i++)
118112463Sralph 				(void) close(i);
118212463Sralph 			if ((cp = rindex(OF, '/')) == NULL)
118312463Sralph 				cp = OF;
118412463Sralph 			else
118512463Sralph 				cp++;
118612463Sralph 			execl(OF, cp, width, length, 0);
118716762Sralph 			syslog(LOG_ERR, "%s: %s: %m", printer, OF);
118812463Sralph 			exit(1);
118912463Sralph 		}
119012463Sralph 		(void) close(p[0]);		/* close input side */
119112463Sralph 		ofd = p[1];			/* use pipe for output */
119212463Sralph 	} else {
119312463Sralph 		ofd = pfd;
119412463Sralph 		ofilter = 0;
119512463Sralph 	}
119612463Sralph }
119712463Sralph 
119812111Sralph struct bauds {
119912111Sralph 	int	baud;
120012111Sralph 	int	speed;
120112111Sralph } bauds[] = {
120212111Sralph 	50,	B50,
120312111Sralph 	75,	B75,
120412111Sralph 	110,	B110,
120512111Sralph 	134,	B134,
120612111Sralph 	150,	B150,
120712111Sralph 	200,	B200,
120812111Sralph 	300,	B300,
120912111Sralph 	600,	B600,
121012111Sralph 	1200,	B1200,
121112111Sralph 	1800,	B1800,
121212111Sralph 	2400,	B2400,
121312111Sralph 	4800,	B4800,
121412111Sralph 	9600,	B9600,
121512111Sralph 	19200,	EXTA,
121612111Sralph 	38400,	EXTB,
121712111Sralph 	0,	0
121812111Sralph };
121912111Sralph 
122012111Sralph /*
122112111Sralph  * setup tty lines.
122212111Sralph  */
122312111Sralph setty()
122412111Sralph {
122512111Sralph 	struct sgttyb ttybuf;
122612111Sralph 	register struct bauds *bp;
122712111Sralph 
122812111Sralph 	if (ioctl(pfd, TIOCEXCL, (char *)0) < 0) {
122916762Sralph 		syslog(LOG_ERR, "%s: ioctl(TIOCEXCL): %m", printer);
123012111Sralph 		exit(1);
123112111Sralph 	}
123212111Sralph 	if (ioctl(pfd, TIOCGETP, (char *)&ttybuf) < 0) {
123316762Sralph 		syslog(LOG_ERR, "%s: ioctl(TIOCGETP): %m", printer);
123412111Sralph 		exit(1);
123512111Sralph 	}
123612111Sralph 	if (BR > 0) {
123712111Sralph 		for (bp = bauds; bp->baud; bp++)
123812111Sralph 			if (BR == bp->baud)
123912111Sralph 				break;
124012111Sralph 		if (!bp->baud) {
124116762Sralph 			syslog(LOG_ERR, "%s: illegal baud rate %d", printer, BR);
124212111Sralph 			exit(1);
124312111Sralph 		}
124412111Sralph 		ttybuf.sg_ispeed = ttybuf.sg_ospeed = bp->speed;
124512111Sralph 	}
124613169Sralph 	ttybuf.sg_flags &= ~FC;
124713169Sralph 	ttybuf.sg_flags |= FS;
124812111Sralph 	if (ioctl(pfd, TIOCSETP, (char *)&ttybuf) < 0) {
124916762Sralph 		syslog(LOG_ERR, "%s: ioctl(TIOCSETP): %m", printer);
125012111Sralph 		exit(1);
125112111Sralph 	}
125217168Sralph 	if (XC || XS) {
125317168Sralph 		int ldisc = NTTYDISC;
125417168Sralph 
125517168Sralph 		if (ioctl(pfd, TIOCSETD, &ldisc) < 0) {
125617168Sralph 			syslog(LOG_ERR, "%s: ioctl(TIOCSETD): %m", printer);
125717168Sralph 			exit(1);
125817168Sralph 		}
125917168Sralph 	}
126012111Sralph 	if (XC) {
126112111Sralph 		if (ioctl(pfd, TIOCLBIC, &XC) < 0) {
126216762Sralph 			syslog(LOG_ERR, "%s: ioctl(TIOCLBIC): %m", printer);
126312111Sralph 			exit(1);
126412111Sralph 		}
126512111Sralph 	}
126612111Sralph 	if (XS) {
126712111Sralph 		if (ioctl(pfd, TIOCLBIS, &XS) < 0) {
126816762Sralph 			syslog(LOG_ERR, "%s: ioctl(TIOCLBIS): %m", printer);
126912111Sralph 			exit(1);
127012111Sralph 		}
127112111Sralph 	}
127212111Sralph }
127312463Sralph 
127412463Sralph /*VARARGS1*/
127512463Sralph status(msg, a1, a2, a3)
127612463Sralph 	char *msg;
127712463Sralph {
127812463Sralph 	register int fd;
127912463Sralph 	char buf[BUFSIZ];
128012463Sralph 
128112463Sralph 	umask(0);
128213148Ssam 	fd = open(ST, O_WRONLY|O_CREAT, 0664);
128316762Sralph 	if (fd < 0 || flock(fd, LOCK_EX) < 0) {
128416762Sralph 		syslog(LOG_ERR, "%s: %s: %m", printer, ST);
128516762Sralph 		exit(1);
128616762Sralph 	}
128713148Ssam 	ftruncate(fd, 0);
128812463Sralph 	sprintf(buf, msg, a1, a2, a3);
128912463Sralph 	strcat(buf, "\n");
129012463Sralph 	(void) write(fd, buf, strlen(buf));
129112463Sralph 	(void) close(fd);
129212463Sralph }
1293