xref: /csrg-svn/usr.sbin/lpr/lpd/printjob.c (revision 39954)
122437Sdist /*
222437Sdist  * Copyright (c) 1983 Regents of the University of California.
334203Sbostic  * All rights reserved.
434203Sbostic  *
534203Sbostic  * Redistribution and use in source and binary forms are permitted
634936Sbostic  * provided that the above copyright notice and this paragraph are
734936Sbostic  * duplicated in all such forms and that any documentation,
834936Sbostic  * advertising materials, and other materials related to such
934936Sbostic  * distribution and use acknowledge that the software was developed
1034936Sbostic  * by the University of California, Berkeley.  The name of the
1134936Sbostic  * University may not be used to endorse or promote products derived
1234936Sbostic  * from this software without specific prior written permission.
1334936Sbostic  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
1434936Sbostic  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
1534936Sbostic  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
1622437Sdist  */
1722437Sdist 
1813954Ssam #ifndef lint
19*39954Smckusick static char sccsid[] = "@(#)printjob.c	5.10 (Berkeley) 01/30/90";
2034203Sbostic #endif /* not lint */
2113954Ssam 
2212111Sralph /*
2312111Sralph  * printjob -- print jobs in the queue.
2412111Sralph  *
2512111Sralph  *	NOTE: the lock file is used to pass information to lpq and lprm.
2612111Sralph  *	it does not need to be removed because file locks are dynamic.
2712111Sralph  */
2812111Sralph 
2912111Sralph #include "lp.h"
3037968Sbostic #include "pathnames.h"
3112111Sralph 
3216762Sralph #define DORETURN	0	/* absorb fork error */
3316762Sralph #define DOABORT		1	/* abort if dofork fails */
3412111Sralph 
3517463Sralph /*
3617463Sralph  * Error tokens
3717463Sralph  */
3817463Sralph #define REPRINT		-2
3917463Sralph #define ERROR		-1
4017463Sralph #define	OK		0
4117463Sralph #define	FATALERR	1
4217463Sralph #define	NOACCT		2
4317463Sralph #define	FILTERERR	3
4417463Sralph #define	ACCESS		4
4517463Sralph 
4616762Sralph char	title[80];		/* ``pr'' title */
4716762Sralph FILE	*cfp;			/* control file */
4816762Sralph int	pfd;			/* printer file descriptor */
4916762Sralph int	ofd;			/* output filter file descriptor */
5016762Sralph int	lfd;			/* lock file descriptor */
5116762Sralph int	pid;			/* pid of lpd process */
5216762Sralph int	prchild;		/* id of pr process */
5316762Sralph int	child;			/* id of any filters */
5416762Sralph int	ofilter;		/* id of output filter, if any */
5516762Sralph int	tof;			/* true if at top of form */
5616762Sralph int	remote;			/* true if sending files to remote */
5717463Sralph dev_t	fdev;			/* device of file pointed to by symlink */
5817463Sralph ino_t	fino;			/* inode of file pointed to by symlink */
5912111Sralph 
6016762Sralph char	fromhost[32];		/* user's host machine */
6116762Sralph char	logname[32];		/* user's login name */
6216762Sralph char	jobname[100];		/* job or file name */
6316762Sralph char	class[32];		/* classification field */
6416762Sralph char	width[10] = "-w";	/* page width in characters */
6516762Sralph char	length[10] = "-l";	/* page length in lines */
6616762Sralph char	pxwidth[10] = "-x";	/* page width in pixels */
6716762Sralph char	pxlength[10] = "-y";	/* page length in pixels */
6816762Sralph char	indent[10] = "-i0";	/* indentation size in characters */
69*39954Smckusick char	tempfile[] = "errsXXXXXX"; /* file name for filter output */
7012111Sralph 
7112111Sralph printjob()
7212111Sralph {
7312111Sralph 	struct stat stb;
7412111Sralph 	register struct queue *q, **qp;
7512111Sralph 	struct queue **queue;
7612111Sralph 	register int i, nitems;
7712111Sralph 	long pidoff;
7816762Sralph 	int count = 0;
7916762Sralph 	extern int abortpr();
8012111Sralph 
8112111Sralph 	init();					/* set up capabilities */
8213442Sralph 	(void) write(1, "", 1);			/* ack that daemon is started */
8325496Seric 	(void) close(2);			/* set up log file */
8425496Seric 	if (open(LF, O_WRONLY|O_APPEND, 0664) < 0) {
8525496Seric 		syslog(LOG_ERR, "%s: %m", LF);
8637968Sbostic 		(void) open(_PATH_DEVNULL, O_WRONLY);
8725496Seric 	}
8816762Sralph 	setgid(getegid());
8912463Sralph 	pid = getpid();				/* for use with lprm */
9012111Sralph 	setpgrp(0, pid);
9116762Sralph 	signal(SIGHUP, abortpr);
9216762Sralph 	signal(SIGINT, abortpr);
9316762Sralph 	signal(SIGQUIT, abortpr);
9416762Sralph 	signal(SIGTERM, abortpr);
9512111Sralph 
96*39954Smckusick 	(void) mktemp(tempfile);
9715811Sralph 
9812111Sralph 	/*
9912111Sralph 	 * uses short form file names
10012111Sralph 	 */
10112111Sralph 	if (chdir(SD) < 0) {
10216762Sralph 		syslog(LOG_ERR, "%s: %m", SD);
10312111Sralph 		exit(1);
10412111Sralph 	}
10512463Sralph 	if (stat(LO, &stb) == 0 && (stb.st_mode & 0100))
10612463Sralph 		exit(0);		/* printing disabled */
10714150Sralph 	lfd = open(LO, O_WRONLY|O_CREAT, 0644);
10813169Sralph 	if (lfd < 0) {
10916762Sralph 		syslog(LOG_ERR, "%s: %s: %m", printer, LO);
11013169Sralph 		exit(1);
11113169Sralph 	}
11213169Sralph 	if (flock(lfd, LOCK_EX|LOCK_NB) < 0) {
11312111Sralph 		if (errno == EWOULDBLOCK)	/* active deamon present */
11412111Sralph 			exit(0);
11516762Sralph 		syslog(LOG_ERR, "%s: %s: %m", printer, LO);
11612111Sralph 		exit(1);
11712111Sralph 	}
11813148Ssam 	ftruncate(lfd, 0);
11912111Sralph 	/*
12012111Sralph 	 * write process id for others to know
12112111Sralph 	 */
12212111Sralph 	sprintf(line, "%u\n", pid);
12312111Sralph 	pidoff = i = strlen(line);
12412463Sralph 	if (write(lfd, line, i) != i) {
12516762Sralph 		syslog(LOG_ERR, "%s: %s: %m", printer, LO);
12612111Sralph 		exit(1);
12712111Sralph 	}
12812111Sralph 	/*
12912111Sralph 	 * search the spool directory for work and sort by queue order.
13012111Sralph 	 */
13112111Sralph 	if ((nitems = getq(&queue)) < 0) {
13216762Sralph 		syslog(LOG_ERR, "%s: can't scan %s", printer, SD);
13312111Sralph 		exit(1);
13412111Sralph 	}
13512463Sralph 	if (nitems == 0)		/* no work to do */
13612111Sralph 		exit(0);
13713169Sralph 	if (stb.st_mode & 01) {		/* reset queue flag */
13813169Sralph 		if (fchmod(lfd, stb.st_mode & 0776) < 0)
13916762Sralph 			syslog(LOG_ERR, "%s: %s: %m", printer, LO);
14013169Sralph 	}
14112463Sralph 	openpr();			/* open printer or remote */
14212463Sralph again:
14312111Sralph 	/*
14412111Sralph 	 * we found something to do now do it --
14512111Sralph 	 *    write the name of the current control file into the lock file
14612111Sralph 	 *    so the spool queue program can tell what we're working on
14712111Sralph 	 */
14812111Sralph 	for (qp = queue; nitems--; free((char *) q)) {
14912111Sralph 		q = *qp++;
15012111Sralph 		if (stat(q->q_name, &stb) < 0)
15112111Sralph 			continue;
15212463Sralph 	restart:
15312111Sralph 		(void) lseek(lfd, pidoff, 0);
15412111Sralph 		(void) sprintf(line, "%s\n", q->q_name);
15512111Sralph 		i = strlen(line);
15612111Sralph 		if (write(lfd, line, i) != i)
15716762Sralph 			syslog(LOG_ERR, "%s: %s: %m", printer, LO);
15812111Sralph 		if (!remote)
15912111Sralph 			i = printit(q->q_name);
16012111Sralph 		else
16112111Sralph 			i = sendit(q->q_name);
16212463Sralph 		/*
16313169Sralph 		 * Check to see if we are supposed to stop printing or
16413169Sralph 		 * if we are to rebuild the queue.
16512463Sralph 		 */
16613169Sralph 		if (fstat(lfd, &stb) == 0) {
16716762Sralph 			/* stop printing before starting next job? */
16813169Sralph 			if (stb.st_mode & 0100)
16913169Sralph 				goto done;
17016762Sralph 			/* rebuild queue (after lpc topq) */
17113169Sralph 			if (stb.st_mode & 01) {
17213169Sralph 				for (free((char *) q); nitems--; free((char *) q))
17313169Sralph 					q = *qp++;
17413169Sralph 				if (fchmod(lfd, stb.st_mode & 0776) < 0)
17516762Sralph 					syslog(LOG_WARNING, "%s: %s: %m",
17616762Sralph 						printer, LO);
17713169Sralph 				break;
17813169Sralph 			}
17913169Sralph 		}
18017463Sralph 		if (i == OK)		/* file ok and printed */
18114150Sralph 			count++;
18217463Sralph 		else if (i == REPRINT) { /* try reprinting the job */
18316762Sralph 			syslog(LOG_INFO, "restarting %s", printer);
18412111Sralph 			if (ofilter > 0) {
18512111Sralph 				kill(ofilter, SIGCONT);	/* to be sure */
18612111Sralph 				(void) close(ofd);
18712111Sralph 				while ((i = wait(0)) > 0 && i != ofilter)
18812111Sralph 					;
18912111Sralph 				ofilter = 0;
19012111Sralph 			}
19112463Sralph 			(void) close(pfd);	/* close printer */
19215811Sralph 			if (ftruncate(lfd, pidoff) < 0)
19316762Sralph 				syslog(LOG_WARNING, "%s: %s: %m", printer, LO);
19412463Sralph 			openpr();		/* try to reopen printer */
19512111Sralph 			goto restart;
19612111Sralph 		}
19712111Sralph 	}
19812111Sralph 	free((char *) queue);
19912463Sralph 	/*
20012463Sralph 	 * search the spool directory for more work.
20112463Sralph 	 */
20212463Sralph 	if ((nitems = getq(&queue)) < 0) {
20316762Sralph 		syslog(LOG_ERR, "%s: can't scan %s", printer, SD);
20412463Sralph 		exit(1);
20512463Sralph 	}
20612463Sralph 	if (nitems == 0) {		/* no more work to do */
20712463Sralph 	done:
20814150Sralph 		if (count > 0) {	/* Files actually printed */
20914150Sralph 			if (!SF && !tof)
21014150Sralph 				(void) write(ofd, FF, strlen(FF));
21114150Sralph 			if (TR != NULL)		/* output trailer */
21214150Sralph 				(void) write(ofd, TR, strlen(TR));
21314150Sralph 		}
214*39954Smckusick 		(void) unlink(tempfile);
21512463Sralph 		exit(0);
21612463Sralph 	}
21712111Sralph 	goto again;
21812111Sralph }
21912111Sralph 
22012111Sralph char	fonts[4][50];	/* fonts for troff */
22112111Sralph 
22237968Sbostic char ifonts[4][40] = {
22337968Sbostic 	_PATH_VFONTR,
22437968Sbostic 	_PATH_VFONTI,
22537968Sbostic 	_PATH_VFONTB,
22637968Sbostic 	_PATH_VFONTS,
22712111Sralph };
22812111Sralph 
22912111Sralph /*
23012111Sralph  * The remaining part is the reading of the control file (cf)
23112111Sralph  * and performing the various actions.
23212111Sralph  */
23312111Sralph printit(file)
23412111Sralph 	char *file;
23512111Sralph {
23612111Sralph 	register int i;
23717463Sralph 	char *cp;
23817463Sralph 	int bombed = OK;
23912111Sralph 
24012111Sralph 	/*
24117463Sralph 	 * open control file; ignore if no longer there.
24212111Sralph 	 */
24312111Sralph 	if ((cfp = fopen(file, "r")) == NULL) {
24416762Sralph 		syslog(LOG_INFO, "%s: %s: %m", printer, file);
24517463Sralph 		return(OK);
24612111Sralph 	}
24712111Sralph 	/*
24812111Sralph 	 * Reset troff fonts.
24912111Sralph 	 */
25012111Sralph 	for (i = 0; i < 4; i++)
25112111Sralph 		strcpy(fonts[i], ifonts[i]);
25217339Sralph 	strcpy(width+2, "0");
25317302Sralph 	strcpy(indent+2, "0");
25412111Sralph 
25512111Sralph 	/*
25612111Sralph 	 *      read the control file for work to do
25712111Sralph 	 *
25812111Sralph 	 *      file format -- first character in the line is a command
25912111Sralph 	 *      rest of the line is the argument.
26012111Sralph 	 *      valid commands are:
26112111Sralph 	 *
26217463Sralph 	 *		S -- "stat info" for symbolic link protection
26312111Sralph 	 *		J -- "job name" on banner page
26412111Sralph 	 *		C -- "class name" on banner page
26512111Sralph 	 *              L -- "literal" user's name to print on banner
26612111Sralph 	 *		T -- "title" for pr
26712111Sralph 	 *		H -- "host name" of machine where lpr was done
26812111Sralph 	 *              P -- "person" user's login name
26912581Sralph 	 *              I -- "indent" amount to indent output
27012111Sralph 	 *              f -- "file name" name of text file to print
27112111Sralph 	 *		l -- "file name" text file with control chars
27212111Sralph 	 *		p -- "file name" text file to print with pr(1)
27312111Sralph 	 *		t -- "file name" troff(1) file to print
27413233Sralph 	 *		n -- "file name" ditroff(1) file to print
27512111Sralph 	 *		d -- "file name" dvi file to print
27612111Sralph 	 *		g -- "file name" plot(1G) file to print
27712111Sralph 	 *		v -- "file name" plain raster file to print
27812111Sralph 	 *		c -- "file name" cifplot file to print
27912111Sralph 	 *		1 -- "R font file" for troff
28012111Sralph 	 *		2 -- "I font file" for troff
28112111Sralph 	 *		3 -- "B font file" for troff
28212111Sralph 	 *		4 -- "S font file" for troff
28312111Sralph 	 *		N -- "name" of file (used by lpq)
28412111Sralph 	 *              U -- "unlink" name of file to remove
28512111Sralph 	 *                    (after we print it. (Pass 2 only)).
28612111Sralph 	 *		M -- "mail" to user when done printing
28712111Sralph 	 *
28812111Sralph 	 *      getline reads a line and expands tabs to blanks
28912111Sralph 	 */
29012111Sralph 
29112111Sralph 	/* pass 1 */
29212111Sralph 
29312111Sralph 	while (getline(cfp))
29412111Sralph 		switch (line[0]) {
29512111Sralph 		case 'H':
29614150Sralph 			strcpy(fromhost, line+1);
29712111Sralph 			if (class[0] == '\0')
29815552Sralph 				strncpy(class, line+1, sizeof(class)-1);
29912111Sralph 			continue;
30012111Sralph 
30112111Sralph 		case 'P':
30215552Sralph 			strncpy(logname, line+1, sizeof(logname)-1);
30312463Sralph 			if (RS) {			/* restricted */
30412463Sralph 				if (getpwnam(logname) == (struct passwd *)0) {
30517463Sralph 					bombed = NOACCT;
30615811Sralph 					sendmail(line+1, bombed);
30712463Sralph 					goto pass2;
30812463Sralph 				}
30912463Sralph 			}
31012111Sralph 			continue;
31112111Sralph 
31217463Sralph 		case 'S':
31317463Sralph 			cp = line+1;
31417463Sralph 			i = 0;
31517463Sralph 			while (*cp >= '0' && *cp <= '9')
31617463Sralph 				i = i * 10 + (*cp++ - '0');
31717463Sralph 			fdev = i;
31817463Sralph 			cp++;
31917463Sralph 			i = 0;
32017463Sralph 			while (*cp >= '0' && *cp <= '9')
32117463Sralph 				i = i * 10 + (*cp++ - '0');
32217463Sralph 			fino = i;
32317463Sralph 			continue;
32417463Sralph 
32512111Sralph 		case 'J':
32612111Sralph 			if (line[1] != '\0')
32715552Sralph 				strncpy(jobname, line+1, sizeof(jobname)-1);
32812111Sralph 			else
32912111Sralph 				strcpy(jobname, " ");
33012111Sralph 			continue;
33112111Sralph 
33212111Sralph 		case 'C':
33312111Sralph 			if (line[1] != '\0')
33415552Sralph 				strncpy(class, line+1, sizeof(class)-1);
33512111Sralph 			else if (class[0] == '\0')
33615811Sralph 				gethostname(class, sizeof(class));
33712111Sralph 			continue;
33812111Sralph 
33912111Sralph 		case 'T':	/* header title for pr */
34015552Sralph 			strncpy(title, line+1, sizeof(title)-1);
34112111Sralph 			continue;
34212111Sralph 
34312111Sralph 		case 'L':	/* identification line */
34418127Sralph 			if (!SH && !HL)
34512111Sralph 				banner(line+1, jobname);
34612111Sralph 			continue;
34712111Sralph 
34812111Sralph 		case '1':	/* troff fonts */
34912111Sralph 		case '2':
35012111Sralph 		case '3':
35112111Sralph 		case '4':
35212111Sralph 			if (line[1] != '\0')
35312111Sralph 				strcpy(fonts[line[0]-'1'], line+1);
35412111Sralph 			continue;
35512111Sralph 
35612111Sralph 		case 'W':	/* page width */
35715552Sralph 			strncpy(width+2, line+1, sizeof(width)-3);
35812111Sralph 			continue;
35912111Sralph 
36012581Sralph 		case 'I':	/* indent amount */
36115552Sralph 			strncpy(indent+2, line+1, sizeof(indent)-3);
36212581Sralph 			continue;
36312581Sralph 
36412111Sralph 		default:	/* some file to print */
36515811Sralph 			switch (i = print(line[0], line+1)) {
36617463Sralph 			case ERROR:
36717463Sralph 				if (bombed == OK)
36817463Sralph 					bombed = FATALERR;
36915811Sralph 				break;
37017463Sralph 			case REPRINT:
37112111Sralph 				(void) fclose(cfp);
37217463Sralph 				return(REPRINT);
37317463Sralph 			case FILTERERR:
37417463Sralph 			case ACCESS:
37517463Sralph 				bombed = i;
37615811Sralph 				sendmail(logname, bombed);
37715811Sralph 			}
37812111Sralph 			title[0] = '\0';
37912111Sralph 			continue;
38012111Sralph 
38112111Sralph 		case 'N':
38212111Sralph 		case 'U':
38312111Sralph 		case 'M':
38412111Sralph 			continue;
38512111Sralph 		}
38612111Sralph 
38712111Sralph 	/* pass 2 */
38812111Sralph 
38912463Sralph pass2:
39012111Sralph 	fseek(cfp, 0L, 0);
39112111Sralph 	while (getline(cfp))
39212111Sralph 		switch (line[0]) {
39318127Sralph 		case 'L':	/* identification line */
39418127Sralph 			if (!SH && HL)
39518127Sralph 				banner(line+1, jobname);
39618127Sralph 			continue;
39718127Sralph 
39812111Sralph 		case 'M':
39917463Sralph 			if (bombed < NOACCT)	/* already sent if >= NOACCT */
40015811Sralph 				sendmail(line+1, bombed);
40112111Sralph 			continue;
40212111Sralph 
40312111Sralph 		case 'U':
40412111Sralph 			(void) unlink(line+1);
40512111Sralph 		}
40612111Sralph 	/*
40715811Sralph 	 * clean-up in case another control file exists
40812111Sralph 	 */
40912111Sralph 	(void) fclose(cfp);
41012111Sralph 	(void) unlink(file);
41117463Sralph 	return(bombed == OK ? OK : ERROR);
41212111Sralph }
41312111Sralph 
41412111Sralph /*
41512111Sralph  * Print a file.
41613233Sralph  * Set up the chain [ PR [ | {IF, OF} ] ] or {IF, RF, TF, NF, DF, CF, VF}.
41715811Sralph  * Return -1 if a non-recoverable error occured,
41815811Sralph  * 2 if the filter detected some errors (but printed the job anyway),
41915811Sralph  * 1 if we should try to reprint this job and
42012111Sralph  * 0 if all is well.
42112111Sralph  * Note: all filters take stdin as the file, stdout as the printer,
42212111Sralph  * stderr as the log file, and must not ignore SIGINT.
42312111Sralph  */
42412111Sralph print(format, file)
42512111Sralph 	int format;
42612111Sralph 	char *file;
42712111Sralph {
42815811Sralph 	register int n;
42912111Sralph 	register char *prog;
43015811Sralph 	int fi, fo;
431*39954Smckusick 	FILE *fp;
43212111Sralph 	char *av[15], buf[BUFSIZ];
43312111Sralph 	int pid, p[2], stopped = 0;
43412111Sralph 	union wait status;
43517463Sralph 	struct stat stb;
43612111Sralph 
43717463Sralph 	if (lstat(file, &stb) < 0 || (fi = open(file, O_RDONLY)) < 0)
43817463Sralph 		return(ERROR);
43917463Sralph 	/*
44017463Sralph 	 * Check to see if data file is a symbolic link. If so, it should
44117463Sralph 	 * still point to the same file or someone is trying to print
44217463Sralph 	 * something he shouldn't.
44317463Sralph 	 */
44417463Sralph 	if ((stb.st_mode & S_IFMT) == S_IFLNK && fstat(fi, &stb) == 0 &&
44517463Sralph 	    (stb.st_dev != fdev || stb.st_ino != fino))
44617463Sralph 		return(ACCESS);
44712111Sralph 	if (!SF && !tof) {		/* start on a fresh page */
44812111Sralph 		(void) write(ofd, FF, strlen(FF));
44912111Sralph 		tof = 1;
45012111Sralph 	}
45112111Sralph 	if (IF == NULL && (format == 'f' || format == 'l')) {
45212111Sralph 		tof = 0;
45312111Sralph 		while ((n = read(fi, buf, BUFSIZ)) > 0)
45412111Sralph 			if (write(ofd, buf, n) != n) {
45512111Sralph 				(void) close(fi);
45617463Sralph 				return(REPRINT);
45712111Sralph 			}
45812111Sralph 		(void) close(fi);
45917463Sralph 		return(OK);
46012111Sralph 	}
46112111Sralph 	switch (format) {
46212111Sralph 	case 'p':	/* print file using 'pr' */
46312111Sralph 		if (IF == NULL) {	/* use output filter */
46437968Sbostic 			prog = _PATH_PR;
46512111Sralph 			av[0] = "pr";
46612111Sralph 			av[1] = width;
46712111Sralph 			av[2] = length;
46812111Sralph 			av[3] = "-h";
46912111Sralph 			av[4] = *title ? title : " ";
47012111Sralph 			av[5] = 0;
47112111Sralph 			fo = ofd;
47212111Sralph 			goto start;
47312111Sralph 		}
47412111Sralph 		pipe(p);
47512111Sralph 		if ((prchild = dofork(DORETURN)) == 0) {	/* child */
47612111Sralph 			dup2(fi, 0);		/* file is stdin */
47712111Sralph 			dup2(p[1], 1);		/* pipe is stdout */
47812111Sralph 			for (n = 3; n < NOFILE; n++)
47912111Sralph 				(void) close(n);
48037968Sbostic 			execl(_PATH_PR, "pr", width, length,
48137968Sbostic 			    "-h", *title ? title : " ", 0);
48237968Sbostic 			syslog(LOG_ERR, "cannot execl %s", _PATH_PR);
48312111Sralph 			exit(2);
48412111Sralph 		}
48512111Sralph 		(void) close(p[1]);		/* close output side */
48612111Sralph 		(void) close(fi);
48712111Sralph 		if (prchild < 0) {
48812111Sralph 			prchild = 0;
48912111Sralph 			(void) close(p[0]);
49017463Sralph 			return(ERROR);
49112111Sralph 		}
49212111Sralph 		fi = p[0];			/* use pipe for input */
49312111Sralph 	case 'f':	/* print plain text file */
49412111Sralph 		prog = IF;
49512111Sralph 		av[1] = width;
49612111Sralph 		av[2] = length;
49712581Sralph 		av[3] = indent;
49812581Sralph 		n = 4;
49912111Sralph 		break;
50012111Sralph 	case 'l':	/* like 'f' but pass control characters */
50112111Sralph 		prog = IF;
50214325Sralph 		av[1] = "-c";
50312111Sralph 		av[2] = width;
50412111Sralph 		av[3] = length;
50512581Sralph 		av[4] = indent;
50612581Sralph 		n = 5;
50712111Sralph 		break;
50812463Sralph 	case 'r':	/* print a fortran text file */
50912463Sralph 		prog = RF;
51012463Sralph 		av[1] = width;
51112463Sralph 		av[2] = length;
51212463Sralph 		n = 3;
51312463Sralph 		break;
51412111Sralph 	case 't':	/* print troff output */
51513233Sralph 	case 'n':	/* print ditroff output */
51612463Sralph 	case 'd':	/* print tex output */
51712111Sralph 		(void) unlink(".railmag");
51812463Sralph 		if ((fo = creat(".railmag", FILMOD)) < 0) {
51916762Sralph 			syslog(LOG_ERR, "%s: cannot create .railmag", printer);
52012111Sralph 			(void) unlink(".railmag");
52112111Sralph 		} else {
52212111Sralph 			for (n = 0; n < 4; n++) {
52312111Sralph 				if (fonts[n][0] != '/')
52437968Sbostic 					(void) write(fo, _PATH_VFONT, 15);
52512111Sralph 				(void) write(fo, fonts[n], strlen(fonts[n]));
52612111Sralph 				(void) write(fo, "\n", 1);
52712111Sralph 			}
52812111Sralph 			(void) close(fo);
52912111Sralph 		}
53013233Sralph 		prog = (format == 't') ? TF : (format == 'n') ? NF : DF;
53112463Sralph 		av[1] = pxwidth;
53212463Sralph 		av[2] = pxlength;
53312463Sralph 		n = 3;
53412111Sralph 		break;
53512111Sralph 	case 'c':	/* print cifplot output */
53612111Sralph 		prog = CF;
53712463Sralph 		av[1] = pxwidth;
53812463Sralph 		av[2] = pxlength;
53912463Sralph 		n = 3;
54012111Sralph 		break;
54112111Sralph 	case 'g':	/* print plot(1G) output */
54212111Sralph 		prog = GF;
54312463Sralph 		av[1] = pxwidth;
54412463Sralph 		av[2] = pxlength;
54512463Sralph 		n = 3;
54612111Sralph 		break;
54712111Sralph 	case 'v':	/* print raster output */
54812111Sralph 		prog = VF;
54912463Sralph 		av[1] = pxwidth;
55012463Sralph 		av[2] = pxlength;
55112463Sralph 		n = 3;
55212111Sralph 		break;
55312111Sralph 	default:
55412111Sralph 		(void) close(fi);
55516762Sralph 		syslog(LOG_ERR, "%s: illegal format character '%c'",
55616762Sralph 			printer, format);
55717463Sralph 		return(ERROR);
55812111Sralph 	}
55912111Sralph 	if ((av[0] = rindex(prog, '/')) != NULL)
56012111Sralph 		av[0]++;
56112111Sralph 	else
56212111Sralph 		av[0] = prog;
56312111Sralph 	av[n++] = "-n";
56412111Sralph 	av[n++] = logname;
56512111Sralph 	av[n++] = "-h";
56614150Sralph 	av[n++] = fromhost;
56712111Sralph 	av[n++] = AF;
56812111Sralph 	av[n] = 0;
56912111Sralph 	fo = pfd;
57012111Sralph 	if (ofilter > 0) {		/* stop output filter */
57112111Sralph 		write(ofd, "\031\1", 2);
57212111Sralph 		while ((pid = wait3(&status, WUNTRACED, 0)) > 0 && pid != ofilter)
57312111Sralph 			;
57412111Sralph 		if (status.w_stopval != WSTOPPED) {
57512111Sralph 			(void) close(fi);
57616762Sralph 			syslog(LOG_WARNING, "%s: output filter died (%d)",
57716762Sralph 				printer, status.w_retcode);
57817463Sralph 			return(REPRINT);
57912111Sralph 		}
58012111Sralph 		stopped++;
58112111Sralph 	}
58212111Sralph start:
58312111Sralph 	if ((child = dofork(DORETURN)) == 0) {	/* child */
58412111Sralph 		dup2(fi, 0);
58512111Sralph 		dup2(fo, 1);
586*39954Smckusick 		n = open(tempfile, O_WRONLY|O_CREAT|O_TRUNC, 0664);
58715811Sralph 		if (n >= 0)
58815811Sralph 			dup2(n, 2);
58912111Sralph 		for (n = 3; n < NOFILE; n++)
59012111Sralph 			(void) close(n);
59112111Sralph 		execv(prog, av);
59216762Sralph 		syslog(LOG_ERR, "cannot execv %s", prog);
59312111Sralph 		exit(2);
59412111Sralph 	}
59512111Sralph 	(void) close(fi);
59612111Sralph 	if (child < 0)
59712111Sralph 		status.w_retcode = 100;
59812111Sralph 	else
59912111Sralph 		while ((pid = wait(&status)) > 0 && pid != child)
60012111Sralph 			;
60112111Sralph 	child = 0;
60212111Sralph 	prchild = 0;
60312111Sralph 	if (stopped) {		/* restart output filter */
60412111Sralph 		if (kill(ofilter, SIGCONT) < 0) {
60516762Sralph 			syslog(LOG_ERR, "cannot restart output filter");
60612111Sralph 			exit(1);
60712111Sralph 		}
60812111Sralph 	}
60912111Sralph 	tof = 0;
610*39954Smckusick 
611*39954Smckusick 	/* Copy filter output to "lf" logfile */
612*39954Smckusick 	if (fp = fopen(tempfile, "r")) {
613*39954Smckusick 		char tbuf[512];
614*39954Smckusick 
615*39954Smckusick 		while (fgets(buf, sizeof(buf), fp))
616*39954Smckusick 			fputs(buf, stderr);
617*39954Smckusick 		close(fp);
618*39954Smckusick 	}
619*39954Smckusick 
62015811Sralph 	if (!WIFEXITED(status)) {
62116762Sralph 		syslog(LOG_WARNING, "%s: Daemon filter '%c' terminated (%d)",
62216762Sralph 			printer, format, status.w_termsig);
62317463Sralph 		return(ERROR);
62417463Sralph 	}
62517463Sralph 	switch (status.w_retcode) {
62617463Sralph 	case 0:
62717463Sralph 		tof = 1;
62817463Sralph 		return(OK);
62917463Sralph 	case 1:
63017463Sralph 		return(REPRINT);
63117463Sralph 	default:
63216762Sralph 		syslog(LOG_WARNING, "%s: Daemon filter '%c' exited (%d)",
63316762Sralph 			printer, format, status.w_retcode);
63417463Sralph 	case 2:
63517463Sralph 		return(ERROR);
63617463Sralph 	}
63712111Sralph }
63812111Sralph 
63912111Sralph /*
64012111Sralph  * Send the daemon control file (cf) and any data files.
64112111Sralph  * Return -1 if a non-recoverable error occured, 1 if a recoverable error and
64212111Sralph  * 0 if all is well.
64312111Sralph  */
64412111Sralph sendit(file)
64512111Sralph 	char *file;
64612111Sralph {
64717463Sralph 	register int i, err = OK;
64817463Sralph 	char *cp, last[BUFSIZ];
64912111Sralph 
65012111Sralph 	/*
65112111Sralph 	 * open control file
65212111Sralph 	 */
65316762Sralph 	if ((cfp = fopen(file, "r")) == NULL)
65417463Sralph 		return(OK);
65512111Sralph 	/*
65612111Sralph 	 *      read the control file for work to do
65712111Sralph 	 *
65812111Sralph 	 *      file format -- first character in the line is a command
65912111Sralph 	 *      rest of the line is the argument.
66012111Sralph 	 *      commands of interest are:
66112111Sralph 	 *
66212111Sralph 	 *            a-z -- "file name" name of file to print
66312111Sralph 	 *              U -- "unlink" name of file to remove
66412111Sralph 	 *                    (after we print it. (Pass 2 only)).
66512111Sralph 	 */
66612111Sralph 
66712111Sralph 	/*
66812111Sralph 	 * pass 1
66912111Sralph 	 */
67012111Sralph 	while (getline(cfp)) {
67112111Sralph 	again:
67217463Sralph 		if (line[0] == 'S') {
67317463Sralph 			cp = line+1;
67417463Sralph 			i = 0;
67517463Sralph 			while (*cp >= '0' && *cp <= '9')
67617463Sralph 				i = i * 10 + (*cp++ - '0');
67717463Sralph 			fdev = i;
67817463Sralph 			cp++;
67917463Sralph 			i = 0;
68017463Sralph 			while (*cp >= '0' && *cp <= '9')
68117463Sralph 				i = i * 10 + (*cp++ - '0');
68217463Sralph 			fino = i;
68317463Sralph 			continue;
68417463Sralph 		}
68512111Sralph 		if (line[0] >= 'a' && line[0] <= 'z') {
68612111Sralph 			strcpy(last, line);
68717463Sralph 			while (i = getline(cfp))
68812111Sralph 				if (strcmp(last, line))
68912111Sralph 					break;
69017463Sralph 			switch (sendfile('\3', last+1)) {
69117463Sralph 			case OK:
69217463Sralph 				if (i)
69317463Sralph 					goto again;
69417463Sralph 				break;
69517463Sralph 			case REPRINT:
69612111Sralph 				(void) fclose(cfp);
69717463Sralph 				return(REPRINT);
69817463Sralph 			case ACCESS:
69917463Sralph 				sendmail(logname, ACCESS);
70017463Sralph 			case ERROR:
70117463Sralph 				err = ERROR;
70217463Sralph 			}
70312111Sralph 			break;
70412111Sralph 		}
70512111Sralph 	}
70617463Sralph 	if (err == OK && sendfile('\2', file) > 0) {
70712111Sralph 		(void) fclose(cfp);
70817463Sralph 		return(REPRINT);
70912111Sralph 	}
71012111Sralph 	/*
71112111Sralph 	 * pass 2
71212111Sralph 	 */
71312111Sralph 	fseek(cfp, 0L, 0);
71412111Sralph 	while (getline(cfp))
71512111Sralph 		if (line[0] == 'U')
71612111Sralph 			(void) unlink(line+1);
71712111Sralph 	/*
71817463Sralph 	 * clean-up in case another control file exists
71912111Sralph 	 */
72012111Sralph 	(void) fclose(cfp);
72112111Sralph 	(void) unlink(file);
72217463Sralph 	return(err);
72312111Sralph }
72412111Sralph 
72512111Sralph /*
72612111Sralph  * Send a data file to the remote machine and spool it.
72712111Sralph  * Return positive if we should try resending.
72812111Sralph  */
72912111Sralph sendfile(type, file)
73012111Sralph 	char type, *file;
73112111Sralph {
73212111Sralph 	register int f, i, amt;
73312111Sralph 	struct stat stb;
73412111Sralph 	char buf[BUFSIZ];
73516762Sralph 	int sizerr, resp;
73612111Sralph 
73717463Sralph 	if (lstat(file, &stb) < 0 || (f = open(file, O_RDONLY)) < 0)
73817463Sralph 		return(ERROR);
73917463Sralph 	/*
74017463Sralph 	 * Check to see if data file is a symbolic link. If so, it should
74117463Sralph 	 * still point to the same file or someone is trying to print something
74217463Sralph 	 * he shouldn't.
74317463Sralph 	 */
74417463Sralph 	if ((stb.st_mode & S_IFMT) == S_IFLNK && fstat(f, &stb) == 0 &&
74517463Sralph 	    (stb.st_dev != fdev || stb.st_ino != fino))
74617463Sralph 		return(ACCESS);
74712111Sralph 	(void) sprintf(buf, "%c%d %s\n", type, stb.st_size, file);
74812111Sralph 	amt = strlen(buf);
74916762Sralph 	for (i = 0;  ; i++) {
75016762Sralph 		if (write(pfd, buf, amt) != amt ||
75116762Sralph 		    (resp = response()) < 0 || resp == '\1') {
75216762Sralph 			(void) close(f);
75317463Sralph 			return(REPRINT);
75416762Sralph 		} else if (resp == '\0')
75516762Sralph 			break;
75616762Sralph 		if (i == 0)
75716762Sralph 			status("no space on remote; waiting for queue to drain");
75816762Sralph 		if (i == 10)
75924861Seric 			syslog(LOG_ALERT, "%s: can't send to %s; queue full",
76016762Sralph 				printer, RM);
76116762Sralph 		sleep(5 * 60);
76212692Sralph 	}
76316762Sralph 	if (i)
76416762Sralph 		status("sending to %s", RM);
76512111Sralph 	sizerr = 0;
76612111Sralph 	for (i = 0; i < stb.st_size; i += BUFSIZ) {
76712111Sralph 		amt = BUFSIZ;
76812111Sralph 		if (i + amt > stb.st_size)
76912111Sralph 			amt = stb.st_size - i;
77012111Sralph 		if (sizerr == 0 && read(f, buf, amt) != amt)
77112111Sralph 			sizerr = 1;
77212692Sralph 		if (write(pfd, buf, amt) != amt) {
77312692Sralph 			(void) close(f);
77417463Sralph 			return(REPRINT);
77512692Sralph 		}
77612111Sralph 	}
77712111Sralph 	(void) close(f);
77812111Sralph 	if (sizerr) {
77916762Sralph 		syslog(LOG_INFO, "%s: %s: changed size", printer, file);
78017463Sralph 		/* tell recvjob to ignore this file */
78117463Sralph 		(void) write(pfd, "\1", 1);
78217463Sralph 		return(ERROR);
78317463Sralph 	}
78417463Sralph 	if (write(pfd, "", 1) != 1 || response())
78517463Sralph 		return(REPRINT);
78617463Sralph 	return(OK);
78712111Sralph }
78812111Sralph 
78912111Sralph /*
79012111Sralph  * Check to make sure there have been no errors and that both programs
79112111Sralph  * are in sync with eachother.
79212111Sralph  * Return non-zero if the connection was lost.
79312111Sralph  */
79416762Sralph response()
79512111Sralph {
79612111Sralph 	char resp;
79712111Sralph 
79816762Sralph 	if (read(pfd, &resp, 1) != 1) {
79916762Sralph 		syslog(LOG_INFO, "%s: lost connection", printer);
80016762Sralph 		return(-1);
80112111Sralph 	}
80216762Sralph 	return(resp);
80312111Sralph }
80412111Sralph 
80512111Sralph /*
80612111Sralph  * Banner printing stuff
80712111Sralph  */
80812111Sralph banner(name1, name2)
80912111Sralph 	char *name1, *name2;
81012111Sralph {
81112111Sralph 	time_t tvec;
81212111Sralph 	extern char *ctime();
81312111Sralph 
81412111Sralph 	time(&tvec);
81512111Sralph 	if (!SF && !tof)
81612111Sralph 		(void) write(ofd, FF, strlen(FF));
81712111Sralph 	if (SB) {	/* short banner only */
81812111Sralph 		if (class[0]) {
81912111Sralph 			(void) write(ofd, class, strlen(class));
82012111Sralph 			(void) write(ofd, ":", 1);
82112111Sralph 		}
82212111Sralph 		(void) write(ofd, name1, strlen(name1));
82312111Sralph 		(void) write(ofd, "  Job: ", 7);
82412111Sralph 		(void) write(ofd, name2, strlen(name2));
82512111Sralph 		(void) write(ofd, "  Date: ", 8);
82612111Sralph 		(void) write(ofd, ctime(&tvec), 24);
82712111Sralph 		(void) write(ofd, "\n", 1);
82812111Sralph 	} else {	/* normal banner */
82912111Sralph 		(void) write(ofd, "\n\n\n", 3);
83012111Sralph 		scan_out(ofd, name1, '\0');
83112111Sralph 		(void) write(ofd, "\n\n", 2);
83212111Sralph 		scan_out(ofd, name2, '\0');
83312111Sralph 		if (class[0]) {
83412111Sralph 			(void) write(ofd,"\n\n\n",3);
83512111Sralph 			scan_out(ofd, class, '\0');
83612111Sralph 		}
83712111Sralph 		(void) write(ofd, "\n\n\n\n\t\t\t\t\tJob:  ", 15);
83812111Sralph 		(void) write(ofd, name2, strlen(name2));
83912111Sralph 		(void) write(ofd, "\n\t\t\t\t\tDate: ", 12);
84012111Sralph 		(void) write(ofd, ctime(&tvec), 24);
84112111Sralph 		(void) write(ofd, "\n", 1);
84212111Sralph 	}
84312111Sralph 	if (!SF)
84412111Sralph 		(void) write(ofd, FF, strlen(FF));
84512111Sralph 	tof = 1;
84612111Sralph }
84712111Sralph 
84816762Sralph char *
84912111Sralph scnline(key, p, c)
85012111Sralph 	register char key, *p;
85112111Sralph 	char c;
85212111Sralph {
85312111Sralph 	register scnwidth;
85412111Sralph 
85512111Sralph 	for (scnwidth = WIDTH; --scnwidth;) {
85612111Sralph 		key <<= 1;
85712111Sralph 		*p++ = key & 0200 ? c : BACKGND;
85812111Sralph 	}
85912111Sralph 	return (p);
86012111Sralph }
86112111Sralph 
86212111Sralph #define TRC(q)	(((q)-' ')&0177)
86312111Sralph 
86412111Sralph scan_out(scfd, scsp, dlm)
86512111Sralph 	int scfd;
86612111Sralph 	char *scsp, dlm;
86712111Sralph {
86812111Sralph 	register char *strp;
86912111Sralph 	register nchrs, j;
87012111Sralph 	char outbuf[LINELEN+1], *sp, c, cc;
87112111Sralph 	int d, scnhgt;
87212111Sralph 	extern char scnkey[][HEIGHT];	/* in lpdchar.c */
87312111Sralph 
87412111Sralph 	for (scnhgt = 0; scnhgt++ < HEIGHT+DROP; ) {
87512111Sralph 		strp = &outbuf[0];
87612111Sralph 		sp = scsp;
87712111Sralph 		for (nchrs = 0; ; ) {
87812111Sralph 			d = dropit(c = TRC(cc = *sp++));
87912111Sralph 			if ((!d && scnhgt > HEIGHT) || (scnhgt <= DROP && d))
88012111Sralph 				for (j = WIDTH; --j;)
88112111Sralph 					*strp++ = BACKGND;
88212111Sralph 			else
88312111Sralph 				strp = scnline(scnkey[c][scnhgt-1-d], strp, cc);
88412111Sralph 			if (*sp == dlm || *sp == '\0' || nchrs++ >= PW/(WIDTH+1)-1)
88512111Sralph 				break;
88612111Sralph 			*strp++ = BACKGND;
88712111Sralph 			*strp++ = BACKGND;
88812111Sralph 		}
88912111Sralph 		while (*--strp == BACKGND && strp >= outbuf)
89012111Sralph 			;
89112111Sralph 		strp++;
89212111Sralph 		*strp++ = '\n';
89312111Sralph 		(void) write(scfd, outbuf, strp-outbuf);
89412111Sralph 	}
89512111Sralph }
89612111Sralph 
89712111Sralph dropit(c)
89812111Sralph 	char c;
89912111Sralph {
90012111Sralph 	switch(c) {
90112111Sralph 
90212111Sralph 	case TRC('_'):
90312111Sralph 	case TRC(';'):
90412111Sralph 	case TRC(','):
90512111Sralph 	case TRC('g'):
90612111Sralph 	case TRC('j'):
90712111Sralph 	case TRC('p'):
90812111Sralph 	case TRC('q'):
90912111Sralph 	case TRC('y'):
91012111Sralph 		return (DROP);
91112111Sralph 
91212111Sralph 	default:
91312111Sralph 		return (0);
91412111Sralph 	}
91512111Sralph }
91612111Sralph 
91712111Sralph /*
91812111Sralph  * sendmail ---
91912111Sralph  *   tell people about job completion
92012111Sralph  */
92115811Sralph sendmail(user, bombed)
92215811Sralph 	char *user;
92312111Sralph 	int bombed;
92412111Sralph {
92512111Sralph 	register int i;
92615811Sralph 	int p[2], s;
92712111Sralph 	register char *cp;
92812111Sralph 	char buf[100];
92915811Sralph 	struct stat stb;
93015811Sralph 	FILE *fp;
93112111Sralph 
93212111Sralph 	pipe(p);
93315811Sralph 	if ((s = dofork(DORETURN)) == 0) {		/* child */
93412111Sralph 		dup2(p[0], 0);
93512111Sralph 		for (i = 3; i < NOFILE; i++)
93612111Sralph 			(void) close(i);
93737968Sbostic 		if ((cp = rindex(_PATH_SENDMAIL, '/')) != NULL)
93812111Sralph 			cp++;
93912111Sralph 		else
94037968Sbostic 			cp = _PATH_SENDMAIL;
94115811Sralph 		sprintf(buf, "%s@%s", user, fromhost);
94237968Sbostic 		execl(_PATH_SENDMAIL, cp, buf, 0);
94312111Sralph 		exit(0);
94415811Sralph 	} else if (s > 0) {				/* parent */
94512111Sralph 		dup2(p[1], 1);
94615811Sralph 		printf("To: %s@%s\n", user, fromhost);
94712111Sralph 		printf("Subject: printer job\n\n");
94812111Sralph 		printf("Your printer job ");
94912111Sralph 		if (*jobname)
95012111Sralph 			printf("(%s) ", jobname);
95112463Sralph 		switch (bombed) {
95217463Sralph 		case OK:
95312463Sralph 			printf("\ncompleted successfully\n");
95412463Sralph 			break;
95512463Sralph 		default:
95617463Sralph 		case FATALERR:
95712463Sralph 			printf("\ncould not be printed\n");
95812463Sralph 			break;
95917463Sralph 		case NOACCT:
96012463Sralph 			printf("\ncould not be printed without an account on %s\n", host);
96112463Sralph 			break;
96217463Sralph 		case FILTERERR:
963*39954Smckusick 			if (stat(tempfile, &stb) < 0 || stb.st_size == 0 ||
964*39954Smckusick 			    (fp = fopen(tempfile, "r")) == NULL) {
96515811Sralph 				printf("\nwas printed but had some errors\n");
96615811Sralph 				break;
96715811Sralph 			}
96815811Sralph 			printf("\nwas printed but had the following errors:\n");
96915811Sralph 			while ((i = getc(fp)) != EOF)
97015811Sralph 				putchar(i);
97115811Sralph 			(void) fclose(fp);
97217463Sralph 			break;
97317463Sralph 		case ACCESS:
97417463Sralph 			printf("\nwas not printed because it was not linked to the original file\n");
97512463Sralph 		}
97612111Sralph 		fflush(stdout);
97712111Sralph 		(void) close(1);
97812111Sralph 	}
97912111Sralph 	(void) close(p[0]);
98012111Sralph 	(void) close(p[1]);
98115811Sralph 	wait(&s);
98212111Sralph }
98312111Sralph 
98412111Sralph /*
98512111Sralph  * dofork - fork with retries on failure
98612111Sralph  */
98712111Sralph dofork(action)
98812111Sralph 	int action;
98912111Sralph {
99012111Sralph 	register int i, pid;
99112111Sralph 
99212111Sralph 	for (i = 0; i < 20; i++) {
99312463Sralph 		if ((pid = fork()) < 0) {
99412111Sralph 			sleep((unsigned)(i*i));
99512463Sralph 			continue;
99612463Sralph 		}
99712463Sralph 		/*
99812463Sralph 		 * Child should run as daemon instead of root
99912463Sralph 		 */
100012463Sralph 		if (pid == 0)
100112463Sralph 			setuid(DU);
100212463Sralph 		return(pid);
100312111Sralph 	}
100416762Sralph 	syslog(LOG_ERR, "can't fork");
100512111Sralph 
100612111Sralph 	switch (action) {
100712111Sralph 	case DORETURN:
100812111Sralph 		return (-1);
100912111Sralph 	default:
101016762Sralph 		syslog(LOG_ERR, "bad action (%d) to dofork", action);
101112111Sralph 		/*FALL THRU*/
101212111Sralph 	case DOABORT:
101312111Sralph 		exit(1);
101412111Sralph 	}
101512111Sralph 	/*NOTREACHED*/
101612111Sralph }
101712111Sralph 
101812111Sralph /*
101916762Sralph  * Kill child processes to abort current job.
102012111Sralph  */
102116762Sralph abortpr()
102212111Sralph {
1023*39954Smckusick 	(void) unlink(tempfile);
102412111Sralph 	kill(0, SIGINT);
102512111Sralph 	if (ofilter > 0)
102612111Sralph 		kill(ofilter, SIGCONT);
102712111Sralph 	while (wait(0) > 0)
102812111Sralph 		;
102912111Sralph 	exit(0);
103012111Sralph }
103112111Sralph 
103212111Sralph init()
103312111Sralph {
103412111Sralph 	int status;
103538736Stef 	char *s;
103612111Sralph 
103725468Stef 	if ((status = pgetent(line, printer)) < 0) {
103825468Stef 		syslog(LOG_ERR, "can't open printer description file");
103925468Stef 		exit(1);
104025468Stef 	} else if (status == 0) {
104125468Stef 		syslog(LOG_ERR, "unknown printer: %s", printer);
104225468Stef 		exit(1);
104325468Stef 	}
104412111Sralph 	if ((LP = pgetstr("lp", &bp)) == NULL)
104537968Sbostic 		LP = _PATH_DEFDEVLP;
104612111Sralph 	if ((RP = pgetstr("rp", &bp)) == NULL)
104712463Sralph 		RP = DEFLP;
104812111Sralph 	if ((LO = pgetstr("lo", &bp)) == NULL)
104912111Sralph 		LO = DEFLOCK;
105012111Sralph 	if ((ST = pgetstr("st", &bp)) == NULL)
105112111Sralph 		ST = DEFSTAT;
105212111Sralph 	if ((LF = pgetstr("lf", &bp)) == NULL)
105337968Sbostic 		LF = _PATH_CONSOLE;
105412111Sralph 	if ((SD = pgetstr("sd", &bp)) == NULL)
105537968Sbostic 		SD = _PATH_DEFSPOOL;
105612111Sralph 	if ((DU = pgetnum("du")) < 0)
105712111Sralph 		DU = DEFUID;
105812111Sralph 	if ((FF = pgetstr("ff", &bp)) == NULL)
105912111Sralph 		FF = DEFFF;
106012111Sralph 	if ((PW = pgetnum("pw")) < 0)
106112111Sralph 		PW = DEFWIDTH;
106212111Sralph 	sprintf(&width[2], "%d", PW);
106312111Sralph 	if ((PL = pgetnum("pl")) < 0)
106412111Sralph 		PL = DEFLENGTH;
106512111Sralph 	sprintf(&length[2], "%d", PL);
106612463Sralph 	if ((PX = pgetnum("px")) < 0)
106712463Sralph 		PX = 0;
106812463Sralph 	sprintf(&pxwidth[2], "%d", PX);
106912463Sralph 	if ((PY = pgetnum("py")) < 0)
107012463Sralph 		PY = 0;
107112463Sralph 	sprintf(&pxlength[2], "%d", PY);
107212111Sralph 	RM = pgetstr("rm", &bp);
107338736Stef 	if (s = checkremote())
107438736Stef 		syslog(LOG_WARNING, s);
107525468Stef 
107612111Sralph 	AF = pgetstr("af", &bp);
107712111Sralph 	OF = pgetstr("of", &bp);
107812111Sralph 	IF = pgetstr("if", &bp);
107912463Sralph 	RF = pgetstr("rf", &bp);
108012111Sralph 	TF = pgetstr("tf", &bp);
108113233Sralph 	NF = pgetstr("nf", &bp);
108212111Sralph 	DF = pgetstr("df", &bp);
108312111Sralph 	GF = pgetstr("gf", &bp);
108412111Sralph 	VF = pgetstr("vf", &bp);
108512111Sralph 	CF = pgetstr("cf", &bp);
108612111Sralph 	TR = pgetstr("tr", &bp);
108712463Sralph 	RS = pgetflag("rs");
108812111Sralph 	SF = pgetflag("sf");
108912111Sralph 	SH = pgetflag("sh");
109012111Sralph 	SB = pgetflag("sb");
109118127Sralph 	HL = pgetflag("hl");
109212111Sralph 	RW = pgetflag("rw");
109312111Sralph 	BR = pgetnum("br");
109412111Sralph 	if ((FC = pgetnum("fc")) < 0)
109512111Sralph 		FC = 0;
109612111Sralph 	if ((FS = pgetnum("fs")) < 0)
109712111Sralph 		FS = 0;
109812111Sralph 	if ((XC = pgetnum("xc")) < 0)
109912111Sralph 		XC = 0;
110012111Sralph 	if ((XS = pgetnum("xs")) < 0)
110112111Sralph 		XS = 0;
110212581Sralph 	tof = !pgetflag("fo");
110312111Sralph }
110412111Sralph 
110512463Sralph /*
110612463Sralph  * Acquire line printer or remote connection.
110712463Sralph  */
110812463Sralph openpr()
110912463Sralph {
111012463Sralph 	register int i, n;
111116762Sralph 	int resp;
111212463Sralph 
111338736Stef 	if (!sendtorem && *LP) {
111412463Sralph 		for (i = 1; ; i = i < 32 ? i << 1 : i) {
111513148Ssam 			pfd = open(LP, RW ? O_RDWR : O_WRONLY);
111612463Sralph 			if (pfd >= 0)
111712463Sralph 				break;
111812463Sralph 			if (errno == ENOENT) {
111916762Sralph 				syslog(LOG_ERR, "%s: %m", LP);
112012463Sralph 				exit(1);
112112463Sralph 			}
112212463Sralph 			if (i == 1)
112312463Sralph 				status("waiting for %s to become ready (offline ?)", printer);
112412463Sralph 			sleep(i);
112512463Sralph 		}
112612463Sralph 		if (isatty(pfd))
112712463Sralph 			setty();
112812463Sralph 		status("%s is ready and printing", printer);
112912463Sralph 	} else if (RM != NULL) {
113016762Sralph 		for (i = 1; ; i = i < 256 ? i << 1 : i) {
113116762Sralph 			resp = -1;
113212528Sralph 			pfd = getport(RM);
113312463Sralph 			if (pfd >= 0) {
113412463Sralph 				(void) sprintf(line, "\2%s\n", RP);
113512463Sralph 				n = strlen(line);
113616762Sralph 				if (write(pfd, line, n) == n &&
113716762Sralph 				    (resp = response()) == '\0')
113812463Sralph 					break;
113916031Sralph 				(void) close(pfd);
114012463Sralph 			}
114116031Sralph 			if (i == 1) {
114216762Sralph 				if (resp < 0)
114316031Sralph 					status("waiting for %s to come up", RM);
114416762Sralph 				else {
114516031Sralph 					status("waiting for queue to be enabled on %s", RM);
114616762Sralph 					i = 256;
114716762Sralph 				}
114816031Sralph 			}
114912463Sralph 			sleep(i);
115012463Sralph 		}
115112463Sralph 		status("sending to %s", RM);
115212463Sralph 		remote = 1;
115312463Sralph 	} else {
115416762Sralph 		syslog(LOG_ERR, "%s: no line printer device or host name",
115516762Sralph 			printer);
115612463Sralph 		exit(1);
115712463Sralph 	}
115812463Sralph 	/*
115912463Sralph 	 * Start up an output filter, if needed.
116012463Sralph 	 */
116112463Sralph 	if (OF) {
116212463Sralph 		int p[2];
116312463Sralph 		char *cp;
116412463Sralph 
116512463Sralph 		pipe(p);
116612463Sralph 		if ((ofilter = dofork(DOABORT)) == 0) {	/* child */
116712463Sralph 			dup2(p[0], 0);		/* pipe is std in */
116812463Sralph 			dup2(pfd, 1);		/* printer is std out */
116912463Sralph 			for (i = 3; i < NOFILE; i++)
117012463Sralph 				(void) close(i);
117112463Sralph 			if ((cp = rindex(OF, '/')) == NULL)
117212463Sralph 				cp = OF;
117312463Sralph 			else
117412463Sralph 				cp++;
117512463Sralph 			execl(OF, cp, width, length, 0);
117616762Sralph 			syslog(LOG_ERR, "%s: %s: %m", printer, OF);
117712463Sralph 			exit(1);
117812463Sralph 		}
117912463Sralph 		(void) close(p[0]);		/* close input side */
118012463Sralph 		ofd = p[1];			/* use pipe for output */
118112463Sralph 	} else {
118212463Sralph 		ofd = pfd;
118312463Sralph 		ofilter = 0;
118412463Sralph 	}
118512463Sralph }
118612463Sralph 
118712111Sralph struct bauds {
118812111Sralph 	int	baud;
118912111Sralph 	int	speed;
119012111Sralph } bauds[] = {
119112111Sralph 	50,	B50,
119212111Sralph 	75,	B75,
119312111Sralph 	110,	B110,
119412111Sralph 	134,	B134,
119512111Sralph 	150,	B150,
119612111Sralph 	200,	B200,
119712111Sralph 	300,	B300,
119812111Sralph 	600,	B600,
119912111Sralph 	1200,	B1200,
120012111Sralph 	1800,	B1800,
120112111Sralph 	2400,	B2400,
120212111Sralph 	4800,	B4800,
120312111Sralph 	9600,	B9600,
120412111Sralph 	19200,	EXTA,
120512111Sralph 	38400,	EXTB,
120612111Sralph 	0,	0
120712111Sralph };
120812111Sralph 
120912111Sralph /*
121012111Sralph  * setup tty lines.
121112111Sralph  */
121212111Sralph setty()
121312111Sralph {
121412111Sralph 	struct sgttyb ttybuf;
121512111Sralph 	register struct bauds *bp;
121612111Sralph 
121712111Sralph 	if (ioctl(pfd, TIOCEXCL, (char *)0) < 0) {
121816762Sralph 		syslog(LOG_ERR, "%s: ioctl(TIOCEXCL): %m", printer);
121912111Sralph 		exit(1);
122012111Sralph 	}
122112111Sralph 	if (ioctl(pfd, TIOCGETP, (char *)&ttybuf) < 0) {
122216762Sralph 		syslog(LOG_ERR, "%s: ioctl(TIOCGETP): %m", printer);
122312111Sralph 		exit(1);
122412111Sralph 	}
122512111Sralph 	if (BR > 0) {
122612111Sralph 		for (bp = bauds; bp->baud; bp++)
122712111Sralph 			if (BR == bp->baud)
122812111Sralph 				break;
122912111Sralph 		if (!bp->baud) {
123016762Sralph 			syslog(LOG_ERR, "%s: illegal baud rate %d", printer, BR);
123112111Sralph 			exit(1);
123212111Sralph 		}
123312111Sralph 		ttybuf.sg_ispeed = ttybuf.sg_ospeed = bp->speed;
123412111Sralph 	}
123513169Sralph 	ttybuf.sg_flags &= ~FC;
123613169Sralph 	ttybuf.sg_flags |= FS;
123712111Sralph 	if (ioctl(pfd, TIOCSETP, (char *)&ttybuf) < 0) {
123816762Sralph 		syslog(LOG_ERR, "%s: ioctl(TIOCSETP): %m", printer);
123912111Sralph 		exit(1);
124012111Sralph 	}
124112111Sralph 	if (XC) {
124212111Sralph 		if (ioctl(pfd, TIOCLBIC, &XC) < 0) {
124316762Sralph 			syslog(LOG_ERR, "%s: ioctl(TIOCLBIC): %m", printer);
124412111Sralph 			exit(1);
124512111Sralph 		}
124612111Sralph 	}
124712111Sralph 	if (XS) {
124812111Sralph 		if (ioctl(pfd, TIOCLBIS, &XS) < 0) {
124916762Sralph 			syslog(LOG_ERR, "%s: ioctl(TIOCLBIS): %m", printer);
125012111Sralph 			exit(1);
125112111Sralph 		}
125212111Sralph 	}
125312111Sralph }
125412463Sralph 
125512463Sralph /*VARARGS1*/
125612463Sralph status(msg, a1, a2, a3)
125712463Sralph 	char *msg;
125812463Sralph {
125912463Sralph 	register int fd;
126012463Sralph 	char buf[BUFSIZ];
126112463Sralph 
126212463Sralph 	umask(0);
126313148Ssam 	fd = open(ST, O_WRONLY|O_CREAT, 0664);
126416762Sralph 	if (fd < 0 || flock(fd, LOCK_EX) < 0) {
126516762Sralph 		syslog(LOG_ERR, "%s: %s: %m", printer, ST);
126616762Sralph 		exit(1);
126716762Sralph 	}
126813148Ssam 	ftruncate(fd, 0);
126912463Sralph 	sprintf(buf, msg, a1, a2, a3);
127012463Sralph 	strcat(buf, "\n");
127112463Sralph 	(void) write(fd, buf, strlen(buf));
127212463Sralph 	(void) close(fd);
127312463Sralph }
1274