xref: /csrg-svn/usr.sbin/lpr/lpd/printjob.c (revision 25496)
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
825468Stef 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 */
71*25496Seric 	(void) close(2);			/* set up log file */
72*25496Seric 	if (open(LF, O_WRONLY|O_APPEND, 0664) < 0) {
73*25496Seric 		syslog(LOG_ERR, "%s: %m", LF);
74*25496Seric 		(void) open("/dev/null", O_WRONLY);
75*25496Seric 	}
7616762Sralph 	setgid(getegid());
7712463Sralph 	pid = getpid();				/* for use with lprm */
7812111Sralph 	setpgrp(0, pid);
7916762Sralph 	signal(SIGHUP, abortpr);
8016762Sralph 	signal(SIGINT, abortpr);
8116762Sralph 	signal(SIGQUIT, abortpr);
8216762Sralph 	signal(SIGTERM, abortpr);
8312111Sralph 
8415811Sralph 	(void) mktemp(tmpfile);
8515811Sralph 
8612111Sralph 	/*
8712111Sralph 	 * uses short form file names
8812111Sralph 	 */
8912111Sralph 	if (chdir(SD) < 0) {
9016762Sralph 		syslog(LOG_ERR, "%s: %m", SD);
9112111Sralph 		exit(1);
9212111Sralph 	}
9312463Sralph 	if (stat(LO, &stb) == 0 && (stb.st_mode & 0100))
9412463Sralph 		exit(0);		/* printing disabled */
9514150Sralph 	lfd = open(LO, O_WRONLY|O_CREAT, 0644);
9613169Sralph 	if (lfd < 0) {
9716762Sralph 		syslog(LOG_ERR, "%s: %s: %m", printer, LO);
9813169Sralph 		exit(1);
9913169Sralph 	}
10013169Sralph 	if (flock(lfd, LOCK_EX|LOCK_NB) < 0) {
10112111Sralph 		if (errno == EWOULDBLOCK)	/* active deamon present */
10212111Sralph 			exit(0);
10316762Sralph 		syslog(LOG_ERR, "%s: %s: %m", printer, LO);
10412111Sralph 		exit(1);
10512111Sralph 	}
10613148Ssam 	ftruncate(lfd, 0);
10712111Sralph 	/*
10812111Sralph 	 * write process id for others to know
10912111Sralph 	 */
11012111Sralph 	sprintf(line, "%u\n", pid);
11112111Sralph 	pidoff = i = strlen(line);
11212463Sralph 	if (write(lfd, line, i) != i) {
11316762Sralph 		syslog(LOG_ERR, "%s: %s: %m", printer, LO);
11412111Sralph 		exit(1);
11512111Sralph 	}
11612111Sralph 	/*
11712111Sralph 	 * search the spool directory for work and sort by queue order.
11812111Sralph 	 */
11912111Sralph 	if ((nitems = getq(&queue)) < 0) {
12016762Sralph 		syslog(LOG_ERR, "%s: can't scan %s", printer, SD);
12112111Sralph 		exit(1);
12212111Sralph 	}
12312463Sralph 	if (nitems == 0)		/* no work to do */
12412111Sralph 		exit(0);
12513169Sralph 	if (stb.st_mode & 01) {		/* reset queue flag */
12613169Sralph 		if (fchmod(lfd, stb.st_mode & 0776) < 0)
12716762Sralph 			syslog(LOG_ERR, "%s: %s: %m", printer, LO);
12813169Sralph 	}
12912463Sralph 	openpr();			/* open printer or remote */
13012463Sralph again:
13112111Sralph 	/*
13212111Sralph 	 * we found something to do now do it --
13312111Sralph 	 *    write the name of the current control file into the lock file
13412111Sralph 	 *    so the spool queue program can tell what we're working on
13512111Sralph 	 */
13612111Sralph 	for (qp = queue; nitems--; free((char *) q)) {
13712111Sralph 		q = *qp++;
13812111Sralph 		if (stat(q->q_name, &stb) < 0)
13912111Sralph 			continue;
14012463Sralph 	restart:
14112111Sralph 		(void) lseek(lfd, pidoff, 0);
14212111Sralph 		(void) sprintf(line, "%s\n", q->q_name);
14312111Sralph 		i = strlen(line);
14412111Sralph 		if (write(lfd, line, i) != i)
14516762Sralph 			syslog(LOG_ERR, "%s: %s: %m", printer, LO);
14612111Sralph 		if (!remote)
14712111Sralph 			i = printit(q->q_name);
14812111Sralph 		else
14912111Sralph 			i = sendit(q->q_name);
15012463Sralph 		/*
15113169Sralph 		 * Check to see if we are supposed to stop printing or
15213169Sralph 		 * if we are to rebuild the queue.
15312463Sralph 		 */
15413169Sralph 		if (fstat(lfd, &stb) == 0) {
15516762Sralph 			/* stop printing before starting next job? */
15613169Sralph 			if (stb.st_mode & 0100)
15713169Sralph 				goto done;
15816762Sralph 			/* rebuild queue (after lpc topq) */
15913169Sralph 			if (stb.st_mode & 01) {
16013169Sralph 				for (free((char *) q); nitems--; free((char *) q))
16113169Sralph 					q = *qp++;
16213169Sralph 				if (fchmod(lfd, stb.st_mode & 0776) < 0)
16316762Sralph 					syslog(LOG_WARNING, "%s: %s: %m",
16416762Sralph 						printer, LO);
16513169Sralph 				break;
16613169Sralph 			}
16713169Sralph 		}
16817463Sralph 		if (i == OK)		/* file ok and printed */
16914150Sralph 			count++;
17017463Sralph 		else if (i == REPRINT) { /* try reprinting the job */
17116762Sralph 			syslog(LOG_INFO, "restarting %s", printer);
17212111Sralph 			if (ofilter > 0) {
17312111Sralph 				kill(ofilter, SIGCONT);	/* to be sure */
17412111Sralph 				(void) close(ofd);
17512111Sralph 				while ((i = wait(0)) > 0 && i != ofilter)
17612111Sralph 					;
17712111Sralph 				ofilter = 0;
17812111Sralph 			}
17912463Sralph 			(void) close(pfd);	/* close printer */
18015811Sralph 			if (ftruncate(lfd, pidoff) < 0)
18116762Sralph 				syslog(LOG_WARNING, "%s: %s: %m", printer, LO);
18212463Sralph 			openpr();		/* try to reopen printer */
18312111Sralph 			goto restart;
18412111Sralph 		}
18512111Sralph 	}
18612111Sralph 	free((char *) queue);
18712463Sralph 	/*
18812463Sralph 	 * search the spool directory for more work.
18912463Sralph 	 */
19012463Sralph 	if ((nitems = getq(&queue)) < 0) {
19116762Sralph 		syslog(LOG_ERR, "%s: can't scan %s", printer, SD);
19212463Sralph 		exit(1);
19312463Sralph 	}
19412463Sralph 	if (nitems == 0) {		/* no more work to do */
19512463Sralph 	done:
19614150Sralph 		if (count > 0) {	/* Files actually printed */
19714150Sralph 			if (!SF && !tof)
19814150Sralph 				(void) write(ofd, FF, strlen(FF));
19914150Sralph 			if (TR != NULL)		/* output trailer */
20014150Sralph 				(void) write(ofd, TR, strlen(TR));
20114150Sralph 		}
20215811Sralph 		(void) unlink(tmpfile);
20312463Sralph 		exit(0);
20412463Sralph 	}
20512111Sralph 	goto again;
20612111Sralph }
20712111Sralph 
20812111Sralph char	fonts[4][50];	/* fonts for troff */
20912111Sralph 
21016762Sralph char ifonts[4][18] = {
21112111Sralph 	"/usr/lib/vfont/R",
21212111Sralph 	"/usr/lib/vfont/I",
21312111Sralph 	"/usr/lib/vfont/B",
21412111Sralph 	"/usr/lib/vfont/S"
21512111Sralph };
21612111Sralph 
21712111Sralph /*
21812111Sralph  * The remaining part is the reading of the control file (cf)
21912111Sralph  * and performing the various actions.
22012111Sralph  */
22112111Sralph printit(file)
22212111Sralph 	char *file;
22312111Sralph {
22412111Sralph 	register int i;
22517463Sralph 	char *cp;
22617463Sralph 	int bombed = OK;
22712111Sralph 
22812111Sralph 	/*
22917463Sralph 	 * open control file; ignore if no longer there.
23012111Sralph 	 */
23112111Sralph 	if ((cfp = fopen(file, "r")) == NULL) {
23216762Sralph 		syslog(LOG_INFO, "%s: %s: %m", printer, file);
23317463Sralph 		return(OK);
23412111Sralph 	}
23512111Sralph 	/*
23612111Sralph 	 * Reset troff fonts.
23712111Sralph 	 */
23812111Sralph 	for (i = 0; i < 4; i++)
23912111Sralph 		strcpy(fonts[i], ifonts[i]);
24017339Sralph 	strcpy(width+2, "0");
24117302Sralph 	strcpy(indent+2, "0");
24212111Sralph 
24312111Sralph 	/*
24412111Sralph 	 *      read the control file for work to do
24512111Sralph 	 *
24612111Sralph 	 *      file format -- first character in the line is a command
24712111Sralph 	 *      rest of the line is the argument.
24812111Sralph 	 *      valid commands are:
24912111Sralph 	 *
25017463Sralph 	 *		S -- "stat info" for symbolic link protection
25112111Sralph 	 *		J -- "job name" on banner page
25212111Sralph 	 *		C -- "class name" on banner page
25312111Sralph 	 *              L -- "literal" user's name to print on banner
25412111Sralph 	 *		T -- "title" for pr
25512111Sralph 	 *		H -- "host name" of machine where lpr was done
25612111Sralph 	 *              P -- "person" user's login name
25712581Sralph 	 *              I -- "indent" amount to indent output
25812111Sralph 	 *              f -- "file name" name of text file to print
25912111Sralph 	 *		l -- "file name" text file with control chars
26012111Sralph 	 *		p -- "file name" text file to print with pr(1)
26112111Sralph 	 *		t -- "file name" troff(1) file to print
26213233Sralph 	 *		n -- "file name" ditroff(1) file to print
26312111Sralph 	 *		d -- "file name" dvi file to print
26412111Sralph 	 *		g -- "file name" plot(1G) file to print
26512111Sralph 	 *		v -- "file name" plain raster file to print
26612111Sralph 	 *		c -- "file name" cifplot file to print
26712111Sralph 	 *		1 -- "R font file" for troff
26812111Sralph 	 *		2 -- "I font file" for troff
26912111Sralph 	 *		3 -- "B font file" for troff
27012111Sralph 	 *		4 -- "S font file" for troff
27112111Sralph 	 *		N -- "name" of file (used by lpq)
27212111Sralph 	 *              U -- "unlink" name of file to remove
27312111Sralph 	 *                    (after we print it. (Pass 2 only)).
27412111Sralph 	 *		M -- "mail" to user when done printing
27512111Sralph 	 *
27612111Sralph 	 *      getline reads a line and expands tabs to blanks
27712111Sralph 	 */
27812111Sralph 
27912111Sralph 	/* pass 1 */
28012111Sralph 
28112111Sralph 	while (getline(cfp))
28212111Sralph 		switch (line[0]) {
28312111Sralph 		case 'H':
28414150Sralph 			strcpy(fromhost, line+1);
28512111Sralph 			if (class[0] == '\0')
28615552Sralph 				strncpy(class, line+1, sizeof(class)-1);
28712111Sralph 			continue;
28812111Sralph 
28912111Sralph 		case 'P':
29015552Sralph 			strncpy(logname, line+1, sizeof(logname)-1);
29112463Sralph 			if (RS) {			/* restricted */
29212463Sralph 				if (getpwnam(logname) == (struct passwd *)0) {
29317463Sralph 					bombed = NOACCT;
29415811Sralph 					sendmail(line+1, bombed);
29512463Sralph 					goto pass2;
29612463Sralph 				}
29712463Sralph 			}
29812111Sralph 			continue;
29912111Sralph 
30017463Sralph 		case 'S':
30117463Sralph 			cp = line+1;
30217463Sralph 			i = 0;
30317463Sralph 			while (*cp >= '0' && *cp <= '9')
30417463Sralph 				i = i * 10 + (*cp++ - '0');
30517463Sralph 			fdev = i;
30617463Sralph 			cp++;
30717463Sralph 			i = 0;
30817463Sralph 			while (*cp >= '0' && *cp <= '9')
30917463Sralph 				i = i * 10 + (*cp++ - '0');
31017463Sralph 			fino = i;
31117463Sralph 			continue;
31217463Sralph 
31312111Sralph 		case 'J':
31412111Sralph 			if (line[1] != '\0')
31515552Sralph 				strncpy(jobname, line+1, sizeof(jobname)-1);
31612111Sralph 			else
31712111Sralph 				strcpy(jobname, " ");
31812111Sralph 			continue;
31912111Sralph 
32012111Sralph 		case 'C':
32112111Sralph 			if (line[1] != '\0')
32215552Sralph 				strncpy(class, line+1, sizeof(class)-1);
32312111Sralph 			else if (class[0] == '\0')
32415811Sralph 				gethostname(class, sizeof(class));
32512111Sralph 			continue;
32612111Sralph 
32712111Sralph 		case 'T':	/* header title for pr */
32815552Sralph 			strncpy(title, line+1, sizeof(title)-1);
32912111Sralph 			continue;
33012111Sralph 
33112111Sralph 		case 'L':	/* identification line */
33218127Sralph 			if (!SH && !HL)
33312111Sralph 				banner(line+1, jobname);
33412111Sralph 			continue;
33512111Sralph 
33612111Sralph 		case '1':	/* troff fonts */
33712111Sralph 		case '2':
33812111Sralph 		case '3':
33912111Sralph 		case '4':
34012111Sralph 			if (line[1] != '\0')
34112111Sralph 				strcpy(fonts[line[0]-'1'], line+1);
34212111Sralph 			continue;
34312111Sralph 
34412111Sralph 		case 'W':	/* page width */
34515552Sralph 			strncpy(width+2, line+1, sizeof(width)-3);
34612111Sralph 			continue;
34712111Sralph 
34812581Sralph 		case 'I':	/* indent amount */
34915552Sralph 			strncpy(indent+2, line+1, sizeof(indent)-3);
35012581Sralph 			continue;
35112581Sralph 
35212111Sralph 		default:	/* some file to print */
35315811Sralph 			switch (i = print(line[0], line+1)) {
35417463Sralph 			case ERROR:
35517463Sralph 				if (bombed == OK)
35617463Sralph 					bombed = FATALERR;
35715811Sralph 				break;
35817463Sralph 			case REPRINT:
35912111Sralph 				(void) fclose(cfp);
36017463Sralph 				return(REPRINT);
36117463Sralph 			case FILTERERR:
36217463Sralph 			case ACCESS:
36317463Sralph 				bombed = i;
36415811Sralph 				sendmail(logname, bombed);
36515811Sralph 			}
36612111Sralph 			title[0] = '\0';
36712111Sralph 			continue;
36812111Sralph 
36912111Sralph 		case 'N':
37012111Sralph 		case 'U':
37112111Sralph 		case 'M':
37212111Sralph 			continue;
37312111Sralph 		}
37412111Sralph 
37512111Sralph 	/* pass 2 */
37612111Sralph 
37712463Sralph pass2:
37812111Sralph 	fseek(cfp, 0L, 0);
37912111Sralph 	while (getline(cfp))
38012111Sralph 		switch (line[0]) {
38118127Sralph 		case 'L':	/* identification line */
38218127Sralph 			if (!SH && HL)
38318127Sralph 				banner(line+1, jobname);
38418127Sralph 			continue;
38518127Sralph 
38612111Sralph 		case 'M':
38717463Sralph 			if (bombed < NOACCT)	/* already sent if >= NOACCT */
38815811Sralph 				sendmail(line+1, bombed);
38912111Sralph 			continue;
39012111Sralph 
39112111Sralph 		case 'U':
39212111Sralph 			(void) unlink(line+1);
39312111Sralph 		}
39412111Sralph 	/*
39515811Sralph 	 * clean-up in case another control file exists
39612111Sralph 	 */
39712111Sralph 	(void) fclose(cfp);
39812111Sralph 	(void) unlink(file);
39917463Sralph 	return(bombed == OK ? OK : ERROR);
40012111Sralph }
40112111Sralph 
40212111Sralph /*
40312111Sralph  * Print a file.
40413233Sralph  * Set up the chain [ PR [ | {IF, OF} ] ] or {IF, RF, TF, NF, DF, CF, VF}.
40515811Sralph  * Return -1 if a non-recoverable error occured,
40615811Sralph  * 2 if the filter detected some errors (but printed the job anyway),
40715811Sralph  * 1 if we should try to reprint this job and
40812111Sralph  * 0 if all is well.
40912111Sralph  * Note: all filters take stdin as the file, stdout as the printer,
41012111Sralph  * stderr as the log file, and must not ignore SIGINT.
41112111Sralph  */
41212111Sralph print(format, file)
41312111Sralph 	int format;
41412111Sralph 	char *file;
41512111Sralph {
41615811Sralph 	register int n;
41712111Sralph 	register char *prog;
41815811Sralph 	int fi, fo;
41912111Sralph 	char *av[15], buf[BUFSIZ];
42012111Sralph 	int pid, p[2], stopped = 0;
42112111Sralph 	union wait status;
42217463Sralph 	struct stat stb;
42312111Sralph 
42417463Sralph 	if (lstat(file, &stb) < 0 || (fi = open(file, O_RDONLY)) < 0)
42517463Sralph 		return(ERROR);
42617463Sralph 	/*
42717463Sralph 	 * Check to see if data file is a symbolic link. If so, it should
42817463Sralph 	 * still point to the same file or someone is trying to print
42917463Sralph 	 * something he shouldn't.
43017463Sralph 	 */
43117463Sralph 	if ((stb.st_mode & S_IFMT) == S_IFLNK && fstat(fi, &stb) == 0 &&
43217463Sralph 	    (stb.st_dev != fdev || stb.st_ino != fino))
43317463Sralph 		return(ACCESS);
43412111Sralph 	if (!SF && !tof) {		/* start on a fresh page */
43512111Sralph 		(void) write(ofd, FF, strlen(FF));
43612111Sralph 		tof = 1;
43712111Sralph 	}
43812111Sralph 	if (IF == NULL && (format == 'f' || format == 'l')) {
43912111Sralph 		tof = 0;
44012111Sralph 		while ((n = read(fi, buf, BUFSIZ)) > 0)
44112111Sralph 			if (write(ofd, buf, n) != n) {
44212111Sralph 				(void) close(fi);
44317463Sralph 				return(REPRINT);
44412111Sralph 			}
44512111Sralph 		(void) close(fi);
44617463Sralph 		return(OK);
44712111Sralph 	}
44812111Sralph 	switch (format) {
44912111Sralph 	case 'p':	/* print file using 'pr' */
45012111Sralph 		if (IF == NULL) {	/* use output filter */
45112111Sralph 			prog = PR;
45212111Sralph 			av[0] = "pr";
45312111Sralph 			av[1] = width;
45412111Sralph 			av[2] = length;
45512111Sralph 			av[3] = "-h";
45612111Sralph 			av[4] = *title ? title : " ";
45712111Sralph 			av[5] = 0;
45812111Sralph 			fo = ofd;
45912111Sralph 			goto start;
46012111Sralph 		}
46112111Sralph 		pipe(p);
46212111Sralph 		if ((prchild = dofork(DORETURN)) == 0) {	/* child */
46312111Sralph 			dup2(fi, 0);		/* file is stdin */
46412111Sralph 			dup2(p[1], 1);		/* pipe is stdout */
46512111Sralph 			for (n = 3; n < NOFILE; n++)
46612111Sralph 				(void) close(n);
46712111Sralph 			execl(PR, "pr", width, length, "-h", *title ? title : " ", 0);
46816762Sralph 			syslog(LOG_ERR, "cannot execl %s", PR);
46912111Sralph 			exit(2);
47012111Sralph 		}
47112111Sralph 		(void) close(p[1]);		/* close output side */
47212111Sralph 		(void) close(fi);
47312111Sralph 		if (prchild < 0) {
47412111Sralph 			prchild = 0;
47512111Sralph 			(void) close(p[0]);
47617463Sralph 			return(ERROR);
47712111Sralph 		}
47812111Sralph 		fi = p[0];			/* use pipe for input */
47912111Sralph 	case 'f':	/* print plain text file */
48012111Sralph 		prog = IF;
48112111Sralph 		av[1] = width;
48212111Sralph 		av[2] = length;
48312581Sralph 		av[3] = indent;
48412581Sralph 		n = 4;
48512111Sralph 		break;
48612111Sralph 	case 'l':	/* like 'f' but pass control characters */
48712111Sralph 		prog = IF;
48814325Sralph 		av[1] = "-c";
48912111Sralph 		av[2] = width;
49012111Sralph 		av[3] = length;
49112581Sralph 		av[4] = indent;
49212581Sralph 		n = 5;
49312111Sralph 		break;
49412463Sralph 	case 'r':	/* print a fortran text file */
49512463Sralph 		prog = RF;
49612463Sralph 		av[1] = width;
49712463Sralph 		av[2] = length;
49812463Sralph 		n = 3;
49912463Sralph 		break;
50012111Sralph 	case 't':	/* print troff output */
50113233Sralph 	case 'n':	/* print ditroff output */
50212463Sralph 	case 'd':	/* print tex output */
50312111Sralph 		(void) unlink(".railmag");
50412463Sralph 		if ((fo = creat(".railmag", FILMOD)) < 0) {
50516762Sralph 			syslog(LOG_ERR, "%s: cannot create .railmag", printer);
50612111Sralph 			(void) unlink(".railmag");
50712111Sralph 		} else {
50812111Sralph 			for (n = 0; n < 4; n++) {
50912111Sralph 				if (fonts[n][0] != '/')
51012111Sralph 					(void) write(fo, "/usr/lib/vfont/", 15);
51112111Sralph 				(void) write(fo, fonts[n], strlen(fonts[n]));
51212111Sralph 				(void) write(fo, "\n", 1);
51312111Sralph 			}
51412111Sralph 			(void) close(fo);
51512111Sralph 		}
51613233Sralph 		prog = (format == 't') ? TF : (format == 'n') ? NF : DF;
51712463Sralph 		av[1] = pxwidth;
51812463Sralph 		av[2] = pxlength;
51912463Sralph 		n = 3;
52012111Sralph 		break;
52112111Sralph 	case 'c':	/* print cifplot output */
52212111Sralph 		prog = CF;
52312463Sralph 		av[1] = pxwidth;
52412463Sralph 		av[2] = pxlength;
52512463Sralph 		n = 3;
52612111Sralph 		break;
52712111Sralph 	case 'g':	/* print plot(1G) output */
52812111Sralph 		prog = GF;
52912463Sralph 		av[1] = pxwidth;
53012463Sralph 		av[2] = pxlength;
53112463Sralph 		n = 3;
53212111Sralph 		break;
53312111Sralph 	case 'v':	/* print raster output */
53412111Sralph 		prog = VF;
53512463Sralph 		av[1] = pxwidth;
53612463Sralph 		av[2] = pxlength;
53712463Sralph 		n = 3;
53812111Sralph 		break;
53912111Sralph 	default:
54012111Sralph 		(void) close(fi);
54116762Sralph 		syslog(LOG_ERR, "%s: illegal format character '%c'",
54216762Sralph 			printer, format);
54317463Sralph 		return(ERROR);
54412111Sralph 	}
54512111Sralph 	if ((av[0] = rindex(prog, '/')) != NULL)
54612111Sralph 		av[0]++;
54712111Sralph 	else
54812111Sralph 		av[0] = prog;
54912111Sralph 	av[n++] = "-n";
55012111Sralph 	av[n++] = logname;
55112111Sralph 	av[n++] = "-h";
55214150Sralph 	av[n++] = fromhost;
55312111Sralph 	av[n++] = AF;
55412111Sralph 	av[n] = 0;
55512111Sralph 	fo = pfd;
55612111Sralph 	if (ofilter > 0) {		/* stop output filter */
55712111Sralph 		write(ofd, "\031\1", 2);
55812111Sralph 		while ((pid = wait3(&status, WUNTRACED, 0)) > 0 && pid != ofilter)
55912111Sralph 			;
56012111Sralph 		if (status.w_stopval != WSTOPPED) {
56112111Sralph 			(void) close(fi);
56216762Sralph 			syslog(LOG_WARNING, "%s: output filter died (%d)",
56316762Sralph 				printer, status.w_retcode);
56417463Sralph 			return(REPRINT);
56512111Sralph 		}
56612111Sralph 		stopped++;
56712111Sralph 	}
56812111Sralph start:
56912111Sralph 	if ((child = dofork(DORETURN)) == 0) {	/* child */
57012111Sralph 		dup2(fi, 0);
57112111Sralph 		dup2(fo, 1);
57217304Sralph 		n = open(tmpfile, O_WRONLY|O_CREAT|O_TRUNC, 0664);
57315811Sralph 		if (n >= 0)
57415811Sralph 			dup2(n, 2);
57512111Sralph 		for (n = 3; n < NOFILE; n++)
57612111Sralph 			(void) close(n);
57712111Sralph 		execv(prog, av);
57816762Sralph 		syslog(LOG_ERR, "cannot execv %s", prog);
57912111Sralph 		exit(2);
58012111Sralph 	}
58112111Sralph 	(void) close(fi);
58212111Sralph 	if (child < 0)
58312111Sralph 		status.w_retcode = 100;
58412111Sralph 	else
58512111Sralph 		while ((pid = wait(&status)) > 0 && pid != child)
58612111Sralph 			;
58712111Sralph 	child = 0;
58812111Sralph 	prchild = 0;
58912111Sralph 	if (stopped) {		/* restart output filter */
59012111Sralph 		if (kill(ofilter, SIGCONT) < 0) {
59116762Sralph 			syslog(LOG_ERR, "cannot restart output filter");
59212111Sralph 			exit(1);
59312111Sralph 		}
59412111Sralph 	}
59512111Sralph 	tof = 0;
59615811Sralph 	if (!WIFEXITED(status)) {
59716762Sralph 		syslog(LOG_WARNING, "%s: Daemon filter '%c' terminated (%d)",
59816762Sralph 			printer, format, status.w_termsig);
59917463Sralph 		return(ERROR);
60017463Sralph 	}
60117463Sralph 	switch (status.w_retcode) {
60217463Sralph 	case 0:
60317463Sralph 		tof = 1;
60417463Sralph 		return(OK);
60517463Sralph 	case 1:
60617463Sralph 		return(REPRINT);
60717463Sralph 	default:
60816762Sralph 		syslog(LOG_WARNING, "%s: Daemon filter '%c' exited (%d)",
60916762Sralph 			printer, format, status.w_retcode);
61017463Sralph 	case 2:
61117463Sralph 		return(ERROR);
61217463Sralph 	}
61312111Sralph }
61412111Sralph 
61512111Sralph /*
61612111Sralph  * Send the daemon control file (cf) and any data files.
61712111Sralph  * Return -1 if a non-recoverable error occured, 1 if a recoverable error and
61812111Sralph  * 0 if all is well.
61912111Sralph  */
62012111Sralph sendit(file)
62112111Sralph 	char *file;
62212111Sralph {
62317463Sralph 	register int i, err = OK;
62417463Sralph 	char *cp, last[BUFSIZ];
62512111Sralph 
62612111Sralph 	/*
62712111Sralph 	 * open control file
62812111Sralph 	 */
62916762Sralph 	if ((cfp = fopen(file, "r")) == NULL)
63017463Sralph 		return(OK);
63112111Sralph 	/*
63212111Sralph 	 *      read the control file for work to do
63312111Sralph 	 *
63412111Sralph 	 *      file format -- first character in the line is a command
63512111Sralph 	 *      rest of the line is the argument.
63612111Sralph 	 *      commands of interest are:
63712111Sralph 	 *
63812111Sralph 	 *            a-z -- "file name" name of file to print
63912111Sralph 	 *              U -- "unlink" name of file to remove
64012111Sralph 	 *                    (after we print it. (Pass 2 only)).
64112111Sralph 	 */
64212111Sralph 
64312111Sralph 	/*
64412111Sralph 	 * pass 1
64512111Sralph 	 */
64612111Sralph 	while (getline(cfp)) {
64712111Sralph 	again:
64817463Sralph 		if (line[0] == 'S') {
64917463Sralph 			cp = line+1;
65017463Sralph 			i = 0;
65117463Sralph 			while (*cp >= '0' && *cp <= '9')
65217463Sralph 				i = i * 10 + (*cp++ - '0');
65317463Sralph 			fdev = i;
65417463Sralph 			cp++;
65517463Sralph 			i = 0;
65617463Sralph 			while (*cp >= '0' && *cp <= '9')
65717463Sralph 				i = i * 10 + (*cp++ - '0');
65817463Sralph 			fino = i;
65917463Sralph 			continue;
66017463Sralph 		}
66112111Sralph 		if (line[0] >= 'a' && line[0] <= 'z') {
66212111Sralph 			strcpy(last, line);
66317463Sralph 			while (i = getline(cfp))
66412111Sralph 				if (strcmp(last, line))
66512111Sralph 					break;
66617463Sralph 			switch (sendfile('\3', last+1)) {
66717463Sralph 			case OK:
66817463Sralph 				if (i)
66917463Sralph 					goto again;
67017463Sralph 				break;
67117463Sralph 			case REPRINT:
67212111Sralph 				(void) fclose(cfp);
67317463Sralph 				return(REPRINT);
67417463Sralph 			case ACCESS:
67517463Sralph 				sendmail(logname, ACCESS);
67617463Sralph 			case ERROR:
67717463Sralph 				err = ERROR;
67817463Sralph 			}
67912111Sralph 			break;
68012111Sralph 		}
68112111Sralph 	}
68217463Sralph 	if (err == OK && sendfile('\2', file) > 0) {
68312111Sralph 		(void) fclose(cfp);
68417463Sralph 		return(REPRINT);
68512111Sralph 	}
68612111Sralph 	/*
68712111Sralph 	 * pass 2
68812111Sralph 	 */
68912111Sralph 	fseek(cfp, 0L, 0);
69012111Sralph 	while (getline(cfp))
69112111Sralph 		if (line[0] == 'U')
69212111Sralph 			(void) unlink(line+1);
69312111Sralph 	/*
69417463Sralph 	 * clean-up in case another control file exists
69512111Sralph 	 */
69612111Sralph 	(void) fclose(cfp);
69712111Sralph 	(void) unlink(file);
69817463Sralph 	return(err);
69912111Sralph }
70012111Sralph 
70112111Sralph /*
70212111Sralph  * Send a data file to the remote machine and spool it.
70312111Sralph  * Return positive if we should try resending.
70412111Sralph  */
70512111Sralph sendfile(type, file)
70612111Sralph 	char type, *file;
70712111Sralph {
70812111Sralph 	register int f, i, amt;
70912111Sralph 	struct stat stb;
71012111Sralph 	char buf[BUFSIZ];
71116762Sralph 	int sizerr, resp;
71212111Sralph 
71317463Sralph 	if (lstat(file, &stb) < 0 || (f = open(file, O_RDONLY)) < 0)
71417463Sralph 		return(ERROR);
71517463Sralph 	/*
71617463Sralph 	 * Check to see if data file is a symbolic link. If so, it should
71717463Sralph 	 * still point to the same file or someone is trying to print something
71817463Sralph 	 * he shouldn't.
71917463Sralph 	 */
72017463Sralph 	if ((stb.st_mode & S_IFMT) == S_IFLNK && fstat(f, &stb) == 0 &&
72117463Sralph 	    (stb.st_dev != fdev || stb.st_ino != fino))
72217463Sralph 		return(ACCESS);
72312111Sralph 	(void) sprintf(buf, "%c%d %s\n", type, stb.st_size, file);
72412111Sralph 	amt = strlen(buf);
72516762Sralph 	for (i = 0;  ; i++) {
72616762Sralph 		if (write(pfd, buf, amt) != amt ||
72716762Sralph 		    (resp = response()) < 0 || resp == '\1') {
72816762Sralph 			(void) close(f);
72917463Sralph 			return(REPRINT);
73016762Sralph 		} else if (resp == '\0')
73116762Sralph 			break;
73216762Sralph 		if (i == 0)
73316762Sralph 			status("no space on remote; waiting for queue to drain");
73416762Sralph 		if (i == 10)
73524861Seric 			syslog(LOG_ALERT, "%s: can't send to %s; queue full",
73616762Sralph 				printer, RM);
73716762Sralph 		sleep(5 * 60);
73812692Sralph 	}
73916762Sralph 	if (i)
74016762Sralph 		status("sending to %s", RM);
74112111Sralph 	sizerr = 0;
74212111Sralph 	for (i = 0; i < stb.st_size; i += BUFSIZ) {
74312111Sralph 		amt = BUFSIZ;
74412111Sralph 		if (i + amt > stb.st_size)
74512111Sralph 			amt = stb.st_size - i;
74612111Sralph 		if (sizerr == 0 && read(f, buf, amt) != amt)
74712111Sralph 			sizerr = 1;
74812692Sralph 		if (write(pfd, buf, amt) != amt) {
74912692Sralph 			(void) close(f);
75017463Sralph 			return(REPRINT);
75112692Sralph 		}
75212111Sralph 	}
75312111Sralph 	(void) close(f);
75412111Sralph 	if (sizerr) {
75516762Sralph 		syslog(LOG_INFO, "%s: %s: changed size", printer, file);
75617463Sralph 		/* tell recvjob to ignore this file */
75717463Sralph 		(void) write(pfd, "\1", 1);
75817463Sralph 		return(ERROR);
75917463Sralph 	}
76017463Sralph 	if (write(pfd, "", 1) != 1 || response())
76117463Sralph 		return(REPRINT);
76217463Sralph 	return(OK);
76312111Sralph }
76412111Sralph 
76512111Sralph /*
76612111Sralph  * Check to make sure there have been no errors and that both programs
76712111Sralph  * are in sync with eachother.
76812111Sralph  * Return non-zero if the connection was lost.
76912111Sralph  */
77016762Sralph response()
77112111Sralph {
77212111Sralph 	char resp;
77312111Sralph 
77416762Sralph 	if (read(pfd, &resp, 1) != 1) {
77516762Sralph 		syslog(LOG_INFO, "%s: lost connection", printer);
77616762Sralph 		return(-1);
77712111Sralph 	}
77816762Sralph 	return(resp);
77912111Sralph }
78012111Sralph 
78112111Sralph /*
78212111Sralph  * Banner printing stuff
78312111Sralph  */
78412111Sralph banner(name1, name2)
78512111Sralph 	char *name1, *name2;
78612111Sralph {
78712111Sralph 	time_t tvec;
78812111Sralph 	extern char *ctime();
78912111Sralph 
79012111Sralph 	time(&tvec);
79112111Sralph 	if (!SF && !tof)
79212111Sralph 		(void) write(ofd, FF, strlen(FF));
79312111Sralph 	if (SB) {	/* short banner only */
79412111Sralph 		if (class[0]) {
79512111Sralph 			(void) write(ofd, class, strlen(class));
79612111Sralph 			(void) write(ofd, ":", 1);
79712111Sralph 		}
79812111Sralph 		(void) write(ofd, name1, strlen(name1));
79912111Sralph 		(void) write(ofd, "  Job: ", 7);
80012111Sralph 		(void) write(ofd, name2, strlen(name2));
80112111Sralph 		(void) write(ofd, "  Date: ", 8);
80212111Sralph 		(void) write(ofd, ctime(&tvec), 24);
80312111Sralph 		(void) write(ofd, "\n", 1);
80412111Sralph 	} else {	/* normal banner */
80512111Sralph 		(void) write(ofd, "\n\n\n", 3);
80612111Sralph 		scan_out(ofd, name1, '\0');
80712111Sralph 		(void) write(ofd, "\n\n", 2);
80812111Sralph 		scan_out(ofd, name2, '\0');
80912111Sralph 		if (class[0]) {
81012111Sralph 			(void) write(ofd,"\n\n\n",3);
81112111Sralph 			scan_out(ofd, class, '\0');
81212111Sralph 		}
81312111Sralph 		(void) write(ofd, "\n\n\n\n\t\t\t\t\tJob:  ", 15);
81412111Sralph 		(void) write(ofd, name2, strlen(name2));
81512111Sralph 		(void) write(ofd, "\n\t\t\t\t\tDate: ", 12);
81612111Sralph 		(void) write(ofd, ctime(&tvec), 24);
81712111Sralph 		(void) write(ofd, "\n", 1);
81812111Sralph 	}
81912111Sralph 	if (!SF)
82012111Sralph 		(void) write(ofd, FF, strlen(FF));
82112111Sralph 	tof = 1;
82212111Sralph }
82312111Sralph 
82416762Sralph char *
82512111Sralph scnline(key, p, c)
82612111Sralph 	register char key, *p;
82712111Sralph 	char c;
82812111Sralph {
82912111Sralph 	register scnwidth;
83012111Sralph 
83112111Sralph 	for (scnwidth = WIDTH; --scnwidth;) {
83212111Sralph 		key <<= 1;
83312111Sralph 		*p++ = key & 0200 ? c : BACKGND;
83412111Sralph 	}
83512111Sralph 	return (p);
83612111Sralph }
83712111Sralph 
83812111Sralph #define TRC(q)	(((q)-' ')&0177)
83912111Sralph 
84012111Sralph scan_out(scfd, scsp, dlm)
84112111Sralph 	int scfd;
84212111Sralph 	char *scsp, dlm;
84312111Sralph {
84412111Sralph 	register char *strp;
84512111Sralph 	register nchrs, j;
84612111Sralph 	char outbuf[LINELEN+1], *sp, c, cc;
84712111Sralph 	int d, scnhgt;
84812111Sralph 	extern char scnkey[][HEIGHT];	/* in lpdchar.c */
84912111Sralph 
85012111Sralph 	for (scnhgt = 0; scnhgt++ < HEIGHT+DROP; ) {
85112111Sralph 		strp = &outbuf[0];
85212111Sralph 		sp = scsp;
85312111Sralph 		for (nchrs = 0; ; ) {
85412111Sralph 			d = dropit(c = TRC(cc = *sp++));
85512111Sralph 			if ((!d && scnhgt > HEIGHT) || (scnhgt <= DROP && d))
85612111Sralph 				for (j = WIDTH; --j;)
85712111Sralph 					*strp++ = BACKGND;
85812111Sralph 			else
85912111Sralph 				strp = scnline(scnkey[c][scnhgt-1-d], strp, cc);
86012111Sralph 			if (*sp == dlm || *sp == '\0' || nchrs++ >= PW/(WIDTH+1)-1)
86112111Sralph 				break;
86212111Sralph 			*strp++ = BACKGND;
86312111Sralph 			*strp++ = BACKGND;
86412111Sralph 		}
86512111Sralph 		while (*--strp == BACKGND && strp >= outbuf)
86612111Sralph 			;
86712111Sralph 		strp++;
86812111Sralph 		*strp++ = '\n';
86912111Sralph 		(void) write(scfd, outbuf, strp-outbuf);
87012111Sralph 	}
87112111Sralph }
87212111Sralph 
87312111Sralph dropit(c)
87412111Sralph 	char c;
87512111Sralph {
87612111Sralph 	switch(c) {
87712111Sralph 
87812111Sralph 	case TRC('_'):
87912111Sralph 	case TRC(';'):
88012111Sralph 	case TRC(','):
88112111Sralph 	case TRC('g'):
88212111Sralph 	case TRC('j'):
88312111Sralph 	case TRC('p'):
88412111Sralph 	case TRC('q'):
88512111Sralph 	case TRC('y'):
88612111Sralph 		return (DROP);
88712111Sralph 
88812111Sralph 	default:
88912111Sralph 		return (0);
89012111Sralph 	}
89112111Sralph }
89212111Sralph 
89312111Sralph /*
89412111Sralph  * sendmail ---
89512111Sralph  *   tell people about job completion
89612111Sralph  */
89715811Sralph sendmail(user, bombed)
89815811Sralph 	char *user;
89912111Sralph 	int bombed;
90012111Sralph {
90112111Sralph 	register int i;
90215811Sralph 	int p[2], s;
90312111Sralph 	register char *cp;
90412111Sralph 	char buf[100];
90515811Sralph 	struct stat stb;
90615811Sralph 	FILE *fp;
90712111Sralph 
90812111Sralph 	pipe(p);
90915811Sralph 	if ((s = dofork(DORETURN)) == 0) {		/* child */
91012111Sralph 		dup2(p[0], 0);
91112111Sralph 		for (i = 3; i < NOFILE; i++)
91212111Sralph 			(void) close(i);
91312111Sralph 		if ((cp = rindex(MAIL, '/')) != NULL)
91412111Sralph 			cp++;
91512111Sralph 		else
91612111Sralph 			cp = MAIL;
91715811Sralph 		sprintf(buf, "%s@%s", user, fromhost);
91812111Sralph 		execl(MAIL, cp, buf, 0);
91912111Sralph 		exit(0);
92015811Sralph 	} else if (s > 0) {				/* parent */
92112111Sralph 		dup2(p[1], 1);
92215811Sralph 		printf("To: %s@%s\n", user, fromhost);
92312111Sralph 		printf("Subject: printer job\n\n");
92412111Sralph 		printf("Your printer job ");
92512111Sralph 		if (*jobname)
92612111Sralph 			printf("(%s) ", jobname);
92712463Sralph 		switch (bombed) {
92817463Sralph 		case OK:
92912463Sralph 			printf("\ncompleted successfully\n");
93012463Sralph 			break;
93112463Sralph 		default:
93217463Sralph 		case FATALERR:
93312463Sralph 			printf("\ncould not be printed\n");
93412463Sralph 			break;
93517463Sralph 		case NOACCT:
93612463Sralph 			printf("\ncould not be printed without an account on %s\n", host);
93712463Sralph 			break;
93817463Sralph 		case FILTERERR:
93915811Sralph 			if (stat(tmpfile, &stb) < 0 || stb.st_size == 0 ||
94015811Sralph 			    (fp = fopen(tmpfile, "r")) == NULL) {
94115811Sralph 				printf("\nwas printed but had some errors\n");
94215811Sralph 				break;
94315811Sralph 			}
94415811Sralph 			printf("\nwas printed but had the following errors:\n");
94515811Sralph 			while ((i = getc(fp)) != EOF)
94615811Sralph 				putchar(i);
94715811Sralph 			(void) fclose(fp);
94817463Sralph 			break;
94917463Sralph 		case ACCESS:
95017463Sralph 			printf("\nwas not printed because it was not linked to the original file\n");
95112463Sralph 		}
95212111Sralph 		fflush(stdout);
95312111Sralph 		(void) close(1);
95412111Sralph 	}
95512111Sralph 	(void) close(p[0]);
95612111Sralph 	(void) close(p[1]);
95715811Sralph 	wait(&s);
95812111Sralph }
95912111Sralph 
96012111Sralph /*
96112111Sralph  * dofork - fork with retries on failure
96212111Sralph  */
96312111Sralph dofork(action)
96412111Sralph 	int action;
96512111Sralph {
96612111Sralph 	register int i, pid;
96712111Sralph 
96812111Sralph 	for (i = 0; i < 20; i++) {
96912463Sralph 		if ((pid = fork()) < 0) {
97012111Sralph 			sleep((unsigned)(i*i));
97112463Sralph 			continue;
97212463Sralph 		}
97312463Sralph 		/*
97412463Sralph 		 * Child should run as daemon instead of root
97512463Sralph 		 */
97612463Sralph 		if (pid == 0)
97712463Sralph 			setuid(DU);
97812463Sralph 		return(pid);
97912111Sralph 	}
98016762Sralph 	syslog(LOG_ERR, "can't fork");
98112111Sralph 
98212111Sralph 	switch (action) {
98312111Sralph 	case DORETURN:
98412111Sralph 		return (-1);
98512111Sralph 	default:
98616762Sralph 		syslog(LOG_ERR, "bad action (%d) to dofork", action);
98712111Sralph 		/*FALL THRU*/
98812111Sralph 	case DOABORT:
98912111Sralph 		exit(1);
99012111Sralph 	}
99112111Sralph 	/*NOTREACHED*/
99212111Sralph }
99312111Sralph 
99412111Sralph /*
99516762Sralph  * Kill child processes to abort current job.
99612111Sralph  */
99716762Sralph abortpr()
99812111Sralph {
99915811Sralph 	(void) unlink(tmpfile);
100012111Sralph 	kill(0, SIGINT);
100112111Sralph 	if (ofilter > 0)
100212111Sralph 		kill(ofilter, SIGCONT);
100312111Sralph 	while (wait(0) > 0)
100412111Sralph 		;
100512111Sralph 	exit(0);
100612111Sralph }
100712111Sralph 
100812111Sralph init()
100912111Sralph {
101012111Sralph 	int status;
101112111Sralph 
101225468Stef 	if ((status = pgetent(line, printer)) < 0) {
101325468Stef 		syslog(LOG_ERR, "can't open printer description file");
101425468Stef 		exit(1);
101525468Stef 	} else if (status == 0) {
101625468Stef 		syslog(LOG_ERR, "unknown printer: %s", printer);
101725468Stef 		exit(1);
101825468Stef 	}
101912111Sralph 	if ((LP = pgetstr("lp", &bp)) == NULL)
102012111Sralph 		LP = DEFDEVLP;
102112111Sralph 	if ((RP = pgetstr("rp", &bp)) == NULL)
102212463Sralph 		RP = DEFLP;
102312111Sralph 	if ((LO = pgetstr("lo", &bp)) == NULL)
102412111Sralph 		LO = DEFLOCK;
102512111Sralph 	if ((ST = pgetstr("st", &bp)) == NULL)
102612111Sralph 		ST = DEFSTAT;
102712111Sralph 	if ((LF = pgetstr("lf", &bp)) == NULL)
102812111Sralph 		LF = DEFLOGF;
102912111Sralph 	if ((SD = pgetstr("sd", &bp)) == NULL)
103012111Sralph 		SD = DEFSPOOL;
103112111Sralph 	if ((DU = pgetnum("du")) < 0)
103212111Sralph 		DU = DEFUID;
103312111Sralph 	if ((FF = pgetstr("ff", &bp)) == NULL)
103412111Sralph 		FF = DEFFF;
103512111Sralph 	if ((PW = pgetnum("pw")) < 0)
103612111Sralph 		PW = DEFWIDTH;
103712111Sralph 	sprintf(&width[2], "%d", PW);
103812111Sralph 	if ((PL = pgetnum("pl")) < 0)
103912111Sralph 		PL = DEFLENGTH;
104012111Sralph 	sprintf(&length[2], "%d", PL);
104112463Sralph 	if ((PX = pgetnum("px")) < 0)
104212463Sralph 		PX = 0;
104312463Sralph 	sprintf(&pxwidth[2], "%d", PX);
104412463Sralph 	if ((PY = pgetnum("py")) < 0)
104512463Sralph 		PY = 0;
104612463Sralph 	sprintf(&pxlength[2], "%d", PY);
104712111Sralph 	RM = pgetstr("rm", &bp);
104825468Stef 	/*
104925468Stef 	 * Figure out whether the local machine is the same as the remote
105025468Stef 	 * machine entry (if it exists).  If not, then ignore the local
105125468Stef 	 * queue information.
105225468Stef 	 */
105325468Stef 	 if (RM != (char *) NULL) {
105425468Stef 		char name[256];
105525468Stef 		struct hostent *hp;
105625468Stef 
105725468Stef 		/* get the standard network name of the local host */
105825468Stef 		gethostname(name, sizeof(name));
105925468Stef 		name[sizeof(name)-1] = '\0';
106025468Stef 		hp = gethostbyname(name);
106125468Stef 		if (hp == (struct hostent *) NULL) {
106225468Stef 		    syslog(LOG_ERR,
106325468Stef 			"unable to get network name for local machine %s",
106425468Stef 			name);
106525468Stef 		    goto localcheck_done;
106625468Stef 		} else strcpy(name, hp->h_name);
106725468Stef 
106825468Stef 		/* get the standard network name of RM */
106925468Stef 		hp = gethostbyname(RM);
107025468Stef 		if (hp == (struct hostent *) NULL) {
107125468Stef 		    syslog(LOG_ERR,
107225468Stef 			"unable to get hostname for remote machine %s", RM);
107325468Stef 		    goto localcheck_done;
107425468Stef 		}
107525468Stef 
107625468Stef 		/* if printer is not on local machine, ignore LP */
107725468Stef 		if (strcmp(name, hp->h_name) != 0) *LP = '\0';
107825468Stef 	}
107925468Stef localcheck_done:
108025468Stef 
108112111Sralph 	AF = pgetstr("af", &bp);
108212111Sralph 	OF = pgetstr("of", &bp);
108312111Sralph 	IF = pgetstr("if", &bp);
108412463Sralph 	RF = pgetstr("rf", &bp);
108512111Sralph 	TF = pgetstr("tf", &bp);
108613233Sralph 	NF = pgetstr("nf", &bp);
108712111Sralph 	DF = pgetstr("df", &bp);
108812111Sralph 	GF = pgetstr("gf", &bp);
108912111Sralph 	VF = pgetstr("vf", &bp);
109012111Sralph 	CF = pgetstr("cf", &bp);
109112111Sralph 	TR = pgetstr("tr", &bp);
109212463Sralph 	RS = pgetflag("rs");
109312111Sralph 	SF = pgetflag("sf");
109412111Sralph 	SH = pgetflag("sh");
109512111Sralph 	SB = pgetflag("sb");
109618127Sralph 	HL = pgetflag("hl");
109712111Sralph 	RW = pgetflag("rw");
109812111Sralph 	BR = pgetnum("br");
109912111Sralph 	if ((FC = pgetnum("fc")) < 0)
110012111Sralph 		FC = 0;
110112111Sralph 	if ((FS = pgetnum("fs")) < 0)
110212111Sralph 		FS = 0;
110312111Sralph 	if ((XC = pgetnum("xc")) < 0)
110412111Sralph 		XC = 0;
110512111Sralph 	if ((XS = pgetnum("xs")) < 0)
110612111Sralph 		XS = 0;
110712581Sralph 	tof = !pgetflag("fo");
110812111Sralph }
110912111Sralph 
111012463Sralph /*
111112463Sralph  * Acquire line printer or remote connection.
111212463Sralph  */
111312463Sralph openpr()
111412463Sralph {
111512463Sralph 	register int i, n;
111616762Sralph 	int resp;
111712463Sralph 
111812463Sralph 	if (*LP) {
111912463Sralph 		for (i = 1; ; i = i < 32 ? i << 1 : i) {
112013148Ssam 			pfd = open(LP, RW ? O_RDWR : O_WRONLY);
112112463Sralph 			if (pfd >= 0)
112212463Sralph 				break;
112312463Sralph 			if (errno == ENOENT) {
112416762Sralph 				syslog(LOG_ERR, "%s: %m", LP);
112512463Sralph 				exit(1);
112612463Sralph 			}
112712463Sralph 			if (i == 1)
112812463Sralph 				status("waiting for %s to become ready (offline ?)", printer);
112912463Sralph 			sleep(i);
113012463Sralph 		}
113112463Sralph 		if (isatty(pfd))
113212463Sralph 			setty();
113312463Sralph 		status("%s is ready and printing", printer);
113412463Sralph 	} else if (RM != NULL) {
113516762Sralph 		for (i = 1; ; i = i < 256 ? i << 1 : i) {
113616762Sralph 			resp = -1;
113712528Sralph 			pfd = getport(RM);
113812463Sralph 			if (pfd >= 0) {
113912463Sralph 				(void) sprintf(line, "\2%s\n", RP);
114012463Sralph 				n = strlen(line);
114116762Sralph 				if (write(pfd, line, n) == n &&
114216762Sralph 				    (resp = response()) == '\0')
114312463Sralph 					break;
114416031Sralph 				(void) close(pfd);
114512463Sralph 			}
114616031Sralph 			if (i == 1) {
114716762Sralph 				if (resp < 0)
114816031Sralph 					status("waiting for %s to come up", RM);
114916762Sralph 				else {
115016031Sralph 					status("waiting for queue to be enabled on %s", RM);
115116762Sralph 					i = 256;
115216762Sralph 				}
115316031Sralph 			}
115412463Sralph 			sleep(i);
115512463Sralph 		}
115612463Sralph 		status("sending to %s", RM);
115712463Sralph 		remote = 1;
115812463Sralph 	} else {
115916762Sralph 		syslog(LOG_ERR, "%s: no line printer device or host name",
116016762Sralph 			printer);
116112463Sralph 		exit(1);
116212463Sralph 	}
116312463Sralph 	/*
116412463Sralph 	 * Start up an output filter, if needed.
116512463Sralph 	 */
116612463Sralph 	if (OF) {
116712463Sralph 		int p[2];
116812463Sralph 		char *cp;
116912463Sralph 
117012463Sralph 		pipe(p);
117112463Sralph 		if ((ofilter = dofork(DOABORT)) == 0) {	/* child */
117212463Sralph 			dup2(p[0], 0);		/* pipe is std in */
117312463Sralph 			dup2(pfd, 1);		/* printer is std out */
117412463Sralph 			for (i = 3; i < NOFILE; i++)
117512463Sralph 				(void) close(i);
117612463Sralph 			if ((cp = rindex(OF, '/')) == NULL)
117712463Sralph 				cp = OF;
117812463Sralph 			else
117912463Sralph 				cp++;
118012463Sralph 			execl(OF, cp, width, length, 0);
118116762Sralph 			syslog(LOG_ERR, "%s: %s: %m", printer, OF);
118212463Sralph 			exit(1);
118312463Sralph 		}
118412463Sralph 		(void) close(p[0]);		/* close input side */
118512463Sralph 		ofd = p[1];			/* use pipe for output */
118612463Sralph 	} else {
118712463Sralph 		ofd = pfd;
118812463Sralph 		ofilter = 0;
118912463Sralph 	}
119012463Sralph }
119112463Sralph 
119212111Sralph struct bauds {
119312111Sralph 	int	baud;
119412111Sralph 	int	speed;
119512111Sralph } bauds[] = {
119612111Sralph 	50,	B50,
119712111Sralph 	75,	B75,
119812111Sralph 	110,	B110,
119912111Sralph 	134,	B134,
120012111Sralph 	150,	B150,
120112111Sralph 	200,	B200,
120212111Sralph 	300,	B300,
120312111Sralph 	600,	B600,
120412111Sralph 	1200,	B1200,
120512111Sralph 	1800,	B1800,
120612111Sralph 	2400,	B2400,
120712111Sralph 	4800,	B4800,
120812111Sralph 	9600,	B9600,
120912111Sralph 	19200,	EXTA,
121012111Sralph 	38400,	EXTB,
121112111Sralph 	0,	0
121212111Sralph };
121312111Sralph 
121412111Sralph /*
121512111Sralph  * setup tty lines.
121612111Sralph  */
121712111Sralph setty()
121812111Sralph {
121912111Sralph 	struct sgttyb ttybuf;
122012111Sralph 	register struct bauds *bp;
122112111Sralph 
122212111Sralph 	if (ioctl(pfd, TIOCEXCL, (char *)0) < 0) {
122316762Sralph 		syslog(LOG_ERR, "%s: ioctl(TIOCEXCL): %m", printer);
122412111Sralph 		exit(1);
122512111Sralph 	}
122612111Sralph 	if (ioctl(pfd, TIOCGETP, (char *)&ttybuf) < 0) {
122716762Sralph 		syslog(LOG_ERR, "%s: ioctl(TIOCGETP): %m", printer);
122812111Sralph 		exit(1);
122912111Sralph 	}
123012111Sralph 	if (BR > 0) {
123112111Sralph 		for (bp = bauds; bp->baud; bp++)
123212111Sralph 			if (BR == bp->baud)
123312111Sralph 				break;
123412111Sralph 		if (!bp->baud) {
123516762Sralph 			syslog(LOG_ERR, "%s: illegal baud rate %d", printer, BR);
123612111Sralph 			exit(1);
123712111Sralph 		}
123812111Sralph 		ttybuf.sg_ispeed = ttybuf.sg_ospeed = bp->speed;
123912111Sralph 	}
124013169Sralph 	ttybuf.sg_flags &= ~FC;
124113169Sralph 	ttybuf.sg_flags |= FS;
124212111Sralph 	if (ioctl(pfd, TIOCSETP, (char *)&ttybuf) < 0) {
124316762Sralph 		syslog(LOG_ERR, "%s: ioctl(TIOCSETP): %m", printer);
124412111Sralph 		exit(1);
124512111Sralph 	}
124617168Sralph 	if (XC || XS) {
124717168Sralph 		int ldisc = NTTYDISC;
124817168Sralph 
124917168Sralph 		if (ioctl(pfd, TIOCSETD, &ldisc) < 0) {
125017168Sralph 			syslog(LOG_ERR, "%s: ioctl(TIOCSETD): %m", printer);
125117168Sralph 			exit(1);
125217168Sralph 		}
125317168Sralph 	}
125412111Sralph 	if (XC) {
125512111Sralph 		if (ioctl(pfd, TIOCLBIC, &XC) < 0) {
125616762Sralph 			syslog(LOG_ERR, "%s: ioctl(TIOCLBIC): %m", printer);
125712111Sralph 			exit(1);
125812111Sralph 		}
125912111Sralph 	}
126012111Sralph 	if (XS) {
126112111Sralph 		if (ioctl(pfd, TIOCLBIS, &XS) < 0) {
126216762Sralph 			syslog(LOG_ERR, "%s: ioctl(TIOCLBIS): %m", printer);
126312111Sralph 			exit(1);
126412111Sralph 		}
126512111Sralph 	}
126612111Sralph }
126712463Sralph 
126812463Sralph /*VARARGS1*/
126912463Sralph status(msg, a1, a2, a3)
127012463Sralph 	char *msg;
127112463Sralph {
127212463Sralph 	register int fd;
127312463Sralph 	char buf[BUFSIZ];
127412463Sralph 
127512463Sralph 	umask(0);
127613148Ssam 	fd = open(ST, O_WRONLY|O_CREAT, 0664);
127716762Sralph 	if (fd < 0 || flock(fd, LOCK_EX) < 0) {
127816762Sralph 		syslog(LOG_ERR, "%s: %s: %m", printer, ST);
127916762Sralph 		exit(1);
128016762Sralph 	}
128113148Ssam 	ftruncate(fd, 0);
128212463Sralph 	sprintf(buf, msg, a1, a2, a3);
128312463Sralph 	strcat(buf, "\n");
128412463Sralph 	(void) write(fd, buf, strlen(buf));
128512463Sralph 	(void) close(fd);
128612463Sralph }
1287