xref: /csrg-svn/usr.sbin/lpr/lpd/printjob.c (revision 34936)
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
6*34936Sbostic  * provided that the above copyright notice and this paragraph are
7*34936Sbostic  * duplicated in all such forms and that any documentation,
8*34936Sbostic  * advertising materials, and other materials related to such
9*34936Sbostic  * distribution and use acknowledge that the software was developed
10*34936Sbostic  * by the University of California, Berkeley.  The name of the
11*34936Sbostic  * University may not be used to endorse or promote products derived
12*34936Sbostic  * from this software without specific prior written permission.
13*34936Sbostic  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
14*34936Sbostic  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
15*34936Sbostic  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
1622437Sdist  */
1722437Sdist 
1813954Ssam #ifndef lint
19*34936Sbostic static char sccsid[] = "@(#)printjob.c	5.6 (Berkeley) 06/30/88";
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"
3012111Sralph 
3116762Sralph #define DORETURN	0	/* absorb fork error */
3216762Sralph #define DOABORT		1	/* abort if dofork fails */
3312111Sralph 
3417463Sralph /*
3517463Sralph  * Error tokens
3617463Sralph  */
3717463Sralph #define REPRINT		-2
3817463Sralph #define ERROR		-1
3917463Sralph #define	OK		0
4017463Sralph #define	FATALERR	1
4117463Sralph #define	NOACCT		2
4217463Sralph #define	FILTERERR	3
4317463Sralph #define	ACCESS		4
4417463Sralph 
4516762Sralph char	title[80];		/* ``pr'' title */
4616762Sralph FILE	*cfp;			/* control file */
4716762Sralph int	pfd;			/* printer file descriptor */
4816762Sralph int	ofd;			/* output filter file descriptor */
4916762Sralph int	lfd;			/* lock file descriptor */
5016762Sralph int	pid;			/* pid of lpd process */
5116762Sralph int	prchild;		/* id of pr process */
5216762Sralph int	child;			/* id of any filters */
5316762Sralph int	ofilter;		/* id of output filter, if any */
5416762Sralph int	tof;			/* true if at top of form */
5516762Sralph int	remote;			/* true if sending files to remote */
5617463Sralph dev_t	fdev;			/* device of file pointed to by symlink */
5717463Sralph ino_t	fino;			/* inode of file pointed to by symlink */
5812111Sralph 
5916762Sralph char	fromhost[32];		/* user's host machine */
6016762Sralph char	logname[32];		/* user's login name */
6116762Sralph char	jobname[100];		/* job or file name */
6216762Sralph char	class[32];		/* classification field */
6316762Sralph char	width[10] = "-w";	/* page width in characters */
6416762Sralph char	length[10] = "-l";	/* page length in lines */
6516762Sralph char	pxwidth[10] = "-x";	/* page width in pixels */
6616762Sralph char	pxlength[10] = "-y";	/* page length in pixels */
6716762Sralph char	indent[10] = "-i0";	/* indentation size in characters */
6816762Sralph char	tmpfile[] = "errsXXXXXX"; /* file name for filter output */
6912111Sralph 
7012111Sralph printjob()
7112111Sralph {
7212111Sralph 	struct stat stb;
7312111Sralph 	register struct queue *q, **qp;
7412111Sralph 	struct queue **queue;
7512111Sralph 	register int i, nitems;
7612111Sralph 	long pidoff;
7716762Sralph 	int count = 0;
7816762Sralph 	extern int abortpr();
7912111Sralph 
8012111Sralph 	init();					/* set up capabilities */
8113442Sralph 	(void) write(1, "", 1);			/* ack that daemon is started */
8225496Seric 	(void) close(2);			/* set up log file */
8325496Seric 	if (open(LF, O_WRONLY|O_APPEND, 0664) < 0) {
8425496Seric 		syslog(LOG_ERR, "%s: %m", LF);
8525496Seric 		(void) open("/dev/null", O_WRONLY);
8625496Seric 	}
8716762Sralph 	setgid(getegid());
8812463Sralph 	pid = getpid();				/* for use with lprm */
8912111Sralph 	setpgrp(0, pid);
9016762Sralph 	signal(SIGHUP, abortpr);
9116762Sralph 	signal(SIGINT, abortpr);
9216762Sralph 	signal(SIGQUIT, abortpr);
9316762Sralph 	signal(SIGTERM, abortpr);
9412111Sralph 
9515811Sralph 	(void) mktemp(tmpfile);
9615811Sralph 
9712111Sralph 	/*
9812111Sralph 	 * uses short form file names
9912111Sralph 	 */
10012111Sralph 	if (chdir(SD) < 0) {
10116762Sralph 		syslog(LOG_ERR, "%s: %m", SD);
10212111Sralph 		exit(1);
10312111Sralph 	}
10412463Sralph 	if (stat(LO, &stb) == 0 && (stb.st_mode & 0100))
10512463Sralph 		exit(0);		/* printing disabled */
10614150Sralph 	lfd = open(LO, O_WRONLY|O_CREAT, 0644);
10713169Sralph 	if (lfd < 0) {
10816762Sralph 		syslog(LOG_ERR, "%s: %s: %m", printer, LO);
10913169Sralph 		exit(1);
11013169Sralph 	}
11113169Sralph 	if (flock(lfd, LOCK_EX|LOCK_NB) < 0) {
11212111Sralph 		if (errno == EWOULDBLOCK)	/* active deamon present */
11312111Sralph 			exit(0);
11416762Sralph 		syslog(LOG_ERR, "%s: %s: %m", printer, LO);
11512111Sralph 		exit(1);
11612111Sralph 	}
11713148Ssam 	ftruncate(lfd, 0);
11812111Sralph 	/*
11912111Sralph 	 * write process id for others to know
12012111Sralph 	 */
12112111Sralph 	sprintf(line, "%u\n", pid);
12212111Sralph 	pidoff = i = strlen(line);
12312463Sralph 	if (write(lfd, line, i) != i) {
12416762Sralph 		syslog(LOG_ERR, "%s: %s: %m", printer, LO);
12512111Sralph 		exit(1);
12612111Sralph 	}
12712111Sralph 	/*
12812111Sralph 	 * search the spool directory for work and sort by queue order.
12912111Sralph 	 */
13012111Sralph 	if ((nitems = getq(&queue)) < 0) {
13116762Sralph 		syslog(LOG_ERR, "%s: can't scan %s", printer, SD);
13212111Sralph 		exit(1);
13312111Sralph 	}
13412463Sralph 	if (nitems == 0)		/* no work to do */
13512111Sralph 		exit(0);
13613169Sralph 	if (stb.st_mode & 01) {		/* reset queue flag */
13713169Sralph 		if (fchmod(lfd, stb.st_mode & 0776) < 0)
13816762Sralph 			syslog(LOG_ERR, "%s: %s: %m", printer, LO);
13913169Sralph 	}
14012463Sralph 	openpr();			/* open printer or remote */
14112463Sralph again:
14212111Sralph 	/*
14312111Sralph 	 * we found something to do now do it --
14412111Sralph 	 *    write the name of the current control file into the lock file
14512111Sralph 	 *    so the spool queue program can tell what we're working on
14612111Sralph 	 */
14712111Sralph 	for (qp = queue; nitems--; free((char *) q)) {
14812111Sralph 		q = *qp++;
14912111Sralph 		if (stat(q->q_name, &stb) < 0)
15012111Sralph 			continue;
15112463Sralph 	restart:
15212111Sralph 		(void) lseek(lfd, pidoff, 0);
15312111Sralph 		(void) sprintf(line, "%s\n", q->q_name);
15412111Sralph 		i = strlen(line);
15512111Sralph 		if (write(lfd, line, i) != i)
15616762Sralph 			syslog(LOG_ERR, "%s: %s: %m", printer, LO);
15712111Sralph 		if (!remote)
15812111Sralph 			i = printit(q->q_name);
15912111Sralph 		else
16012111Sralph 			i = sendit(q->q_name);
16112463Sralph 		/*
16213169Sralph 		 * Check to see if we are supposed to stop printing or
16313169Sralph 		 * if we are to rebuild the queue.
16412463Sralph 		 */
16513169Sralph 		if (fstat(lfd, &stb) == 0) {
16616762Sralph 			/* stop printing before starting next job? */
16713169Sralph 			if (stb.st_mode & 0100)
16813169Sralph 				goto done;
16916762Sralph 			/* rebuild queue (after lpc topq) */
17013169Sralph 			if (stb.st_mode & 01) {
17113169Sralph 				for (free((char *) q); nitems--; free((char *) q))
17213169Sralph 					q = *qp++;
17313169Sralph 				if (fchmod(lfd, stb.st_mode & 0776) < 0)
17416762Sralph 					syslog(LOG_WARNING, "%s: %s: %m",
17516762Sralph 						printer, LO);
17613169Sralph 				break;
17713169Sralph 			}
17813169Sralph 		}
17917463Sralph 		if (i == OK)		/* file ok and printed */
18014150Sralph 			count++;
18117463Sralph 		else if (i == REPRINT) { /* try reprinting the job */
18216762Sralph 			syslog(LOG_INFO, "restarting %s", printer);
18312111Sralph 			if (ofilter > 0) {
18412111Sralph 				kill(ofilter, SIGCONT);	/* to be sure */
18512111Sralph 				(void) close(ofd);
18612111Sralph 				while ((i = wait(0)) > 0 && i != ofilter)
18712111Sralph 					;
18812111Sralph 				ofilter = 0;
18912111Sralph 			}
19012463Sralph 			(void) close(pfd);	/* close printer */
19115811Sralph 			if (ftruncate(lfd, pidoff) < 0)
19216762Sralph 				syslog(LOG_WARNING, "%s: %s: %m", printer, LO);
19312463Sralph 			openpr();		/* try to reopen printer */
19412111Sralph 			goto restart;
19512111Sralph 		}
19612111Sralph 	}
19712111Sralph 	free((char *) queue);
19812463Sralph 	/*
19912463Sralph 	 * search the spool directory for more work.
20012463Sralph 	 */
20112463Sralph 	if ((nitems = getq(&queue)) < 0) {
20216762Sralph 		syslog(LOG_ERR, "%s: can't scan %s", printer, SD);
20312463Sralph 		exit(1);
20412463Sralph 	}
20512463Sralph 	if (nitems == 0) {		/* no more work to do */
20612463Sralph 	done:
20714150Sralph 		if (count > 0) {	/* Files actually printed */
20814150Sralph 			if (!SF && !tof)
20914150Sralph 				(void) write(ofd, FF, strlen(FF));
21014150Sralph 			if (TR != NULL)		/* output trailer */
21114150Sralph 				(void) write(ofd, TR, strlen(TR));
21214150Sralph 		}
21315811Sralph 		(void) unlink(tmpfile);
21412463Sralph 		exit(0);
21512463Sralph 	}
21612111Sralph 	goto again;
21712111Sralph }
21812111Sralph 
21912111Sralph char	fonts[4][50];	/* fonts for troff */
22012111Sralph 
22116762Sralph char ifonts[4][18] = {
22212111Sralph 	"/usr/lib/vfont/R",
22312111Sralph 	"/usr/lib/vfont/I",
22412111Sralph 	"/usr/lib/vfont/B",
22512111Sralph 	"/usr/lib/vfont/S"
22612111Sralph };
22712111Sralph 
22812111Sralph /*
22912111Sralph  * The remaining part is the reading of the control file (cf)
23012111Sralph  * and performing the various actions.
23112111Sralph  */
23212111Sralph printit(file)
23312111Sralph 	char *file;
23412111Sralph {
23512111Sralph 	register int i;
23617463Sralph 	char *cp;
23717463Sralph 	int bombed = OK;
23812111Sralph 
23912111Sralph 	/*
24017463Sralph 	 * open control file; ignore if no longer there.
24112111Sralph 	 */
24212111Sralph 	if ((cfp = fopen(file, "r")) == NULL) {
24316762Sralph 		syslog(LOG_INFO, "%s: %s: %m", printer, file);
24417463Sralph 		return(OK);
24512111Sralph 	}
24612111Sralph 	/*
24712111Sralph 	 * Reset troff fonts.
24812111Sralph 	 */
24912111Sralph 	for (i = 0; i < 4; i++)
25012111Sralph 		strcpy(fonts[i], ifonts[i]);
25117339Sralph 	strcpy(width+2, "0");
25217302Sralph 	strcpy(indent+2, "0");
25312111Sralph 
25412111Sralph 	/*
25512111Sralph 	 *      read the control file for work to do
25612111Sralph 	 *
25712111Sralph 	 *      file format -- first character in the line is a command
25812111Sralph 	 *      rest of the line is the argument.
25912111Sralph 	 *      valid commands are:
26012111Sralph 	 *
26117463Sralph 	 *		S -- "stat info" for symbolic link protection
26212111Sralph 	 *		J -- "job name" on banner page
26312111Sralph 	 *		C -- "class name" on banner page
26412111Sralph 	 *              L -- "literal" user's name to print on banner
26512111Sralph 	 *		T -- "title" for pr
26612111Sralph 	 *		H -- "host name" of machine where lpr was done
26712111Sralph 	 *              P -- "person" user's login name
26812581Sralph 	 *              I -- "indent" amount to indent output
26912111Sralph 	 *              f -- "file name" name of text file to print
27012111Sralph 	 *		l -- "file name" text file with control chars
27112111Sralph 	 *		p -- "file name" text file to print with pr(1)
27212111Sralph 	 *		t -- "file name" troff(1) file to print
27313233Sralph 	 *		n -- "file name" ditroff(1) file to print
27412111Sralph 	 *		d -- "file name" dvi file to print
27512111Sralph 	 *		g -- "file name" plot(1G) file to print
27612111Sralph 	 *		v -- "file name" plain raster file to print
27712111Sralph 	 *		c -- "file name" cifplot file to print
27812111Sralph 	 *		1 -- "R font file" for troff
27912111Sralph 	 *		2 -- "I font file" for troff
28012111Sralph 	 *		3 -- "B font file" for troff
28112111Sralph 	 *		4 -- "S font file" for troff
28212111Sralph 	 *		N -- "name" of file (used by lpq)
28312111Sralph 	 *              U -- "unlink" name of file to remove
28412111Sralph 	 *                    (after we print it. (Pass 2 only)).
28512111Sralph 	 *		M -- "mail" to user when done printing
28612111Sralph 	 *
28712111Sralph 	 *      getline reads a line and expands tabs to blanks
28812111Sralph 	 */
28912111Sralph 
29012111Sralph 	/* pass 1 */
29112111Sralph 
29212111Sralph 	while (getline(cfp))
29312111Sralph 		switch (line[0]) {
29412111Sralph 		case 'H':
29514150Sralph 			strcpy(fromhost, line+1);
29612111Sralph 			if (class[0] == '\0')
29715552Sralph 				strncpy(class, line+1, sizeof(class)-1);
29812111Sralph 			continue;
29912111Sralph 
30012111Sralph 		case 'P':
30115552Sralph 			strncpy(logname, line+1, sizeof(logname)-1);
30212463Sralph 			if (RS) {			/* restricted */
30312463Sralph 				if (getpwnam(logname) == (struct passwd *)0) {
30417463Sralph 					bombed = NOACCT;
30515811Sralph 					sendmail(line+1, bombed);
30612463Sralph 					goto pass2;
30712463Sralph 				}
30812463Sralph 			}
30912111Sralph 			continue;
31012111Sralph 
31117463Sralph 		case 'S':
31217463Sralph 			cp = line+1;
31317463Sralph 			i = 0;
31417463Sralph 			while (*cp >= '0' && *cp <= '9')
31517463Sralph 				i = i * 10 + (*cp++ - '0');
31617463Sralph 			fdev = i;
31717463Sralph 			cp++;
31817463Sralph 			i = 0;
31917463Sralph 			while (*cp >= '0' && *cp <= '9')
32017463Sralph 				i = i * 10 + (*cp++ - '0');
32117463Sralph 			fino = i;
32217463Sralph 			continue;
32317463Sralph 
32412111Sralph 		case 'J':
32512111Sralph 			if (line[1] != '\0')
32615552Sralph 				strncpy(jobname, line+1, sizeof(jobname)-1);
32712111Sralph 			else
32812111Sralph 				strcpy(jobname, " ");
32912111Sralph 			continue;
33012111Sralph 
33112111Sralph 		case 'C':
33212111Sralph 			if (line[1] != '\0')
33315552Sralph 				strncpy(class, line+1, sizeof(class)-1);
33412111Sralph 			else if (class[0] == '\0')
33515811Sralph 				gethostname(class, sizeof(class));
33612111Sralph 			continue;
33712111Sralph 
33812111Sralph 		case 'T':	/* header title for pr */
33915552Sralph 			strncpy(title, line+1, sizeof(title)-1);
34012111Sralph 			continue;
34112111Sralph 
34212111Sralph 		case 'L':	/* identification line */
34318127Sralph 			if (!SH && !HL)
34412111Sralph 				banner(line+1, jobname);
34512111Sralph 			continue;
34612111Sralph 
34712111Sralph 		case '1':	/* troff fonts */
34812111Sralph 		case '2':
34912111Sralph 		case '3':
35012111Sralph 		case '4':
35112111Sralph 			if (line[1] != '\0')
35212111Sralph 				strcpy(fonts[line[0]-'1'], line+1);
35312111Sralph 			continue;
35412111Sralph 
35512111Sralph 		case 'W':	/* page width */
35615552Sralph 			strncpy(width+2, line+1, sizeof(width)-3);
35712111Sralph 			continue;
35812111Sralph 
35912581Sralph 		case 'I':	/* indent amount */
36015552Sralph 			strncpy(indent+2, line+1, sizeof(indent)-3);
36112581Sralph 			continue;
36212581Sralph 
36312111Sralph 		default:	/* some file to print */
36415811Sralph 			switch (i = print(line[0], line+1)) {
36517463Sralph 			case ERROR:
36617463Sralph 				if (bombed == OK)
36717463Sralph 					bombed = FATALERR;
36815811Sralph 				break;
36917463Sralph 			case REPRINT:
37012111Sralph 				(void) fclose(cfp);
37117463Sralph 				return(REPRINT);
37217463Sralph 			case FILTERERR:
37317463Sralph 			case ACCESS:
37417463Sralph 				bombed = i;
37515811Sralph 				sendmail(logname, bombed);
37615811Sralph 			}
37712111Sralph 			title[0] = '\0';
37812111Sralph 			continue;
37912111Sralph 
38012111Sralph 		case 'N':
38112111Sralph 		case 'U':
38212111Sralph 		case 'M':
38312111Sralph 			continue;
38412111Sralph 		}
38512111Sralph 
38612111Sralph 	/* pass 2 */
38712111Sralph 
38812463Sralph pass2:
38912111Sralph 	fseek(cfp, 0L, 0);
39012111Sralph 	while (getline(cfp))
39112111Sralph 		switch (line[0]) {
39218127Sralph 		case 'L':	/* identification line */
39318127Sralph 			if (!SH && HL)
39418127Sralph 				banner(line+1, jobname);
39518127Sralph 			continue;
39618127Sralph 
39712111Sralph 		case 'M':
39817463Sralph 			if (bombed < NOACCT)	/* already sent if >= NOACCT */
39915811Sralph 				sendmail(line+1, bombed);
40012111Sralph 			continue;
40112111Sralph 
40212111Sralph 		case 'U':
40312111Sralph 			(void) unlink(line+1);
40412111Sralph 		}
40512111Sralph 	/*
40615811Sralph 	 * clean-up in case another control file exists
40712111Sralph 	 */
40812111Sralph 	(void) fclose(cfp);
40912111Sralph 	(void) unlink(file);
41017463Sralph 	return(bombed == OK ? OK : ERROR);
41112111Sralph }
41212111Sralph 
41312111Sralph /*
41412111Sralph  * Print a file.
41513233Sralph  * Set up the chain [ PR [ | {IF, OF} ] ] or {IF, RF, TF, NF, DF, CF, VF}.
41615811Sralph  * Return -1 if a non-recoverable error occured,
41715811Sralph  * 2 if the filter detected some errors (but printed the job anyway),
41815811Sralph  * 1 if we should try to reprint this job and
41912111Sralph  * 0 if all is well.
42012111Sralph  * Note: all filters take stdin as the file, stdout as the printer,
42112111Sralph  * stderr as the log file, and must not ignore SIGINT.
42212111Sralph  */
42312111Sralph print(format, file)
42412111Sralph 	int format;
42512111Sralph 	char *file;
42612111Sralph {
42715811Sralph 	register int n;
42812111Sralph 	register char *prog;
42915811Sralph 	int fi, fo;
43012111Sralph 	char *av[15], buf[BUFSIZ];
43112111Sralph 	int pid, p[2], stopped = 0;
43212111Sralph 	union wait status;
43317463Sralph 	struct stat stb;
43412111Sralph 
43517463Sralph 	if (lstat(file, &stb) < 0 || (fi = open(file, O_RDONLY)) < 0)
43617463Sralph 		return(ERROR);
43717463Sralph 	/*
43817463Sralph 	 * Check to see if data file is a symbolic link. If so, it should
43917463Sralph 	 * still point to the same file or someone is trying to print
44017463Sralph 	 * something he shouldn't.
44117463Sralph 	 */
44217463Sralph 	if ((stb.st_mode & S_IFMT) == S_IFLNK && fstat(fi, &stb) == 0 &&
44317463Sralph 	    (stb.st_dev != fdev || stb.st_ino != fino))
44417463Sralph 		return(ACCESS);
44512111Sralph 	if (!SF && !tof) {		/* start on a fresh page */
44612111Sralph 		(void) write(ofd, FF, strlen(FF));
44712111Sralph 		tof = 1;
44812111Sralph 	}
44912111Sralph 	if (IF == NULL && (format == 'f' || format == 'l')) {
45012111Sralph 		tof = 0;
45112111Sralph 		while ((n = read(fi, buf, BUFSIZ)) > 0)
45212111Sralph 			if (write(ofd, buf, n) != n) {
45312111Sralph 				(void) close(fi);
45417463Sralph 				return(REPRINT);
45512111Sralph 			}
45612111Sralph 		(void) close(fi);
45717463Sralph 		return(OK);
45812111Sralph 	}
45912111Sralph 	switch (format) {
46012111Sralph 	case 'p':	/* print file using 'pr' */
46112111Sralph 		if (IF == NULL) {	/* use output filter */
46212111Sralph 			prog = PR;
46312111Sralph 			av[0] = "pr";
46412111Sralph 			av[1] = width;
46512111Sralph 			av[2] = length;
46612111Sralph 			av[3] = "-h";
46712111Sralph 			av[4] = *title ? title : " ";
46812111Sralph 			av[5] = 0;
46912111Sralph 			fo = ofd;
47012111Sralph 			goto start;
47112111Sralph 		}
47212111Sralph 		pipe(p);
47312111Sralph 		if ((prchild = dofork(DORETURN)) == 0) {	/* child */
47412111Sralph 			dup2(fi, 0);		/* file is stdin */
47512111Sralph 			dup2(p[1], 1);		/* pipe is stdout */
47612111Sralph 			for (n = 3; n < NOFILE; n++)
47712111Sralph 				(void) close(n);
47812111Sralph 			execl(PR, "pr", width, length, "-h", *title ? title : " ", 0);
47916762Sralph 			syslog(LOG_ERR, "cannot execl %s", PR);
48012111Sralph 			exit(2);
48112111Sralph 		}
48212111Sralph 		(void) close(p[1]);		/* close output side */
48312111Sralph 		(void) close(fi);
48412111Sralph 		if (prchild < 0) {
48512111Sralph 			prchild = 0;
48612111Sralph 			(void) close(p[0]);
48717463Sralph 			return(ERROR);
48812111Sralph 		}
48912111Sralph 		fi = p[0];			/* use pipe for input */
49012111Sralph 	case 'f':	/* print plain text file */
49112111Sralph 		prog = IF;
49212111Sralph 		av[1] = width;
49312111Sralph 		av[2] = length;
49412581Sralph 		av[3] = indent;
49512581Sralph 		n = 4;
49612111Sralph 		break;
49712111Sralph 	case 'l':	/* like 'f' but pass control characters */
49812111Sralph 		prog = IF;
49914325Sralph 		av[1] = "-c";
50012111Sralph 		av[2] = width;
50112111Sralph 		av[3] = length;
50212581Sralph 		av[4] = indent;
50312581Sralph 		n = 5;
50412111Sralph 		break;
50512463Sralph 	case 'r':	/* print a fortran text file */
50612463Sralph 		prog = RF;
50712463Sralph 		av[1] = width;
50812463Sralph 		av[2] = length;
50912463Sralph 		n = 3;
51012463Sralph 		break;
51112111Sralph 	case 't':	/* print troff output */
51213233Sralph 	case 'n':	/* print ditroff output */
51312463Sralph 	case 'd':	/* print tex output */
51412111Sralph 		(void) unlink(".railmag");
51512463Sralph 		if ((fo = creat(".railmag", FILMOD)) < 0) {
51616762Sralph 			syslog(LOG_ERR, "%s: cannot create .railmag", printer);
51712111Sralph 			(void) unlink(".railmag");
51812111Sralph 		} else {
51912111Sralph 			for (n = 0; n < 4; n++) {
52012111Sralph 				if (fonts[n][0] != '/')
52112111Sralph 					(void) write(fo, "/usr/lib/vfont/", 15);
52212111Sralph 				(void) write(fo, fonts[n], strlen(fonts[n]));
52312111Sralph 				(void) write(fo, "\n", 1);
52412111Sralph 			}
52512111Sralph 			(void) close(fo);
52612111Sralph 		}
52713233Sralph 		prog = (format == 't') ? TF : (format == 'n') ? NF : DF;
52812463Sralph 		av[1] = pxwidth;
52912463Sralph 		av[2] = pxlength;
53012463Sralph 		n = 3;
53112111Sralph 		break;
53212111Sralph 	case 'c':	/* print cifplot output */
53312111Sralph 		prog = CF;
53412463Sralph 		av[1] = pxwidth;
53512463Sralph 		av[2] = pxlength;
53612463Sralph 		n = 3;
53712111Sralph 		break;
53812111Sralph 	case 'g':	/* print plot(1G) output */
53912111Sralph 		prog = GF;
54012463Sralph 		av[1] = pxwidth;
54112463Sralph 		av[2] = pxlength;
54212463Sralph 		n = 3;
54312111Sralph 		break;
54412111Sralph 	case 'v':	/* print raster output */
54512111Sralph 		prog = VF;
54612463Sralph 		av[1] = pxwidth;
54712463Sralph 		av[2] = pxlength;
54812463Sralph 		n = 3;
54912111Sralph 		break;
55012111Sralph 	default:
55112111Sralph 		(void) close(fi);
55216762Sralph 		syslog(LOG_ERR, "%s: illegal format character '%c'",
55316762Sralph 			printer, format);
55417463Sralph 		return(ERROR);
55512111Sralph 	}
55612111Sralph 	if ((av[0] = rindex(prog, '/')) != NULL)
55712111Sralph 		av[0]++;
55812111Sralph 	else
55912111Sralph 		av[0] = prog;
56012111Sralph 	av[n++] = "-n";
56112111Sralph 	av[n++] = logname;
56212111Sralph 	av[n++] = "-h";
56314150Sralph 	av[n++] = fromhost;
56412111Sralph 	av[n++] = AF;
56512111Sralph 	av[n] = 0;
56612111Sralph 	fo = pfd;
56712111Sralph 	if (ofilter > 0) {		/* stop output filter */
56812111Sralph 		write(ofd, "\031\1", 2);
56912111Sralph 		while ((pid = wait3(&status, WUNTRACED, 0)) > 0 && pid != ofilter)
57012111Sralph 			;
57112111Sralph 		if (status.w_stopval != WSTOPPED) {
57212111Sralph 			(void) close(fi);
57316762Sralph 			syslog(LOG_WARNING, "%s: output filter died (%d)",
57416762Sralph 				printer, status.w_retcode);
57517463Sralph 			return(REPRINT);
57612111Sralph 		}
57712111Sralph 		stopped++;
57812111Sralph 	}
57912111Sralph start:
58012111Sralph 	if ((child = dofork(DORETURN)) == 0) {	/* child */
58112111Sralph 		dup2(fi, 0);
58212111Sralph 		dup2(fo, 1);
58317304Sralph 		n = open(tmpfile, O_WRONLY|O_CREAT|O_TRUNC, 0664);
58415811Sralph 		if (n >= 0)
58515811Sralph 			dup2(n, 2);
58612111Sralph 		for (n = 3; n < NOFILE; n++)
58712111Sralph 			(void) close(n);
58812111Sralph 		execv(prog, av);
58916762Sralph 		syslog(LOG_ERR, "cannot execv %s", prog);
59012111Sralph 		exit(2);
59112111Sralph 	}
59212111Sralph 	(void) close(fi);
59312111Sralph 	if (child < 0)
59412111Sralph 		status.w_retcode = 100;
59512111Sralph 	else
59612111Sralph 		while ((pid = wait(&status)) > 0 && pid != child)
59712111Sralph 			;
59812111Sralph 	child = 0;
59912111Sralph 	prchild = 0;
60012111Sralph 	if (stopped) {		/* restart output filter */
60112111Sralph 		if (kill(ofilter, SIGCONT) < 0) {
60216762Sralph 			syslog(LOG_ERR, "cannot restart output filter");
60312111Sralph 			exit(1);
60412111Sralph 		}
60512111Sralph 	}
60612111Sralph 	tof = 0;
60715811Sralph 	if (!WIFEXITED(status)) {
60816762Sralph 		syslog(LOG_WARNING, "%s: Daemon filter '%c' terminated (%d)",
60916762Sralph 			printer, format, status.w_termsig);
61017463Sralph 		return(ERROR);
61117463Sralph 	}
61217463Sralph 	switch (status.w_retcode) {
61317463Sralph 	case 0:
61417463Sralph 		tof = 1;
61517463Sralph 		return(OK);
61617463Sralph 	case 1:
61717463Sralph 		return(REPRINT);
61817463Sralph 	default:
61916762Sralph 		syslog(LOG_WARNING, "%s: Daemon filter '%c' exited (%d)",
62016762Sralph 			printer, format, status.w_retcode);
62117463Sralph 	case 2:
62217463Sralph 		return(ERROR);
62317463Sralph 	}
62412111Sralph }
62512111Sralph 
62612111Sralph /*
62712111Sralph  * Send the daemon control file (cf) and any data files.
62812111Sralph  * Return -1 if a non-recoverable error occured, 1 if a recoverable error and
62912111Sralph  * 0 if all is well.
63012111Sralph  */
63112111Sralph sendit(file)
63212111Sralph 	char *file;
63312111Sralph {
63417463Sralph 	register int i, err = OK;
63517463Sralph 	char *cp, last[BUFSIZ];
63612111Sralph 
63712111Sralph 	/*
63812111Sralph 	 * open control file
63912111Sralph 	 */
64016762Sralph 	if ((cfp = fopen(file, "r")) == NULL)
64117463Sralph 		return(OK);
64212111Sralph 	/*
64312111Sralph 	 *      read the control file for work to do
64412111Sralph 	 *
64512111Sralph 	 *      file format -- first character in the line is a command
64612111Sralph 	 *      rest of the line is the argument.
64712111Sralph 	 *      commands of interest are:
64812111Sralph 	 *
64912111Sralph 	 *            a-z -- "file name" name of file to print
65012111Sralph 	 *              U -- "unlink" name of file to remove
65112111Sralph 	 *                    (after we print it. (Pass 2 only)).
65212111Sralph 	 */
65312111Sralph 
65412111Sralph 	/*
65512111Sralph 	 * pass 1
65612111Sralph 	 */
65712111Sralph 	while (getline(cfp)) {
65812111Sralph 	again:
65917463Sralph 		if (line[0] == 'S') {
66017463Sralph 			cp = line+1;
66117463Sralph 			i = 0;
66217463Sralph 			while (*cp >= '0' && *cp <= '9')
66317463Sralph 				i = i * 10 + (*cp++ - '0');
66417463Sralph 			fdev = i;
66517463Sralph 			cp++;
66617463Sralph 			i = 0;
66717463Sralph 			while (*cp >= '0' && *cp <= '9')
66817463Sralph 				i = i * 10 + (*cp++ - '0');
66917463Sralph 			fino = i;
67017463Sralph 			continue;
67117463Sralph 		}
67212111Sralph 		if (line[0] >= 'a' && line[0] <= 'z') {
67312111Sralph 			strcpy(last, line);
67417463Sralph 			while (i = getline(cfp))
67512111Sralph 				if (strcmp(last, line))
67612111Sralph 					break;
67717463Sralph 			switch (sendfile('\3', last+1)) {
67817463Sralph 			case OK:
67917463Sralph 				if (i)
68017463Sralph 					goto again;
68117463Sralph 				break;
68217463Sralph 			case REPRINT:
68312111Sralph 				(void) fclose(cfp);
68417463Sralph 				return(REPRINT);
68517463Sralph 			case ACCESS:
68617463Sralph 				sendmail(logname, ACCESS);
68717463Sralph 			case ERROR:
68817463Sralph 				err = ERROR;
68917463Sralph 			}
69012111Sralph 			break;
69112111Sralph 		}
69212111Sralph 	}
69317463Sralph 	if (err == OK && sendfile('\2', file) > 0) {
69412111Sralph 		(void) fclose(cfp);
69517463Sralph 		return(REPRINT);
69612111Sralph 	}
69712111Sralph 	/*
69812111Sralph 	 * pass 2
69912111Sralph 	 */
70012111Sralph 	fseek(cfp, 0L, 0);
70112111Sralph 	while (getline(cfp))
70212111Sralph 		if (line[0] == 'U')
70312111Sralph 			(void) unlink(line+1);
70412111Sralph 	/*
70517463Sralph 	 * clean-up in case another control file exists
70612111Sralph 	 */
70712111Sralph 	(void) fclose(cfp);
70812111Sralph 	(void) unlink(file);
70917463Sralph 	return(err);
71012111Sralph }
71112111Sralph 
71212111Sralph /*
71312111Sralph  * Send a data file to the remote machine and spool it.
71412111Sralph  * Return positive if we should try resending.
71512111Sralph  */
71612111Sralph sendfile(type, file)
71712111Sralph 	char type, *file;
71812111Sralph {
71912111Sralph 	register int f, i, amt;
72012111Sralph 	struct stat stb;
72112111Sralph 	char buf[BUFSIZ];
72216762Sralph 	int sizerr, resp;
72312111Sralph 
72417463Sralph 	if (lstat(file, &stb) < 0 || (f = open(file, O_RDONLY)) < 0)
72517463Sralph 		return(ERROR);
72617463Sralph 	/*
72717463Sralph 	 * Check to see if data file is a symbolic link. If so, it should
72817463Sralph 	 * still point to the same file or someone is trying to print something
72917463Sralph 	 * he shouldn't.
73017463Sralph 	 */
73117463Sralph 	if ((stb.st_mode & S_IFMT) == S_IFLNK && fstat(f, &stb) == 0 &&
73217463Sralph 	    (stb.st_dev != fdev || stb.st_ino != fino))
73317463Sralph 		return(ACCESS);
73412111Sralph 	(void) sprintf(buf, "%c%d %s\n", type, stb.st_size, file);
73512111Sralph 	amt = strlen(buf);
73616762Sralph 	for (i = 0;  ; i++) {
73716762Sralph 		if (write(pfd, buf, amt) != amt ||
73816762Sralph 		    (resp = response()) < 0 || resp == '\1') {
73916762Sralph 			(void) close(f);
74017463Sralph 			return(REPRINT);
74116762Sralph 		} else if (resp == '\0')
74216762Sralph 			break;
74316762Sralph 		if (i == 0)
74416762Sralph 			status("no space on remote; waiting for queue to drain");
74516762Sralph 		if (i == 10)
74624861Seric 			syslog(LOG_ALERT, "%s: can't send to %s; queue full",
74716762Sralph 				printer, RM);
74816762Sralph 		sleep(5 * 60);
74912692Sralph 	}
75016762Sralph 	if (i)
75116762Sralph 		status("sending to %s", RM);
75212111Sralph 	sizerr = 0;
75312111Sralph 	for (i = 0; i < stb.st_size; i += BUFSIZ) {
75412111Sralph 		amt = BUFSIZ;
75512111Sralph 		if (i + amt > stb.st_size)
75612111Sralph 			amt = stb.st_size - i;
75712111Sralph 		if (sizerr == 0 && read(f, buf, amt) != amt)
75812111Sralph 			sizerr = 1;
75912692Sralph 		if (write(pfd, buf, amt) != amt) {
76012692Sralph 			(void) close(f);
76117463Sralph 			return(REPRINT);
76212692Sralph 		}
76312111Sralph 	}
76412111Sralph 	(void) close(f);
76512111Sralph 	if (sizerr) {
76616762Sralph 		syslog(LOG_INFO, "%s: %s: changed size", printer, file);
76717463Sralph 		/* tell recvjob to ignore this file */
76817463Sralph 		(void) write(pfd, "\1", 1);
76917463Sralph 		return(ERROR);
77017463Sralph 	}
77117463Sralph 	if (write(pfd, "", 1) != 1 || response())
77217463Sralph 		return(REPRINT);
77317463Sralph 	return(OK);
77412111Sralph }
77512111Sralph 
77612111Sralph /*
77712111Sralph  * Check to make sure there have been no errors and that both programs
77812111Sralph  * are in sync with eachother.
77912111Sralph  * Return non-zero if the connection was lost.
78012111Sralph  */
78116762Sralph response()
78212111Sralph {
78312111Sralph 	char resp;
78412111Sralph 
78516762Sralph 	if (read(pfd, &resp, 1) != 1) {
78616762Sralph 		syslog(LOG_INFO, "%s: lost connection", printer);
78716762Sralph 		return(-1);
78812111Sralph 	}
78916762Sralph 	return(resp);
79012111Sralph }
79112111Sralph 
79212111Sralph /*
79312111Sralph  * Banner printing stuff
79412111Sralph  */
79512111Sralph banner(name1, name2)
79612111Sralph 	char *name1, *name2;
79712111Sralph {
79812111Sralph 	time_t tvec;
79912111Sralph 	extern char *ctime();
80012111Sralph 
80112111Sralph 	time(&tvec);
80212111Sralph 	if (!SF && !tof)
80312111Sralph 		(void) write(ofd, FF, strlen(FF));
80412111Sralph 	if (SB) {	/* short banner only */
80512111Sralph 		if (class[0]) {
80612111Sralph 			(void) write(ofd, class, strlen(class));
80712111Sralph 			(void) write(ofd, ":", 1);
80812111Sralph 		}
80912111Sralph 		(void) write(ofd, name1, strlen(name1));
81012111Sralph 		(void) write(ofd, "  Job: ", 7);
81112111Sralph 		(void) write(ofd, name2, strlen(name2));
81212111Sralph 		(void) write(ofd, "  Date: ", 8);
81312111Sralph 		(void) write(ofd, ctime(&tvec), 24);
81412111Sralph 		(void) write(ofd, "\n", 1);
81512111Sralph 	} else {	/* normal banner */
81612111Sralph 		(void) write(ofd, "\n\n\n", 3);
81712111Sralph 		scan_out(ofd, name1, '\0');
81812111Sralph 		(void) write(ofd, "\n\n", 2);
81912111Sralph 		scan_out(ofd, name2, '\0');
82012111Sralph 		if (class[0]) {
82112111Sralph 			(void) write(ofd,"\n\n\n",3);
82212111Sralph 			scan_out(ofd, class, '\0');
82312111Sralph 		}
82412111Sralph 		(void) write(ofd, "\n\n\n\n\t\t\t\t\tJob:  ", 15);
82512111Sralph 		(void) write(ofd, name2, strlen(name2));
82612111Sralph 		(void) write(ofd, "\n\t\t\t\t\tDate: ", 12);
82712111Sralph 		(void) write(ofd, ctime(&tvec), 24);
82812111Sralph 		(void) write(ofd, "\n", 1);
82912111Sralph 	}
83012111Sralph 	if (!SF)
83112111Sralph 		(void) write(ofd, FF, strlen(FF));
83212111Sralph 	tof = 1;
83312111Sralph }
83412111Sralph 
83516762Sralph char *
83612111Sralph scnline(key, p, c)
83712111Sralph 	register char key, *p;
83812111Sralph 	char c;
83912111Sralph {
84012111Sralph 	register scnwidth;
84112111Sralph 
84212111Sralph 	for (scnwidth = WIDTH; --scnwidth;) {
84312111Sralph 		key <<= 1;
84412111Sralph 		*p++ = key & 0200 ? c : BACKGND;
84512111Sralph 	}
84612111Sralph 	return (p);
84712111Sralph }
84812111Sralph 
84912111Sralph #define TRC(q)	(((q)-' ')&0177)
85012111Sralph 
85112111Sralph scan_out(scfd, scsp, dlm)
85212111Sralph 	int scfd;
85312111Sralph 	char *scsp, dlm;
85412111Sralph {
85512111Sralph 	register char *strp;
85612111Sralph 	register nchrs, j;
85712111Sralph 	char outbuf[LINELEN+1], *sp, c, cc;
85812111Sralph 	int d, scnhgt;
85912111Sralph 	extern char scnkey[][HEIGHT];	/* in lpdchar.c */
86012111Sralph 
86112111Sralph 	for (scnhgt = 0; scnhgt++ < HEIGHT+DROP; ) {
86212111Sralph 		strp = &outbuf[0];
86312111Sralph 		sp = scsp;
86412111Sralph 		for (nchrs = 0; ; ) {
86512111Sralph 			d = dropit(c = TRC(cc = *sp++));
86612111Sralph 			if ((!d && scnhgt > HEIGHT) || (scnhgt <= DROP && d))
86712111Sralph 				for (j = WIDTH; --j;)
86812111Sralph 					*strp++ = BACKGND;
86912111Sralph 			else
87012111Sralph 				strp = scnline(scnkey[c][scnhgt-1-d], strp, cc);
87112111Sralph 			if (*sp == dlm || *sp == '\0' || nchrs++ >= PW/(WIDTH+1)-1)
87212111Sralph 				break;
87312111Sralph 			*strp++ = BACKGND;
87412111Sralph 			*strp++ = BACKGND;
87512111Sralph 		}
87612111Sralph 		while (*--strp == BACKGND && strp >= outbuf)
87712111Sralph 			;
87812111Sralph 		strp++;
87912111Sralph 		*strp++ = '\n';
88012111Sralph 		(void) write(scfd, outbuf, strp-outbuf);
88112111Sralph 	}
88212111Sralph }
88312111Sralph 
88412111Sralph dropit(c)
88512111Sralph 	char c;
88612111Sralph {
88712111Sralph 	switch(c) {
88812111Sralph 
88912111Sralph 	case TRC('_'):
89012111Sralph 	case TRC(';'):
89112111Sralph 	case TRC(','):
89212111Sralph 	case TRC('g'):
89312111Sralph 	case TRC('j'):
89412111Sralph 	case TRC('p'):
89512111Sralph 	case TRC('q'):
89612111Sralph 	case TRC('y'):
89712111Sralph 		return (DROP);
89812111Sralph 
89912111Sralph 	default:
90012111Sralph 		return (0);
90112111Sralph 	}
90212111Sralph }
90312111Sralph 
90412111Sralph /*
90512111Sralph  * sendmail ---
90612111Sralph  *   tell people about job completion
90712111Sralph  */
90815811Sralph sendmail(user, bombed)
90915811Sralph 	char *user;
91012111Sralph 	int bombed;
91112111Sralph {
91212111Sralph 	register int i;
91315811Sralph 	int p[2], s;
91412111Sralph 	register char *cp;
91512111Sralph 	char buf[100];
91615811Sralph 	struct stat stb;
91715811Sralph 	FILE *fp;
91812111Sralph 
91912111Sralph 	pipe(p);
92015811Sralph 	if ((s = dofork(DORETURN)) == 0) {		/* child */
92112111Sralph 		dup2(p[0], 0);
92212111Sralph 		for (i = 3; i < NOFILE; i++)
92312111Sralph 			(void) close(i);
92412111Sralph 		if ((cp = rindex(MAIL, '/')) != NULL)
92512111Sralph 			cp++;
92612111Sralph 		else
92712111Sralph 			cp = MAIL;
92815811Sralph 		sprintf(buf, "%s@%s", user, fromhost);
92912111Sralph 		execl(MAIL, cp, buf, 0);
93012111Sralph 		exit(0);
93115811Sralph 	} else if (s > 0) {				/* parent */
93212111Sralph 		dup2(p[1], 1);
93315811Sralph 		printf("To: %s@%s\n", user, fromhost);
93412111Sralph 		printf("Subject: printer job\n\n");
93512111Sralph 		printf("Your printer job ");
93612111Sralph 		if (*jobname)
93712111Sralph 			printf("(%s) ", jobname);
93812463Sralph 		switch (bombed) {
93917463Sralph 		case OK:
94012463Sralph 			printf("\ncompleted successfully\n");
94112463Sralph 			break;
94212463Sralph 		default:
94317463Sralph 		case FATALERR:
94412463Sralph 			printf("\ncould not be printed\n");
94512463Sralph 			break;
94617463Sralph 		case NOACCT:
94712463Sralph 			printf("\ncould not be printed without an account on %s\n", host);
94812463Sralph 			break;
94917463Sralph 		case FILTERERR:
95015811Sralph 			if (stat(tmpfile, &stb) < 0 || stb.st_size == 0 ||
95115811Sralph 			    (fp = fopen(tmpfile, "r")) == NULL) {
95215811Sralph 				printf("\nwas printed but had some errors\n");
95315811Sralph 				break;
95415811Sralph 			}
95515811Sralph 			printf("\nwas printed but had the following errors:\n");
95615811Sralph 			while ((i = getc(fp)) != EOF)
95715811Sralph 				putchar(i);
95815811Sralph 			(void) fclose(fp);
95917463Sralph 			break;
96017463Sralph 		case ACCESS:
96117463Sralph 			printf("\nwas not printed because it was not linked to the original file\n");
96212463Sralph 		}
96312111Sralph 		fflush(stdout);
96412111Sralph 		(void) close(1);
96512111Sralph 	}
96612111Sralph 	(void) close(p[0]);
96712111Sralph 	(void) close(p[1]);
96815811Sralph 	wait(&s);
96912111Sralph }
97012111Sralph 
97112111Sralph /*
97212111Sralph  * dofork - fork with retries on failure
97312111Sralph  */
97412111Sralph dofork(action)
97512111Sralph 	int action;
97612111Sralph {
97712111Sralph 	register int i, pid;
97812111Sralph 
97912111Sralph 	for (i = 0; i < 20; i++) {
98012463Sralph 		if ((pid = fork()) < 0) {
98112111Sralph 			sleep((unsigned)(i*i));
98212463Sralph 			continue;
98312463Sralph 		}
98412463Sralph 		/*
98512463Sralph 		 * Child should run as daemon instead of root
98612463Sralph 		 */
98712463Sralph 		if (pid == 0)
98812463Sralph 			setuid(DU);
98912463Sralph 		return(pid);
99012111Sralph 	}
99116762Sralph 	syslog(LOG_ERR, "can't fork");
99212111Sralph 
99312111Sralph 	switch (action) {
99412111Sralph 	case DORETURN:
99512111Sralph 		return (-1);
99612111Sralph 	default:
99716762Sralph 		syslog(LOG_ERR, "bad action (%d) to dofork", action);
99812111Sralph 		/*FALL THRU*/
99912111Sralph 	case DOABORT:
100012111Sralph 		exit(1);
100112111Sralph 	}
100212111Sralph 	/*NOTREACHED*/
100312111Sralph }
100412111Sralph 
100512111Sralph /*
100616762Sralph  * Kill child processes to abort current job.
100712111Sralph  */
100816762Sralph abortpr()
100912111Sralph {
101015811Sralph 	(void) unlink(tmpfile);
101112111Sralph 	kill(0, SIGINT);
101212111Sralph 	if (ofilter > 0)
101312111Sralph 		kill(ofilter, SIGCONT);
101412111Sralph 	while (wait(0) > 0)
101512111Sralph 		;
101612111Sralph 	exit(0);
101712111Sralph }
101812111Sralph 
101912111Sralph init()
102012111Sralph {
102112111Sralph 	int status;
102212111Sralph 
102325468Stef 	if ((status = pgetent(line, printer)) < 0) {
102425468Stef 		syslog(LOG_ERR, "can't open printer description file");
102525468Stef 		exit(1);
102625468Stef 	} else if (status == 0) {
102725468Stef 		syslog(LOG_ERR, "unknown printer: %s", printer);
102825468Stef 		exit(1);
102925468Stef 	}
103012111Sralph 	if ((LP = pgetstr("lp", &bp)) == NULL)
103112111Sralph 		LP = DEFDEVLP;
103212111Sralph 	if ((RP = pgetstr("rp", &bp)) == NULL)
103312463Sralph 		RP = DEFLP;
103412111Sralph 	if ((LO = pgetstr("lo", &bp)) == NULL)
103512111Sralph 		LO = DEFLOCK;
103612111Sralph 	if ((ST = pgetstr("st", &bp)) == NULL)
103712111Sralph 		ST = DEFSTAT;
103812111Sralph 	if ((LF = pgetstr("lf", &bp)) == NULL)
103912111Sralph 		LF = DEFLOGF;
104012111Sralph 	if ((SD = pgetstr("sd", &bp)) == NULL)
104112111Sralph 		SD = DEFSPOOL;
104212111Sralph 	if ((DU = pgetnum("du")) < 0)
104312111Sralph 		DU = DEFUID;
104412111Sralph 	if ((FF = pgetstr("ff", &bp)) == NULL)
104512111Sralph 		FF = DEFFF;
104612111Sralph 	if ((PW = pgetnum("pw")) < 0)
104712111Sralph 		PW = DEFWIDTH;
104812111Sralph 	sprintf(&width[2], "%d", PW);
104912111Sralph 	if ((PL = pgetnum("pl")) < 0)
105012111Sralph 		PL = DEFLENGTH;
105112111Sralph 	sprintf(&length[2], "%d", PL);
105212463Sralph 	if ((PX = pgetnum("px")) < 0)
105312463Sralph 		PX = 0;
105412463Sralph 	sprintf(&pxwidth[2], "%d", PX);
105512463Sralph 	if ((PY = pgetnum("py")) < 0)
105612463Sralph 		PY = 0;
105712463Sralph 	sprintf(&pxlength[2], "%d", PY);
105812111Sralph 	RM = pgetstr("rm", &bp);
105925468Stef 	/*
106025468Stef 	 * Figure out whether the local machine is the same as the remote
106125468Stef 	 * machine entry (if it exists).  If not, then ignore the local
106225468Stef 	 * queue information.
106325468Stef 	 */
106425468Stef 	 if (RM != (char *) NULL) {
106525468Stef 		char name[256];
106625468Stef 		struct hostent *hp;
106725468Stef 
106825468Stef 		/* get the standard network name of the local host */
106925468Stef 		gethostname(name, sizeof(name));
107025468Stef 		name[sizeof(name)-1] = '\0';
107125468Stef 		hp = gethostbyname(name);
107225468Stef 		if (hp == (struct hostent *) NULL) {
107325468Stef 		    syslog(LOG_ERR,
107425468Stef 			"unable to get network name for local machine %s",
107525468Stef 			name);
107625468Stef 		    goto localcheck_done;
107725468Stef 		} else strcpy(name, hp->h_name);
107825468Stef 
107925468Stef 		/* get the standard network name of RM */
108025468Stef 		hp = gethostbyname(RM);
108125468Stef 		if (hp == (struct hostent *) NULL) {
108225468Stef 		    syslog(LOG_ERR,
108325468Stef 			"unable to get hostname for remote machine %s", RM);
108425468Stef 		    goto localcheck_done;
108525468Stef 		}
108625468Stef 
108725468Stef 		/* if printer is not on local machine, ignore LP */
108825468Stef 		if (strcmp(name, hp->h_name) != 0) *LP = '\0';
108925468Stef 	}
109025468Stef localcheck_done:
109125468Stef 
109212111Sralph 	AF = pgetstr("af", &bp);
109312111Sralph 	OF = pgetstr("of", &bp);
109412111Sralph 	IF = pgetstr("if", &bp);
109512463Sralph 	RF = pgetstr("rf", &bp);
109612111Sralph 	TF = pgetstr("tf", &bp);
109713233Sralph 	NF = pgetstr("nf", &bp);
109812111Sralph 	DF = pgetstr("df", &bp);
109912111Sralph 	GF = pgetstr("gf", &bp);
110012111Sralph 	VF = pgetstr("vf", &bp);
110112111Sralph 	CF = pgetstr("cf", &bp);
110212111Sralph 	TR = pgetstr("tr", &bp);
110312463Sralph 	RS = pgetflag("rs");
110412111Sralph 	SF = pgetflag("sf");
110512111Sralph 	SH = pgetflag("sh");
110612111Sralph 	SB = pgetflag("sb");
110718127Sralph 	HL = pgetflag("hl");
110812111Sralph 	RW = pgetflag("rw");
110912111Sralph 	BR = pgetnum("br");
111012111Sralph 	if ((FC = pgetnum("fc")) < 0)
111112111Sralph 		FC = 0;
111212111Sralph 	if ((FS = pgetnum("fs")) < 0)
111312111Sralph 		FS = 0;
111412111Sralph 	if ((XC = pgetnum("xc")) < 0)
111512111Sralph 		XC = 0;
111612111Sralph 	if ((XS = pgetnum("xs")) < 0)
111712111Sralph 		XS = 0;
111812581Sralph 	tof = !pgetflag("fo");
111912111Sralph }
112012111Sralph 
112112463Sralph /*
112212463Sralph  * Acquire line printer or remote connection.
112312463Sralph  */
112412463Sralph openpr()
112512463Sralph {
112612463Sralph 	register int i, n;
112716762Sralph 	int resp;
112812463Sralph 
112912463Sralph 	if (*LP) {
113012463Sralph 		for (i = 1; ; i = i < 32 ? i << 1 : i) {
113113148Ssam 			pfd = open(LP, RW ? O_RDWR : O_WRONLY);
113212463Sralph 			if (pfd >= 0)
113312463Sralph 				break;
113412463Sralph 			if (errno == ENOENT) {
113516762Sralph 				syslog(LOG_ERR, "%s: %m", LP);
113612463Sralph 				exit(1);
113712463Sralph 			}
113812463Sralph 			if (i == 1)
113912463Sralph 				status("waiting for %s to become ready (offline ?)", printer);
114012463Sralph 			sleep(i);
114112463Sralph 		}
114212463Sralph 		if (isatty(pfd))
114312463Sralph 			setty();
114412463Sralph 		status("%s is ready and printing", printer);
114512463Sralph 	} else if (RM != NULL) {
114616762Sralph 		for (i = 1; ; i = i < 256 ? i << 1 : i) {
114716762Sralph 			resp = -1;
114812528Sralph 			pfd = getport(RM);
114912463Sralph 			if (pfd >= 0) {
115012463Sralph 				(void) sprintf(line, "\2%s\n", RP);
115112463Sralph 				n = strlen(line);
115216762Sralph 				if (write(pfd, line, n) == n &&
115316762Sralph 				    (resp = response()) == '\0')
115412463Sralph 					break;
115516031Sralph 				(void) close(pfd);
115612463Sralph 			}
115716031Sralph 			if (i == 1) {
115816762Sralph 				if (resp < 0)
115916031Sralph 					status("waiting for %s to come up", RM);
116016762Sralph 				else {
116116031Sralph 					status("waiting for queue to be enabled on %s", RM);
116216762Sralph 					i = 256;
116316762Sralph 				}
116416031Sralph 			}
116512463Sralph 			sleep(i);
116612463Sralph 		}
116712463Sralph 		status("sending to %s", RM);
116812463Sralph 		remote = 1;
116912463Sralph 	} else {
117016762Sralph 		syslog(LOG_ERR, "%s: no line printer device or host name",
117116762Sralph 			printer);
117212463Sralph 		exit(1);
117312463Sralph 	}
117412463Sralph 	/*
117512463Sralph 	 * Start up an output filter, if needed.
117612463Sralph 	 */
117712463Sralph 	if (OF) {
117812463Sralph 		int p[2];
117912463Sralph 		char *cp;
118012463Sralph 
118112463Sralph 		pipe(p);
118212463Sralph 		if ((ofilter = dofork(DOABORT)) == 0) {	/* child */
118312463Sralph 			dup2(p[0], 0);		/* pipe is std in */
118412463Sralph 			dup2(pfd, 1);		/* printer is std out */
118512463Sralph 			for (i = 3; i < NOFILE; i++)
118612463Sralph 				(void) close(i);
118712463Sralph 			if ((cp = rindex(OF, '/')) == NULL)
118812463Sralph 				cp = OF;
118912463Sralph 			else
119012463Sralph 				cp++;
119112463Sralph 			execl(OF, cp, width, length, 0);
119216762Sralph 			syslog(LOG_ERR, "%s: %s: %m", printer, OF);
119312463Sralph 			exit(1);
119412463Sralph 		}
119512463Sralph 		(void) close(p[0]);		/* close input side */
119612463Sralph 		ofd = p[1];			/* use pipe for output */
119712463Sralph 	} else {
119812463Sralph 		ofd = pfd;
119912463Sralph 		ofilter = 0;
120012463Sralph 	}
120112463Sralph }
120212463Sralph 
120312111Sralph struct bauds {
120412111Sralph 	int	baud;
120512111Sralph 	int	speed;
120612111Sralph } bauds[] = {
120712111Sralph 	50,	B50,
120812111Sralph 	75,	B75,
120912111Sralph 	110,	B110,
121012111Sralph 	134,	B134,
121112111Sralph 	150,	B150,
121212111Sralph 	200,	B200,
121312111Sralph 	300,	B300,
121412111Sralph 	600,	B600,
121512111Sralph 	1200,	B1200,
121612111Sralph 	1800,	B1800,
121712111Sralph 	2400,	B2400,
121812111Sralph 	4800,	B4800,
121912111Sralph 	9600,	B9600,
122012111Sralph 	19200,	EXTA,
122112111Sralph 	38400,	EXTB,
122212111Sralph 	0,	0
122312111Sralph };
122412111Sralph 
122512111Sralph /*
122612111Sralph  * setup tty lines.
122712111Sralph  */
122812111Sralph setty()
122912111Sralph {
123012111Sralph 	struct sgttyb ttybuf;
123112111Sralph 	register struct bauds *bp;
123212111Sralph 
123312111Sralph 	if (ioctl(pfd, TIOCEXCL, (char *)0) < 0) {
123416762Sralph 		syslog(LOG_ERR, "%s: ioctl(TIOCEXCL): %m", printer);
123512111Sralph 		exit(1);
123612111Sralph 	}
123712111Sralph 	if (ioctl(pfd, TIOCGETP, (char *)&ttybuf) < 0) {
123816762Sralph 		syslog(LOG_ERR, "%s: ioctl(TIOCGETP): %m", printer);
123912111Sralph 		exit(1);
124012111Sralph 	}
124112111Sralph 	if (BR > 0) {
124212111Sralph 		for (bp = bauds; bp->baud; bp++)
124312111Sralph 			if (BR == bp->baud)
124412111Sralph 				break;
124512111Sralph 		if (!bp->baud) {
124616762Sralph 			syslog(LOG_ERR, "%s: illegal baud rate %d", printer, BR);
124712111Sralph 			exit(1);
124812111Sralph 		}
124912111Sralph 		ttybuf.sg_ispeed = ttybuf.sg_ospeed = bp->speed;
125012111Sralph 	}
125113169Sralph 	ttybuf.sg_flags &= ~FC;
125213169Sralph 	ttybuf.sg_flags |= FS;
125312111Sralph 	if (ioctl(pfd, TIOCSETP, (char *)&ttybuf) < 0) {
125416762Sralph 		syslog(LOG_ERR, "%s: ioctl(TIOCSETP): %m", printer);
125512111Sralph 		exit(1);
125612111Sralph 	}
125717168Sralph 	if (XC || XS) {
125817168Sralph 		int ldisc = NTTYDISC;
125917168Sralph 
126017168Sralph 		if (ioctl(pfd, TIOCSETD, &ldisc) < 0) {
126117168Sralph 			syslog(LOG_ERR, "%s: ioctl(TIOCSETD): %m", printer);
126217168Sralph 			exit(1);
126317168Sralph 		}
126417168Sralph 	}
126512111Sralph 	if (XC) {
126612111Sralph 		if (ioctl(pfd, TIOCLBIC, &XC) < 0) {
126716762Sralph 			syslog(LOG_ERR, "%s: ioctl(TIOCLBIC): %m", printer);
126812111Sralph 			exit(1);
126912111Sralph 		}
127012111Sralph 	}
127112111Sralph 	if (XS) {
127212111Sralph 		if (ioctl(pfd, TIOCLBIS, &XS) < 0) {
127316762Sralph 			syslog(LOG_ERR, "%s: ioctl(TIOCLBIS): %m", printer);
127412111Sralph 			exit(1);
127512111Sralph 		}
127612111Sralph 	}
127712111Sralph }
127812463Sralph 
127912463Sralph /*VARARGS1*/
128012463Sralph status(msg, a1, a2, a3)
128112463Sralph 	char *msg;
128212463Sralph {
128312463Sralph 	register int fd;
128412463Sralph 	char buf[BUFSIZ];
128512463Sralph 
128612463Sralph 	umask(0);
128713148Ssam 	fd = open(ST, O_WRONLY|O_CREAT, 0664);
128816762Sralph 	if (fd < 0 || flock(fd, LOCK_EX) < 0) {
128916762Sralph 		syslog(LOG_ERR, "%s: %s: %m", printer, ST);
129016762Sralph 		exit(1);
129116762Sralph 	}
129213148Ssam 	ftruncate(fd, 0);
129312463Sralph 	sprintf(buf, msg, a1, a2, a3);
129412463Sralph 	strcat(buf, "\n");
129512463Sralph 	(void) write(fd, buf, strlen(buf));
129612463Sralph 	(void) close(fd);
129712463Sralph }
1298