xref: /csrg-svn/usr.sbin/lpr/lpd/printjob.c (revision 37968)
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*37968Sbostic static char sccsid[] = "@(#)printjob.c	5.7 (Berkeley) 05/11/89";
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"
30*37968Sbostic #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 */
6916762Sralph char	tmpfile[] = "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);
86*37968Sbostic 		(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 
9615811Sralph 	(void) mktemp(tmpfile);
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 		}
21415811Sralph 		(void) unlink(tmpfile);
21512463Sralph 		exit(0);
21612463Sralph 	}
21712111Sralph 	goto again;
21812111Sralph }
21912111Sralph 
22012111Sralph char	fonts[4][50];	/* fonts for troff */
22112111Sralph 
222*37968Sbostic char ifonts[4][40] = {
223*37968Sbostic 	_PATH_VFONTR,
224*37968Sbostic 	_PATH_VFONTI,
225*37968Sbostic 	_PATH_VFONTB,
226*37968Sbostic 	_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;
43112111Sralph 	char *av[15], buf[BUFSIZ];
43212111Sralph 	int pid, p[2], stopped = 0;
43312111Sralph 	union wait status;
43417463Sralph 	struct stat stb;
43512111Sralph 
43617463Sralph 	if (lstat(file, &stb) < 0 || (fi = open(file, O_RDONLY)) < 0)
43717463Sralph 		return(ERROR);
43817463Sralph 	/*
43917463Sralph 	 * Check to see if data file is a symbolic link. If so, it should
44017463Sralph 	 * still point to the same file or someone is trying to print
44117463Sralph 	 * something he shouldn't.
44217463Sralph 	 */
44317463Sralph 	if ((stb.st_mode & S_IFMT) == S_IFLNK && fstat(fi, &stb) == 0 &&
44417463Sralph 	    (stb.st_dev != fdev || stb.st_ino != fino))
44517463Sralph 		return(ACCESS);
44612111Sralph 	if (!SF && !tof) {		/* start on a fresh page */
44712111Sralph 		(void) write(ofd, FF, strlen(FF));
44812111Sralph 		tof = 1;
44912111Sralph 	}
45012111Sralph 	if (IF == NULL && (format == 'f' || format == 'l')) {
45112111Sralph 		tof = 0;
45212111Sralph 		while ((n = read(fi, buf, BUFSIZ)) > 0)
45312111Sralph 			if (write(ofd, buf, n) != n) {
45412111Sralph 				(void) close(fi);
45517463Sralph 				return(REPRINT);
45612111Sralph 			}
45712111Sralph 		(void) close(fi);
45817463Sralph 		return(OK);
45912111Sralph 	}
46012111Sralph 	switch (format) {
46112111Sralph 	case 'p':	/* print file using 'pr' */
46212111Sralph 		if (IF == NULL) {	/* use output filter */
463*37968Sbostic 			prog = _PATH_PR;
46412111Sralph 			av[0] = "pr";
46512111Sralph 			av[1] = width;
46612111Sralph 			av[2] = length;
46712111Sralph 			av[3] = "-h";
46812111Sralph 			av[4] = *title ? title : " ";
46912111Sralph 			av[5] = 0;
47012111Sralph 			fo = ofd;
47112111Sralph 			goto start;
47212111Sralph 		}
47312111Sralph 		pipe(p);
47412111Sralph 		if ((prchild = dofork(DORETURN)) == 0) {	/* child */
47512111Sralph 			dup2(fi, 0);		/* file is stdin */
47612111Sralph 			dup2(p[1], 1);		/* pipe is stdout */
47712111Sralph 			for (n = 3; n < NOFILE; n++)
47812111Sralph 				(void) close(n);
479*37968Sbostic 			execl(_PATH_PR, "pr", width, length,
480*37968Sbostic 			    "-h", *title ? title : " ", 0);
481*37968Sbostic 			syslog(LOG_ERR, "cannot execl %s", _PATH_PR);
48212111Sralph 			exit(2);
48312111Sralph 		}
48412111Sralph 		(void) close(p[1]);		/* close output side */
48512111Sralph 		(void) close(fi);
48612111Sralph 		if (prchild < 0) {
48712111Sralph 			prchild = 0;
48812111Sralph 			(void) close(p[0]);
48917463Sralph 			return(ERROR);
49012111Sralph 		}
49112111Sralph 		fi = p[0];			/* use pipe for input */
49212111Sralph 	case 'f':	/* print plain text file */
49312111Sralph 		prog = IF;
49412111Sralph 		av[1] = width;
49512111Sralph 		av[2] = length;
49612581Sralph 		av[3] = indent;
49712581Sralph 		n = 4;
49812111Sralph 		break;
49912111Sralph 	case 'l':	/* like 'f' but pass control characters */
50012111Sralph 		prog = IF;
50114325Sralph 		av[1] = "-c";
50212111Sralph 		av[2] = width;
50312111Sralph 		av[3] = length;
50412581Sralph 		av[4] = indent;
50512581Sralph 		n = 5;
50612111Sralph 		break;
50712463Sralph 	case 'r':	/* print a fortran text file */
50812463Sralph 		prog = RF;
50912463Sralph 		av[1] = width;
51012463Sralph 		av[2] = length;
51112463Sralph 		n = 3;
51212463Sralph 		break;
51312111Sralph 	case 't':	/* print troff output */
51413233Sralph 	case 'n':	/* print ditroff output */
51512463Sralph 	case 'd':	/* print tex output */
51612111Sralph 		(void) unlink(".railmag");
51712463Sralph 		if ((fo = creat(".railmag", FILMOD)) < 0) {
51816762Sralph 			syslog(LOG_ERR, "%s: cannot create .railmag", printer);
51912111Sralph 			(void) unlink(".railmag");
52012111Sralph 		} else {
52112111Sralph 			for (n = 0; n < 4; n++) {
52212111Sralph 				if (fonts[n][0] != '/')
523*37968Sbostic 					(void) write(fo, _PATH_VFONT, 15);
52412111Sralph 				(void) write(fo, fonts[n], strlen(fonts[n]));
52512111Sralph 				(void) write(fo, "\n", 1);
52612111Sralph 			}
52712111Sralph 			(void) close(fo);
52812111Sralph 		}
52913233Sralph 		prog = (format == 't') ? TF : (format == 'n') ? NF : DF;
53012463Sralph 		av[1] = pxwidth;
53112463Sralph 		av[2] = pxlength;
53212463Sralph 		n = 3;
53312111Sralph 		break;
53412111Sralph 	case 'c':	/* print cifplot output */
53512111Sralph 		prog = CF;
53612463Sralph 		av[1] = pxwidth;
53712463Sralph 		av[2] = pxlength;
53812463Sralph 		n = 3;
53912111Sralph 		break;
54012111Sralph 	case 'g':	/* print plot(1G) output */
54112111Sralph 		prog = GF;
54212463Sralph 		av[1] = pxwidth;
54312463Sralph 		av[2] = pxlength;
54412463Sralph 		n = 3;
54512111Sralph 		break;
54612111Sralph 	case 'v':	/* print raster output */
54712111Sralph 		prog = VF;
54812463Sralph 		av[1] = pxwidth;
54912463Sralph 		av[2] = pxlength;
55012463Sralph 		n = 3;
55112111Sralph 		break;
55212111Sralph 	default:
55312111Sralph 		(void) close(fi);
55416762Sralph 		syslog(LOG_ERR, "%s: illegal format character '%c'",
55516762Sralph 			printer, format);
55617463Sralph 		return(ERROR);
55712111Sralph 	}
55812111Sralph 	if ((av[0] = rindex(prog, '/')) != NULL)
55912111Sralph 		av[0]++;
56012111Sralph 	else
56112111Sralph 		av[0] = prog;
56212111Sralph 	av[n++] = "-n";
56312111Sralph 	av[n++] = logname;
56412111Sralph 	av[n++] = "-h";
56514150Sralph 	av[n++] = fromhost;
56612111Sralph 	av[n++] = AF;
56712111Sralph 	av[n] = 0;
56812111Sralph 	fo = pfd;
56912111Sralph 	if (ofilter > 0) {		/* stop output filter */
57012111Sralph 		write(ofd, "\031\1", 2);
57112111Sralph 		while ((pid = wait3(&status, WUNTRACED, 0)) > 0 && pid != ofilter)
57212111Sralph 			;
57312111Sralph 		if (status.w_stopval != WSTOPPED) {
57412111Sralph 			(void) close(fi);
57516762Sralph 			syslog(LOG_WARNING, "%s: output filter died (%d)",
57616762Sralph 				printer, status.w_retcode);
57717463Sralph 			return(REPRINT);
57812111Sralph 		}
57912111Sralph 		stopped++;
58012111Sralph 	}
58112111Sralph start:
58212111Sralph 	if ((child = dofork(DORETURN)) == 0) {	/* child */
58312111Sralph 		dup2(fi, 0);
58412111Sralph 		dup2(fo, 1);
58517304Sralph 		n = open(tmpfile, O_WRONLY|O_CREAT|O_TRUNC, 0664);
58615811Sralph 		if (n >= 0)
58715811Sralph 			dup2(n, 2);
58812111Sralph 		for (n = 3; n < NOFILE; n++)
58912111Sralph 			(void) close(n);
59012111Sralph 		execv(prog, av);
59116762Sralph 		syslog(LOG_ERR, "cannot execv %s", prog);
59212111Sralph 		exit(2);
59312111Sralph 	}
59412111Sralph 	(void) close(fi);
59512111Sralph 	if (child < 0)
59612111Sralph 		status.w_retcode = 100;
59712111Sralph 	else
59812111Sralph 		while ((pid = wait(&status)) > 0 && pid != child)
59912111Sralph 			;
60012111Sralph 	child = 0;
60112111Sralph 	prchild = 0;
60212111Sralph 	if (stopped) {		/* restart output filter */
60312111Sralph 		if (kill(ofilter, SIGCONT) < 0) {
60416762Sralph 			syslog(LOG_ERR, "cannot restart output filter");
60512111Sralph 			exit(1);
60612111Sralph 		}
60712111Sralph 	}
60812111Sralph 	tof = 0;
60915811Sralph 	if (!WIFEXITED(status)) {
61016762Sralph 		syslog(LOG_WARNING, "%s: Daemon filter '%c' terminated (%d)",
61116762Sralph 			printer, format, status.w_termsig);
61217463Sralph 		return(ERROR);
61317463Sralph 	}
61417463Sralph 	switch (status.w_retcode) {
61517463Sralph 	case 0:
61617463Sralph 		tof = 1;
61717463Sralph 		return(OK);
61817463Sralph 	case 1:
61917463Sralph 		return(REPRINT);
62017463Sralph 	default:
62116762Sralph 		syslog(LOG_WARNING, "%s: Daemon filter '%c' exited (%d)",
62216762Sralph 			printer, format, status.w_retcode);
62317463Sralph 	case 2:
62417463Sralph 		return(ERROR);
62517463Sralph 	}
62612111Sralph }
62712111Sralph 
62812111Sralph /*
62912111Sralph  * Send the daemon control file (cf) and any data files.
63012111Sralph  * Return -1 if a non-recoverable error occured, 1 if a recoverable error and
63112111Sralph  * 0 if all is well.
63212111Sralph  */
63312111Sralph sendit(file)
63412111Sralph 	char *file;
63512111Sralph {
63617463Sralph 	register int i, err = OK;
63717463Sralph 	char *cp, last[BUFSIZ];
63812111Sralph 
63912111Sralph 	/*
64012111Sralph 	 * open control file
64112111Sralph 	 */
64216762Sralph 	if ((cfp = fopen(file, "r")) == NULL)
64317463Sralph 		return(OK);
64412111Sralph 	/*
64512111Sralph 	 *      read the control file for work to do
64612111Sralph 	 *
64712111Sralph 	 *      file format -- first character in the line is a command
64812111Sralph 	 *      rest of the line is the argument.
64912111Sralph 	 *      commands of interest are:
65012111Sralph 	 *
65112111Sralph 	 *            a-z -- "file name" name of file to print
65212111Sralph 	 *              U -- "unlink" name of file to remove
65312111Sralph 	 *                    (after we print it. (Pass 2 only)).
65412111Sralph 	 */
65512111Sralph 
65612111Sralph 	/*
65712111Sralph 	 * pass 1
65812111Sralph 	 */
65912111Sralph 	while (getline(cfp)) {
66012111Sralph 	again:
66117463Sralph 		if (line[0] == 'S') {
66217463Sralph 			cp = line+1;
66317463Sralph 			i = 0;
66417463Sralph 			while (*cp >= '0' && *cp <= '9')
66517463Sralph 				i = i * 10 + (*cp++ - '0');
66617463Sralph 			fdev = i;
66717463Sralph 			cp++;
66817463Sralph 			i = 0;
66917463Sralph 			while (*cp >= '0' && *cp <= '9')
67017463Sralph 				i = i * 10 + (*cp++ - '0');
67117463Sralph 			fino = i;
67217463Sralph 			continue;
67317463Sralph 		}
67412111Sralph 		if (line[0] >= 'a' && line[0] <= 'z') {
67512111Sralph 			strcpy(last, line);
67617463Sralph 			while (i = getline(cfp))
67712111Sralph 				if (strcmp(last, line))
67812111Sralph 					break;
67917463Sralph 			switch (sendfile('\3', last+1)) {
68017463Sralph 			case OK:
68117463Sralph 				if (i)
68217463Sralph 					goto again;
68317463Sralph 				break;
68417463Sralph 			case REPRINT:
68512111Sralph 				(void) fclose(cfp);
68617463Sralph 				return(REPRINT);
68717463Sralph 			case ACCESS:
68817463Sralph 				sendmail(logname, ACCESS);
68917463Sralph 			case ERROR:
69017463Sralph 				err = ERROR;
69117463Sralph 			}
69212111Sralph 			break;
69312111Sralph 		}
69412111Sralph 	}
69517463Sralph 	if (err == OK && sendfile('\2', file) > 0) {
69612111Sralph 		(void) fclose(cfp);
69717463Sralph 		return(REPRINT);
69812111Sralph 	}
69912111Sralph 	/*
70012111Sralph 	 * pass 2
70112111Sralph 	 */
70212111Sralph 	fseek(cfp, 0L, 0);
70312111Sralph 	while (getline(cfp))
70412111Sralph 		if (line[0] == 'U')
70512111Sralph 			(void) unlink(line+1);
70612111Sralph 	/*
70717463Sralph 	 * clean-up in case another control file exists
70812111Sralph 	 */
70912111Sralph 	(void) fclose(cfp);
71012111Sralph 	(void) unlink(file);
71117463Sralph 	return(err);
71212111Sralph }
71312111Sralph 
71412111Sralph /*
71512111Sralph  * Send a data file to the remote machine and spool it.
71612111Sralph  * Return positive if we should try resending.
71712111Sralph  */
71812111Sralph sendfile(type, file)
71912111Sralph 	char type, *file;
72012111Sralph {
72112111Sralph 	register int f, i, amt;
72212111Sralph 	struct stat stb;
72312111Sralph 	char buf[BUFSIZ];
72416762Sralph 	int sizerr, resp;
72512111Sralph 
72617463Sralph 	if (lstat(file, &stb) < 0 || (f = open(file, O_RDONLY)) < 0)
72717463Sralph 		return(ERROR);
72817463Sralph 	/*
72917463Sralph 	 * Check to see if data file is a symbolic link. If so, it should
73017463Sralph 	 * still point to the same file or someone is trying to print something
73117463Sralph 	 * he shouldn't.
73217463Sralph 	 */
73317463Sralph 	if ((stb.st_mode & S_IFMT) == S_IFLNK && fstat(f, &stb) == 0 &&
73417463Sralph 	    (stb.st_dev != fdev || stb.st_ino != fino))
73517463Sralph 		return(ACCESS);
73612111Sralph 	(void) sprintf(buf, "%c%d %s\n", type, stb.st_size, file);
73712111Sralph 	amt = strlen(buf);
73816762Sralph 	for (i = 0;  ; i++) {
73916762Sralph 		if (write(pfd, buf, amt) != amt ||
74016762Sralph 		    (resp = response()) < 0 || resp == '\1') {
74116762Sralph 			(void) close(f);
74217463Sralph 			return(REPRINT);
74316762Sralph 		} else if (resp == '\0')
74416762Sralph 			break;
74516762Sralph 		if (i == 0)
74616762Sralph 			status("no space on remote; waiting for queue to drain");
74716762Sralph 		if (i == 10)
74824861Seric 			syslog(LOG_ALERT, "%s: can't send to %s; queue full",
74916762Sralph 				printer, RM);
75016762Sralph 		sleep(5 * 60);
75112692Sralph 	}
75216762Sralph 	if (i)
75316762Sralph 		status("sending to %s", RM);
75412111Sralph 	sizerr = 0;
75512111Sralph 	for (i = 0; i < stb.st_size; i += BUFSIZ) {
75612111Sralph 		amt = BUFSIZ;
75712111Sralph 		if (i + amt > stb.st_size)
75812111Sralph 			amt = stb.st_size - i;
75912111Sralph 		if (sizerr == 0 && read(f, buf, amt) != amt)
76012111Sralph 			sizerr = 1;
76112692Sralph 		if (write(pfd, buf, amt) != amt) {
76212692Sralph 			(void) close(f);
76317463Sralph 			return(REPRINT);
76412692Sralph 		}
76512111Sralph 	}
76612111Sralph 	(void) close(f);
76712111Sralph 	if (sizerr) {
76816762Sralph 		syslog(LOG_INFO, "%s: %s: changed size", printer, file);
76917463Sralph 		/* tell recvjob to ignore this file */
77017463Sralph 		(void) write(pfd, "\1", 1);
77117463Sralph 		return(ERROR);
77217463Sralph 	}
77317463Sralph 	if (write(pfd, "", 1) != 1 || response())
77417463Sralph 		return(REPRINT);
77517463Sralph 	return(OK);
77612111Sralph }
77712111Sralph 
77812111Sralph /*
77912111Sralph  * Check to make sure there have been no errors and that both programs
78012111Sralph  * are in sync with eachother.
78112111Sralph  * Return non-zero if the connection was lost.
78212111Sralph  */
78316762Sralph response()
78412111Sralph {
78512111Sralph 	char resp;
78612111Sralph 
78716762Sralph 	if (read(pfd, &resp, 1) != 1) {
78816762Sralph 		syslog(LOG_INFO, "%s: lost connection", printer);
78916762Sralph 		return(-1);
79012111Sralph 	}
79116762Sralph 	return(resp);
79212111Sralph }
79312111Sralph 
79412111Sralph /*
79512111Sralph  * Banner printing stuff
79612111Sralph  */
79712111Sralph banner(name1, name2)
79812111Sralph 	char *name1, *name2;
79912111Sralph {
80012111Sralph 	time_t tvec;
80112111Sralph 	extern char *ctime();
80212111Sralph 
80312111Sralph 	time(&tvec);
80412111Sralph 	if (!SF && !tof)
80512111Sralph 		(void) write(ofd, FF, strlen(FF));
80612111Sralph 	if (SB) {	/* short banner only */
80712111Sralph 		if (class[0]) {
80812111Sralph 			(void) write(ofd, class, strlen(class));
80912111Sralph 			(void) write(ofd, ":", 1);
81012111Sralph 		}
81112111Sralph 		(void) write(ofd, name1, strlen(name1));
81212111Sralph 		(void) write(ofd, "  Job: ", 7);
81312111Sralph 		(void) write(ofd, name2, strlen(name2));
81412111Sralph 		(void) write(ofd, "  Date: ", 8);
81512111Sralph 		(void) write(ofd, ctime(&tvec), 24);
81612111Sralph 		(void) write(ofd, "\n", 1);
81712111Sralph 	} else {	/* normal banner */
81812111Sralph 		(void) write(ofd, "\n\n\n", 3);
81912111Sralph 		scan_out(ofd, name1, '\0');
82012111Sralph 		(void) write(ofd, "\n\n", 2);
82112111Sralph 		scan_out(ofd, name2, '\0');
82212111Sralph 		if (class[0]) {
82312111Sralph 			(void) write(ofd,"\n\n\n",3);
82412111Sralph 			scan_out(ofd, class, '\0');
82512111Sralph 		}
82612111Sralph 		(void) write(ofd, "\n\n\n\n\t\t\t\t\tJob:  ", 15);
82712111Sralph 		(void) write(ofd, name2, strlen(name2));
82812111Sralph 		(void) write(ofd, "\n\t\t\t\t\tDate: ", 12);
82912111Sralph 		(void) write(ofd, ctime(&tvec), 24);
83012111Sralph 		(void) write(ofd, "\n", 1);
83112111Sralph 	}
83212111Sralph 	if (!SF)
83312111Sralph 		(void) write(ofd, FF, strlen(FF));
83412111Sralph 	tof = 1;
83512111Sralph }
83612111Sralph 
83716762Sralph char *
83812111Sralph scnline(key, p, c)
83912111Sralph 	register char key, *p;
84012111Sralph 	char c;
84112111Sralph {
84212111Sralph 	register scnwidth;
84312111Sralph 
84412111Sralph 	for (scnwidth = WIDTH; --scnwidth;) {
84512111Sralph 		key <<= 1;
84612111Sralph 		*p++ = key & 0200 ? c : BACKGND;
84712111Sralph 	}
84812111Sralph 	return (p);
84912111Sralph }
85012111Sralph 
85112111Sralph #define TRC(q)	(((q)-' ')&0177)
85212111Sralph 
85312111Sralph scan_out(scfd, scsp, dlm)
85412111Sralph 	int scfd;
85512111Sralph 	char *scsp, dlm;
85612111Sralph {
85712111Sralph 	register char *strp;
85812111Sralph 	register nchrs, j;
85912111Sralph 	char outbuf[LINELEN+1], *sp, c, cc;
86012111Sralph 	int d, scnhgt;
86112111Sralph 	extern char scnkey[][HEIGHT];	/* in lpdchar.c */
86212111Sralph 
86312111Sralph 	for (scnhgt = 0; scnhgt++ < HEIGHT+DROP; ) {
86412111Sralph 		strp = &outbuf[0];
86512111Sralph 		sp = scsp;
86612111Sralph 		for (nchrs = 0; ; ) {
86712111Sralph 			d = dropit(c = TRC(cc = *sp++));
86812111Sralph 			if ((!d && scnhgt > HEIGHT) || (scnhgt <= DROP && d))
86912111Sralph 				for (j = WIDTH; --j;)
87012111Sralph 					*strp++ = BACKGND;
87112111Sralph 			else
87212111Sralph 				strp = scnline(scnkey[c][scnhgt-1-d], strp, cc);
87312111Sralph 			if (*sp == dlm || *sp == '\0' || nchrs++ >= PW/(WIDTH+1)-1)
87412111Sralph 				break;
87512111Sralph 			*strp++ = BACKGND;
87612111Sralph 			*strp++ = BACKGND;
87712111Sralph 		}
87812111Sralph 		while (*--strp == BACKGND && strp >= outbuf)
87912111Sralph 			;
88012111Sralph 		strp++;
88112111Sralph 		*strp++ = '\n';
88212111Sralph 		(void) write(scfd, outbuf, strp-outbuf);
88312111Sralph 	}
88412111Sralph }
88512111Sralph 
88612111Sralph dropit(c)
88712111Sralph 	char c;
88812111Sralph {
88912111Sralph 	switch(c) {
89012111Sralph 
89112111Sralph 	case TRC('_'):
89212111Sralph 	case TRC(';'):
89312111Sralph 	case TRC(','):
89412111Sralph 	case TRC('g'):
89512111Sralph 	case TRC('j'):
89612111Sralph 	case TRC('p'):
89712111Sralph 	case TRC('q'):
89812111Sralph 	case TRC('y'):
89912111Sralph 		return (DROP);
90012111Sralph 
90112111Sralph 	default:
90212111Sralph 		return (0);
90312111Sralph 	}
90412111Sralph }
90512111Sralph 
90612111Sralph /*
90712111Sralph  * sendmail ---
90812111Sralph  *   tell people about job completion
90912111Sralph  */
91015811Sralph sendmail(user, bombed)
91115811Sralph 	char *user;
91212111Sralph 	int bombed;
91312111Sralph {
91412111Sralph 	register int i;
91515811Sralph 	int p[2], s;
91612111Sralph 	register char *cp;
91712111Sralph 	char buf[100];
91815811Sralph 	struct stat stb;
91915811Sralph 	FILE *fp;
92012111Sralph 
92112111Sralph 	pipe(p);
92215811Sralph 	if ((s = dofork(DORETURN)) == 0) {		/* child */
92312111Sralph 		dup2(p[0], 0);
92412111Sralph 		for (i = 3; i < NOFILE; i++)
92512111Sralph 			(void) close(i);
926*37968Sbostic 		if ((cp = rindex(_PATH_SENDMAIL, '/')) != NULL)
92712111Sralph 			cp++;
92812111Sralph 		else
929*37968Sbostic 			cp = _PATH_SENDMAIL;
93015811Sralph 		sprintf(buf, "%s@%s", user, fromhost);
931*37968Sbostic 		execl(_PATH_SENDMAIL, cp, buf, 0);
93212111Sralph 		exit(0);
93315811Sralph 	} else if (s > 0) {				/* parent */
93412111Sralph 		dup2(p[1], 1);
93515811Sralph 		printf("To: %s@%s\n", user, fromhost);
93612111Sralph 		printf("Subject: printer job\n\n");
93712111Sralph 		printf("Your printer job ");
93812111Sralph 		if (*jobname)
93912111Sralph 			printf("(%s) ", jobname);
94012463Sralph 		switch (bombed) {
94117463Sralph 		case OK:
94212463Sralph 			printf("\ncompleted successfully\n");
94312463Sralph 			break;
94412463Sralph 		default:
94517463Sralph 		case FATALERR:
94612463Sralph 			printf("\ncould not be printed\n");
94712463Sralph 			break;
94817463Sralph 		case NOACCT:
94912463Sralph 			printf("\ncould not be printed without an account on %s\n", host);
95012463Sralph 			break;
95117463Sralph 		case FILTERERR:
95215811Sralph 			if (stat(tmpfile, &stb) < 0 || stb.st_size == 0 ||
95315811Sralph 			    (fp = fopen(tmpfile, "r")) == NULL) {
95415811Sralph 				printf("\nwas printed but had some errors\n");
95515811Sralph 				break;
95615811Sralph 			}
95715811Sralph 			printf("\nwas printed but had the following errors:\n");
95815811Sralph 			while ((i = getc(fp)) != EOF)
95915811Sralph 				putchar(i);
96015811Sralph 			(void) fclose(fp);
96117463Sralph 			break;
96217463Sralph 		case ACCESS:
96317463Sralph 			printf("\nwas not printed because it was not linked to the original file\n");
96412463Sralph 		}
96512111Sralph 		fflush(stdout);
96612111Sralph 		(void) close(1);
96712111Sralph 	}
96812111Sralph 	(void) close(p[0]);
96912111Sralph 	(void) close(p[1]);
97015811Sralph 	wait(&s);
97112111Sralph }
97212111Sralph 
97312111Sralph /*
97412111Sralph  * dofork - fork with retries on failure
97512111Sralph  */
97612111Sralph dofork(action)
97712111Sralph 	int action;
97812111Sralph {
97912111Sralph 	register int i, pid;
98012111Sralph 
98112111Sralph 	for (i = 0; i < 20; i++) {
98212463Sralph 		if ((pid = fork()) < 0) {
98312111Sralph 			sleep((unsigned)(i*i));
98412463Sralph 			continue;
98512463Sralph 		}
98612463Sralph 		/*
98712463Sralph 		 * Child should run as daemon instead of root
98812463Sralph 		 */
98912463Sralph 		if (pid == 0)
99012463Sralph 			setuid(DU);
99112463Sralph 		return(pid);
99212111Sralph 	}
99316762Sralph 	syslog(LOG_ERR, "can't fork");
99412111Sralph 
99512111Sralph 	switch (action) {
99612111Sralph 	case DORETURN:
99712111Sralph 		return (-1);
99812111Sralph 	default:
99916762Sralph 		syslog(LOG_ERR, "bad action (%d) to dofork", action);
100012111Sralph 		/*FALL THRU*/
100112111Sralph 	case DOABORT:
100212111Sralph 		exit(1);
100312111Sralph 	}
100412111Sralph 	/*NOTREACHED*/
100512111Sralph }
100612111Sralph 
100712111Sralph /*
100816762Sralph  * Kill child processes to abort current job.
100912111Sralph  */
101016762Sralph abortpr()
101112111Sralph {
101215811Sralph 	(void) unlink(tmpfile);
101312111Sralph 	kill(0, SIGINT);
101412111Sralph 	if (ofilter > 0)
101512111Sralph 		kill(ofilter, SIGCONT);
101612111Sralph 	while (wait(0) > 0)
101712111Sralph 		;
101812111Sralph 	exit(0);
101912111Sralph }
102012111Sralph 
102112111Sralph init()
102212111Sralph {
102312111Sralph 	int status;
102412111Sralph 
102525468Stef 	if ((status = pgetent(line, printer)) < 0) {
102625468Stef 		syslog(LOG_ERR, "can't open printer description file");
102725468Stef 		exit(1);
102825468Stef 	} else if (status == 0) {
102925468Stef 		syslog(LOG_ERR, "unknown printer: %s", printer);
103025468Stef 		exit(1);
103125468Stef 	}
103212111Sralph 	if ((LP = pgetstr("lp", &bp)) == NULL)
1033*37968Sbostic 		LP = _PATH_DEFDEVLP;
103412111Sralph 	if ((RP = pgetstr("rp", &bp)) == NULL)
103512463Sralph 		RP = DEFLP;
103612111Sralph 	if ((LO = pgetstr("lo", &bp)) == NULL)
103712111Sralph 		LO = DEFLOCK;
103812111Sralph 	if ((ST = pgetstr("st", &bp)) == NULL)
103912111Sralph 		ST = DEFSTAT;
104012111Sralph 	if ((LF = pgetstr("lf", &bp)) == NULL)
1041*37968Sbostic 		LF = _PATH_CONSOLE;
104212111Sralph 	if ((SD = pgetstr("sd", &bp)) == NULL)
1043*37968Sbostic 		SD = _PATH_DEFSPOOL;
104412111Sralph 	if ((DU = pgetnum("du")) < 0)
104512111Sralph 		DU = DEFUID;
104612111Sralph 	if ((FF = pgetstr("ff", &bp)) == NULL)
104712111Sralph 		FF = DEFFF;
104812111Sralph 	if ((PW = pgetnum("pw")) < 0)
104912111Sralph 		PW = DEFWIDTH;
105012111Sralph 	sprintf(&width[2], "%d", PW);
105112111Sralph 	if ((PL = pgetnum("pl")) < 0)
105212111Sralph 		PL = DEFLENGTH;
105312111Sralph 	sprintf(&length[2], "%d", PL);
105412463Sralph 	if ((PX = pgetnum("px")) < 0)
105512463Sralph 		PX = 0;
105612463Sralph 	sprintf(&pxwidth[2], "%d", PX);
105712463Sralph 	if ((PY = pgetnum("py")) < 0)
105812463Sralph 		PY = 0;
105912463Sralph 	sprintf(&pxlength[2], "%d", PY);
106012111Sralph 	RM = pgetstr("rm", &bp);
106125468Stef 	/*
106225468Stef 	 * Figure out whether the local machine is the same as the remote
106325468Stef 	 * machine entry (if it exists).  If not, then ignore the local
106425468Stef 	 * queue information.
106525468Stef 	 */
106625468Stef 	 if (RM != (char *) NULL) {
106725468Stef 		char name[256];
106825468Stef 		struct hostent *hp;
106925468Stef 
107025468Stef 		/* get the standard network name of the local host */
107125468Stef 		gethostname(name, sizeof(name));
107225468Stef 		name[sizeof(name)-1] = '\0';
107325468Stef 		hp = gethostbyname(name);
107425468Stef 		if (hp == (struct hostent *) NULL) {
107525468Stef 		    syslog(LOG_ERR,
107625468Stef 			"unable to get network name for local machine %s",
107725468Stef 			name);
107825468Stef 		    goto localcheck_done;
107925468Stef 		} else strcpy(name, hp->h_name);
108025468Stef 
108125468Stef 		/* get the standard network name of RM */
108225468Stef 		hp = gethostbyname(RM);
108325468Stef 		if (hp == (struct hostent *) NULL) {
108425468Stef 		    syslog(LOG_ERR,
108525468Stef 			"unable to get hostname for remote machine %s", RM);
108625468Stef 		    goto localcheck_done;
108725468Stef 		}
108825468Stef 
108925468Stef 		/* if printer is not on local machine, ignore LP */
109025468Stef 		if (strcmp(name, hp->h_name) != 0) *LP = '\0';
109125468Stef 	}
109225468Stef localcheck_done:
109325468Stef 
109412111Sralph 	AF = pgetstr("af", &bp);
109512111Sralph 	OF = pgetstr("of", &bp);
109612111Sralph 	IF = pgetstr("if", &bp);
109712463Sralph 	RF = pgetstr("rf", &bp);
109812111Sralph 	TF = pgetstr("tf", &bp);
109913233Sralph 	NF = pgetstr("nf", &bp);
110012111Sralph 	DF = pgetstr("df", &bp);
110112111Sralph 	GF = pgetstr("gf", &bp);
110212111Sralph 	VF = pgetstr("vf", &bp);
110312111Sralph 	CF = pgetstr("cf", &bp);
110412111Sralph 	TR = pgetstr("tr", &bp);
110512463Sralph 	RS = pgetflag("rs");
110612111Sralph 	SF = pgetflag("sf");
110712111Sralph 	SH = pgetflag("sh");
110812111Sralph 	SB = pgetflag("sb");
110918127Sralph 	HL = pgetflag("hl");
111012111Sralph 	RW = pgetflag("rw");
111112111Sralph 	BR = pgetnum("br");
111212111Sralph 	if ((FC = pgetnum("fc")) < 0)
111312111Sralph 		FC = 0;
111412111Sralph 	if ((FS = pgetnum("fs")) < 0)
111512111Sralph 		FS = 0;
111612111Sralph 	if ((XC = pgetnum("xc")) < 0)
111712111Sralph 		XC = 0;
111812111Sralph 	if ((XS = pgetnum("xs")) < 0)
111912111Sralph 		XS = 0;
112012581Sralph 	tof = !pgetflag("fo");
112112111Sralph }
112212111Sralph 
112312463Sralph /*
112412463Sralph  * Acquire line printer or remote connection.
112512463Sralph  */
112612463Sralph openpr()
112712463Sralph {
112812463Sralph 	register int i, n;
112916762Sralph 	int resp;
113012463Sralph 
113112463Sralph 	if (*LP) {
113212463Sralph 		for (i = 1; ; i = i < 32 ? i << 1 : i) {
113313148Ssam 			pfd = open(LP, RW ? O_RDWR : O_WRONLY);
113412463Sralph 			if (pfd >= 0)
113512463Sralph 				break;
113612463Sralph 			if (errno == ENOENT) {
113716762Sralph 				syslog(LOG_ERR, "%s: %m", LP);
113812463Sralph 				exit(1);
113912463Sralph 			}
114012463Sralph 			if (i == 1)
114112463Sralph 				status("waiting for %s to become ready (offline ?)", printer);
114212463Sralph 			sleep(i);
114312463Sralph 		}
114412463Sralph 		if (isatty(pfd))
114512463Sralph 			setty();
114612463Sralph 		status("%s is ready and printing", printer);
114712463Sralph 	} else if (RM != NULL) {
114816762Sralph 		for (i = 1; ; i = i < 256 ? i << 1 : i) {
114916762Sralph 			resp = -1;
115012528Sralph 			pfd = getport(RM);
115112463Sralph 			if (pfd >= 0) {
115212463Sralph 				(void) sprintf(line, "\2%s\n", RP);
115312463Sralph 				n = strlen(line);
115416762Sralph 				if (write(pfd, line, n) == n &&
115516762Sralph 				    (resp = response()) == '\0')
115612463Sralph 					break;
115716031Sralph 				(void) close(pfd);
115812463Sralph 			}
115916031Sralph 			if (i == 1) {
116016762Sralph 				if (resp < 0)
116116031Sralph 					status("waiting for %s to come up", RM);
116216762Sralph 				else {
116316031Sralph 					status("waiting for queue to be enabled on %s", RM);
116416762Sralph 					i = 256;
116516762Sralph 				}
116616031Sralph 			}
116712463Sralph 			sleep(i);
116812463Sralph 		}
116912463Sralph 		status("sending to %s", RM);
117012463Sralph 		remote = 1;
117112463Sralph 	} else {
117216762Sralph 		syslog(LOG_ERR, "%s: no line printer device or host name",
117316762Sralph 			printer);
117412463Sralph 		exit(1);
117512463Sralph 	}
117612463Sralph 	/*
117712463Sralph 	 * Start up an output filter, if needed.
117812463Sralph 	 */
117912463Sralph 	if (OF) {
118012463Sralph 		int p[2];
118112463Sralph 		char *cp;
118212463Sralph 
118312463Sralph 		pipe(p);
118412463Sralph 		if ((ofilter = dofork(DOABORT)) == 0) {	/* child */
118512463Sralph 			dup2(p[0], 0);		/* pipe is std in */
118612463Sralph 			dup2(pfd, 1);		/* printer is std out */
118712463Sralph 			for (i = 3; i < NOFILE; i++)
118812463Sralph 				(void) close(i);
118912463Sralph 			if ((cp = rindex(OF, '/')) == NULL)
119012463Sralph 				cp = OF;
119112463Sralph 			else
119212463Sralph 				cp++;
119312463Sralph 			execl(OF, cp, width, length, 0);
119416762Sralph 			syslog(LOG_ERR, "%s: %s: %m", printer, OF);
119512463Sralph 			exit(1);
119612463Sralph 		}
119712463Sralph 		(void) close(p[0]);		/* close input side */
119812463Sralph 		ofd = p[1];			/* use pipe for output */
119912463Sralph 	} else {
120012463Sralph 		ofd = pfd;
120112463Sralph 		ofilter = 0;
120212463Sralph 	}
120312463Sralph }
120412463Sralph 
120512111Sralph struct bauds {
120612111Sralph 	int	baud;
120712111Sralph 	int	speed;
120812111Sralph } bauds[] = {
120912111Sralph 	50,	B50,
121012111Sralph 	75,	B75,
121112111Sralph 	110,	B110,
121212111Sralph 	134,	B134,
121312111Sralph 	150,	B150,
121412111Sralph 	200,	B200,
121512111Sralph 	300,	B300,
121612111Sralph 	600,	B600,
121712111Sralph 	1200,	B1200,
121812111Sralph 	1800,	B1800,
121912111Sralph 	2400,	B2400,
122012111Sralph 	4800,	B4800,
122112111Sralph 	9600,	B9600,
122212111Sralph 	19200,	EXTA,
122312111Sralph 	38400,	EXTB,
122412111Sralph 	0,	0
122512111Sralph };
122612111Sralph 
122712111Sralph /*
122812111Sralph  * setup tty lines.
122912111Sralph  */
123012111Sralph setty()
123112111Sralph {
123212111Sralph 	struct sgttyb ttybuf;
123312111Sralph 	register struct bauds *bp;
123412111Sralph 
123512111Sralph 	if (ioctl(pfd, TIOCEXCL, (char *)0) < 0) {
123616762Sralph 		syslog(LOG_ERR, "%s: ioctl(TIOCEXCL): %m", printer);
123712111Sralph 		exit(1);
123812111Sralph 	}
123912111Sralph 	if (ioctl(pfd, TIOCGETP, (char *)&ttybuf) < 0) {
124016762Sralph 		syslog(LOG_ERR, "%s: ioctl(TIOCGETP): %m", printer);
124112111Sralph 		exit(1);
124212111Sralph 	}
124312111Sralph 	if (BR > 0) {
124412111Sralph 		for (bp = bauds; bp->baud; bp++)
124512111Sralph 			if (BR == bp->baud)
124612111Sralph 				break;
124712111Sralph 		if (!bp->baud) {
124816762Sralph 			syslog(LOG_ERR, "%s: illegal baud rate %d", printer, BR);
124912111Sralph 			exit(1);
125012111Sralph 		}
125112111Sralph 		ttybuf.sg_ispeed = ttybuf.sg_ospeed = bp->speed;
125212111Sralph 	}
125313169Sralph 	ttybuf.sg_flags &= ~FC;
125413169Sralph 	ttybuf.sg_flags |= FS;
125512111Sralph 	if (ioctl(pfd, TIOCSETP, (char *)&ttybuf) < 0) {
125616762Sralph 		syslog(LOG_ERR, "%s: ioctl(TIOCSETP): %m", printer);
125712111Sralph 		exit(1);
125812111Sralph 	}
125917168Sralph 	if (XC || XS) {
126017168Sralph 		int ldisc = NTTYDISC;
126117168Sralph 
126217168Sralph 		if (ioctl(pfd, TIOCSETD, &ldisc) < 0) {
126317168Sralph 			syslog(LOG_ERR, "%s: ioctl(TIOCSETD): %m", printer);
126417168Sralph 			exit(1);
126517168Sralph 		}
126617168Sralph 	}
126712111Sralph 	if (XC) {
126812111Sralph 		if (ioctl(pfd, TIOCLBIC, &XC) < 0) {
126916762Sralph 			syslog(LOG_ERR, "%s: ioctl(TIOCLBIC): %m", printer);
127012111Sralph 			exit(1);
127112111Sralph 		}
127212111Sralph 	}
127312111Sralph 	if (XS) {
127412111Sralph 		if (ioctl(pfd, TIOCLBIS, &XS) < 0) {
127516762Sralph 			syslog(LOG_ERR, "%s: ioctl(TIOCLBIS): %m", printer);
127612111Sralph 			exit(1);
127712111Sralph 		}
127812111Sralph 	}
127912111Sralph }
128012463Sralph 
128112463Sralph /*VARARGS1*/
128212463Sralph status(msg, a1, a2, a3)
128312463Sralph 	char *msg;
128412463Sralph {
128512463Sralph 	register int fd;
128612463Sralph 	char buf[BUFSIZ];
128712463Sralph 
128812463Sralph 	umask(0);
128913148Ssam 	fd = open(ST, O_WRONLY|O_CREAT, 0664);
129016762Sralph 	if (fd < 0 || flock(fd, LOCK_EX) < 0) {
129116762Sralph 		syslog(LOG_ERR, "%s: %s: %m", printer, ST);
129216762Sralph 		exit(1);
129316762Sralph 	}
129413148Ssam 	ftruncate(fd, 0);
129512463Sralph 	sprintf(buf, msg, a1, a2, a3);
129612463Sralph 	strcat(buf, "\n");
129712463Sralph 	(void) write(fd, buf, strlen(buf));
129812463Sralph 	(void) close(fd);
129912463Sralph }
1300