xref: /csrg-svn/usr.sbin/lpr/lpd/printjob.c (revision 68972)
122437Sdist /*
261845Sbostic  * Copyright (c) 1983, 1993
361845Sbostic  *	The Regents of the University of California.  All rights reserved.
434203Sbostic  *
556123Selan  *
656251Selan  * %sccs.include.redist.c%
722437Sdist  */
822437Sdist 
913954Ssam #ifndef lint
1061845Sbostic static char copyright[] =
1161845Sbostic "@(#) Copyright (c) 1983, 1993\n\
1261845Sbostic 	The Regents of the University of California.  All rights reserved.\n";
1334203Sbostic #endif /* not lint */
1413954Ssam 
1556251Selan #ifndef lint
16*68972Stef static char sccsid[] = "@(#)printjob.c	8.3 (Berkeley) 04/27/95";
1756251Selan #endif /* not lint */
1856251Selan 
1956251Selan 
2012111Sralph /*
2112111Sralph  * printjob -- print jobs in the queue.
2212111Sralph  *
2312111Sralph  *	NOTE: the lock file is used to pass information to lpq and lprm.
2412111Sralph  *	it does not need to be removed because file locks are dynamic.
2512111Sralph  */
2612111Sralph 
2755474Sbostic #include <sys/param.h>
2855474Sbostic #include <sys/wait.h>
2955474Sbostic #include <sys/stat.h>
3056123Selan #include <sys/types.h>
3155474Sbostic 
3256123Selan #include <pwd.h>
3356123Selan #include <unistd.h>
3455474Sbostic #include <signal.h>
3555474Sbostic #include <sgtty.h>
3655474Sbostic #include <syslog.h>
3755474Sbostic #include <fcntl.h>
3855474Sbostic #include <dirent.h>
3955474Sbostic #include <errno.h>
4055474Sbostic #include <stdio.h>
4155474Sbostic #include <string.h>
4256123Selan #include <stdlib.h>
4312111Sralph #include "lp.h"
4455474Sbostic #include "lp.local.h"
4537968Sbostic #include "pathnames.h"
4655474Sbostic #include "extern.h"
4712111Sralph 
4816762Sralph #define DORETURN	0	/* absorb fork error */
4916762Sralph #define DOABORT		1	/* abort if dofork fails */
5012111Sralph 
5117463Sralph /*
5217463Sralph  * Error tokens
5317463Sralph  */
5417463Sralph #define REPRINT		-2
5517463Sralph #define ERROR		-1
5617463Sralph #define	OK		0
5717463Sralph #define	FATALERR	1
5817463Sralph #define	NOACCT		2
5917463Sralph #define	FILTERERR	3
6017463Sralph #define	ACCESS		4
6117463Sralph 
6256123Selan static dev_t	 fdev;		/* device of file pointed to by symlink */
6356123Selan static ino_t	 fino;		/* inode of file pointed to by symlink */
6456123Selan static FILE	*cfp;		/* control file */
6556123Selan static int	 child;		/* id of any filters */
6656123Selan static int	 lfd;		/* lock file descriptor */
6756123Selan static int	 ofd;		/* output filter file descriptor */
6856123Selan static int	 ofilter;	/* id of output filter, if any */
6956123Selan static int	 pfd;		/* prstatic inter file descriptor */
7056123Selan static int	 pid;		/* pid of lpd process */
7156123Selan static int	 prchild;	/* id of pr process */
7256123Selan static int	 remote;	/* true if sending files to remote */
7356123Selan static char	 title[80];	/* ``pr'' title */
7456123Selan static int	 tof;		/* true if at top of form */
7512111Sralph 
7656123Selan static char	class[32];		/* classification field */
7756123Selan static char	fromhost[32];		/* user's host machine */
7856123Selan 				/* indentation size in static characters */
7956123Selan static char	indent[10] = "-i0";
8056123Selan static char	jobname[100];		/* job or file name */
8156123Selan static char	length[10] = "-l";	/* page length in lines */
8256123Selan static char	logname[32];		/* user's login name */
8356123Selan static char	pxlength[10] = "-y";	/* page length in pixels */
8456123Selan static char	pxwidth[10] = "-x";	/* page width in pixels */
8556123Selan static char	tempfile[] = "errsXXXXXX"; /* file name for filter output */
8656123Selan static char	width[10] = "-w";	/* page width in static characters */
8712111Sralph 
8855474Sbostic static void       abortpr __P((int));
8955474Sbostic static void       banner __P((char *, char *));
9055474Sbostic static int        dofork __P((int));
9155474Sbostic static int        dropit __P((int));
9255474Sbostic static void       init __P((void));
9355474Sbostic static void       openpr __P((void));
9455474Sbostic static int        print __P((int, char *));
9555474Sbostic static int        printit __P((char *));
9655474Sbostic static void       pstatus __P((const char *, ...));
9755474Sbostic static char       response __P((void));
9855474Sbostic static void       scan_out __P((int, char *, int));
9955474Sbostic static char      *scnline __P((int, char *, int));
10055474Sbostic static int        sendfile __P((int, char *));
10155474Sbostic static int        sendit __P((char *));
10255474Sbostic static void       sendmail __P((char *, int));
10355474Sbostic static void       setty __P((void));
10455474Sbostic 
10555474Sbostic void
10612111Sralph printjob()
10712111Sralph {
10812111Sralph 	struct stat stb;
10912111Sralph 	register struct queue *q, **qp;
11012111Sralph 	struct queue **queue;
11112111Sralph 	register int i, nitems;
112*68972Stef 	off_t pidoff;
11316762Sralph 	int count = 0;
11412111Sralph 
11512111Sralph 	init();					/* set up capabilities */
11613442Sralph 	(void) write(1, "", 1);			/* ack that daemon is started */
11725496Seric 	(void) close(2);			/* set up log file */
11825496Seric 	if (open(LF, O_WRONLY|O_APPEND, 0664) < 0) {
11925496Seric 		syslog(LOG_ERR, "%s: %m", LF);
12037968Sbostic 		(void) open(_PATH_DEVNULL, O_WRONLY);
12125496Seric 	}
12216762Sralph 	setgid(getegid());
12312463Sralph 	pid = getpid();				/* for use with lprm */
12412111Sralph 	setpgrp(0, pid);
12516762Sralph 	signal(SIGHUP, abortpr);
12616762Sralph 	signal(SIGINT, abortpr);
12716762Sralph 	signal(SIGQUIT, abortpr);
12816762Sralph 	signal(SIGTERM, abortpr);
12912111Sralph 
13039954Smckusick 	(void) mktemp(tempfile);
13115811Sralph 
13212111Sralph 	/*
13312111Sralph 	 * uses short form file names
13412111Sralph 	 */
13512111Sralph 	if (chdir(SD) < 0) {
13616762Sralph 		syslog(LOG_ERR, "%s: %m", SD);
13712111Sralph 		exit(1);
13812111Sralph 	}
13912463Sralph 	if (stat(LO, &stb) == 0 && (stb.st_mode & 0100))
14012463Sralph 		exit(0);		/* printing disabled */
14114150Sralph 	lfd = open(LO, O_WRONLY|O_CREAT, 0644);
14213169Sralph 	if (lfd < 0) {
14316762Sralph 		syslog(LOG_ERR, "%s: %s: %m", printer, LO);
14413169Sralph 		exit(1);
14513169Sralph 	}
14613169Sralph 	if (flock(lfd, LOCK_EX|LOCK_NB) < 0) {
14712111Sralph 		if (errno == EWOULDBLOCK)	/* active deamon present */
14812111Sralph 			exit(0);
14916762Sralph 		syslog(LOG_ERR, "%s: %s: %m", printer, LO);
15012111Sralph 		exit(1);
15112111Sralph 	}
15213148Ssam 	ftruncate(lfd, 0);
15312111Sralph 	/*
15412111Sralph 	 * write process id for others to know
15512111Sralph 	 */
15612111Sralph 	sprintf(line, "%u\n", pid);
15712111Sralph 	pidoff = i = strlen(line);
15812463Sralph 	if (write(lfd, line, i) != i) {
15916762Sralph 		syslog(LOG_ERR, "%s: %s: %m", printer, LO);
16012111Sralph 		exit(1);
16112111Sralph 	}
16212111Sralph 	/*
16312111Sralph 	 * search the spool directory for work and sort by queue order.
16412111Sralph 	 */
16512111Sralph 	if ((nitems = getq(&queue)) < 0) {
16616762Sralph 		syslog(LOG_ERR, "%s: can't scan %s", printer, SD);
16712111Sralph 		exit(1);
16812111Sralph 	}
16912463Sralph 	if (nitems == 0)		/* no work to do */
17012111Sralph 		exit(0);
17113169Sralph 	if (stb.st_mode & 01) {		/* reset queue flag */
17213169Sralph 		if (fchmod(lfd, stb.st_mode & 0776) < 0)
17316762Sralph 			syslog(LOG_ERR, "%s: %s: %m", printer, LO);
17413169Sralph 	}
17512463Sralph 	openpr();			/* open printer or remote */
17612463Sralph again:
17712111Sralph 	/*
17812111Sralph 	 * we found something to do now do it --
17912111Sralph 	 *    write the name of the current control file into the lock file
18012111Sralph 	 *    so the spool queue program can tell what we're working on
18112111Sralph 	 */
18212111Sralph 	for (qp = queue; nitems--; free((char *) q)) {
18312111Sralph 		q = *qp++;
18412111Sralph 		if (stat(q->q_name, &stb) < 0)
18512111Sralph 			continue;
18612463Sralph 	restart:
187*68972Stef 		(void) lseek(lfd, pidoff, 0);
18812111Sralph 		(void) sprintf(line, "%s\n", q->q_name);
18912111Sralph 		i = strlen(line);
19012111Sralph 		if (write(lfd, line, i) != i)
19116762Sralph 			syslog(LOG_ERR, "%s: %s: %m", printer, LO);
19212111Sralph 		if (!remote)
19312111Sralph 			i = printit(q->q_name);
19412111Sralph 		else
19512111Sralph 			i = sendit(q->q_name);
19612463Sralph 		/*
19713169Sralph 		 * Check to see if we are supposed to stop printing or
19813169Sralph 		 * if we are to rebuild the queue.
19912463Sralph 		 */
20013169Sralph 		if (fstat(lfd, &stb) == 0) {
20116762Sralph 			/* stop printing before starting next job? */
20213169Sralph 			if (stb.st_mode & 0100)
20313169Sralph 				goto done;
20416762Sralph 			/* rebuild queue (after lpc topq) */
20513169Sralph 			if (stb.st_mode & 01) {
20613169Sralph 				for (free((char *) q); nitems--; free((char *) q))
20713169Sralph 					q = *qp++;
20813169Sralph 				if (fchmod(lfd, stb.st_mode & 0776) < 0)
20916762Sralph 					syslog(LOG_WARNING, "%s: %s: %m",
21016762Sralph 						printer, LO);
21113169Sralph 				break;
21213169Sralph 			}
21313169Sralph 		}
21417463Sralph 		if (i == OK)		/* file ok and printed */
21514150Sralph 			count++;
21617463Sralph 		else if (i == REPRINT) { /* try reprinting the job */
21716762Sralph 			syslog(LOG_INFO, "restarting %s", printer);
21812111Sralph 			if (ofilter > 0) {
21912111Sralph 				kill(ofilter, SIGCONT);	/* to be sure */
22012111Sralph 				(void) close(ofd);
22112111Sralph 				while ((i = wait(0)) > 0 && i != ofilter)
22212111Sralph 					;
22312111Sralph 				ofilter = 0;
22412111Sralph 			}
22512463Sralph 			(void) close(pfd);	/* close printer */
22615811Sralph 			if (ftruncate(lfd, pidoff) < 0)
22716762Sralph 				syslog(LOG_WARNING, "%s: %s: %m", printer, LO);
22812463Sralph 			openpr();		/* try to reopen printer */
22912111Sralph 			goto restart;
23012111Sralph 		}
23112111Sralph 	}
23212111Sralph 	free((char *) queue);
23312463Sralph 	/*
23412463Sralph 	 * search the spool directory for more work.
23512463Sralph 	 */
23612463Sralph 	if ((nitems = getq(&queue)) < 0) {
23716762Sralph 		syslog(LOG_ERR, "%s: can't scan %s", printer, SD);
23812463Sralph 		exit(1);
23912463Sralph 	}
24012463Sralph 	if (nitems == 0) {		/* no more work to do */
24112463Sralph 	done:
24214150Sralph 		if (count > 0) {	/* Files actually printed */
24314150Sralph 			if (!SF && !tof)
24414150Sralph 				(void) write(ofd, FF, strlen(FF));
24514150Sralph 			if (TR != NULL)		/* output trailer */
24614150Sralph 				(void) write(ofd, TR, strlen(TR));
24714150Sralph 		}
24839954Smckusick 		(void) unlink(tempfile);
24912463Sralph 		exit(0);
25012463Sralph 	}
25112111Sralph 	goto again;
25212111Sralph }
25312111Sralph 
25412111Sralph char	fonts[4][50];	/* fonts for troff */
25512111Sralph 
25637968Sbostic char ifonts[4][40] = {
25737968Sbostic 	_PATH_VFONTR,
25837968Sbostic 	_PATH_VFONTI,
25937968Sbostic 	_PATH_VFONTB,
26037968Sbostic 	_PATH_VFONTS,
26112111Sralph };
26212111Sralph 
26312111Sralph /*
26412111Sralph  * The remaining part is the reading of the control file (cf)
26512111Sralph  * and performing the various actions.
26612111Sralph  */
26755474Sbostic static int
26812111Sralph printit(file)
26912111Sralph 	char *file;
27012111Sralph {
27112111Sralph 	register int i;
27217463Sralph 	char *cp;
27317463Sralph 	int bombed = OK;
27412111Sralph 
27512111Sralph 	/*
27617463Sralph 	 * open control file; ignore if no longer there.
27712111Sralph 	 */
27812111Sralph 	if ((cfp = fopen(file, "r")) == NULL) {
27916762Sralph 		syslog(LOG_INFO, "%s: %s: %m", printer, file);
28017463Sralph 		return(OK);
28112111Sralph 	}
28212111Sralph 	/*
28312111Sralph 	 * Reset troff fonts.
28412111Sralph 	 */
28512111Sralph 	for (i = 0; i < 4; i++)
28612111Sralph 		strcpy(fonts[i], ifonts[i]);
28766833Sbostic 	sprintf(&width[2], "%d", PW);
28817302Sralph 	strcpy(indent+2, "0");
28912111Sralph 
29012111Sralph 	/*
29112111Sralph 	 *      read the control file for work to do
29212111Sralph 	 *
29312111Sralph 	 *      file format -- first character in the line is a command
29412111Sralph 	 *      rest of the line is the argument.
29512111Sralph 	 *      valid commands are:
29612111Sralph 	 *
29717463Sralph 	 *		S -- "stat info" for symbolic link protection
29812111Sralph 	 *		J -- "job name" on banner page
29912111Sralph 	 *		C -- "class name" on banner page
30012111Sralph 	 *              L -- "literal" user's name to print on banner
30112111Sralph 	 *		T -- "title" for pr
30212111Sralph 	 *		H -- "host name" of machine where lpr was done
30312111Sralph 	 *              P -- "person" user's login name
30412581Sralph 	 *              I -- "indent" amount to indent output
30512111Sralph 	 *              f -- "file name" name of text file to print
30612111Sralph 	 *		l -- "file name" text file with control chars
30712111Sralph 	 *		p -- "file name" text file to print with pr(1)
30812111Sralph 	 *		t -- "file name" troff(1) file to print
30913233Sralph 	 *		n -- "file name" ditroff(1) file to print
31012111Sralph 	 *		d -- "file name" dvi file to print
31112111Sralph 	 *		g -- "file name" plot(1G) file to print
31212111Sralph 	 *		v -- "file name" plain raster file to print
31312111Sralph 	 *		c -- "file name" cifplot file to print
31412111Sralph 	 *		1 -- "R font file" for troff
31512111Sralph 	 *		2 -- "I font file" for troff
31612111Sralph 	 *		3 -- "B font file" for troff
31712111Sralph 	 *		4 -- "S font file" for troff
31812111Sralph 	 *		N -- "name" of file (used by lpq)
31912111Sralph 	 *              U -- "unlink" name of file to remove
32012111Sralph 	 *                    (after we print it. (Pass 2 only)).
32112111Sralph 	 *		M -- "mail" to user when done printing
32212111Sralph 	 *
32312111Sralph 	 *      getline reads a line and expands tabs to blanks
32412111Sralph 	 */
32512111Sralph 
32612111Sralph 	/* pass 1 */
32712111Sralph 
32812111Sralph 	while (getline(cfp))
32912111Sralph 		switch (line[0]) {
33012111Sralph 		case 'H':
33114150Sralph 			strcpy(fromhost, line+1);
33212111Sralph 			if (class[0] == '\0')
33315552Sralph 				strncpy(class, line+1, sizeof(class)-1);
33412111Sralph 			continue;
33512111Sralph 
33612111Sralph 		case 'P':
33715552Sralph 			strncpy(logname, line+1, sizeof(logname)-1);
33812463Sralph 			if (RS) {			/* restricted */
33955474Sbostic 				if (getpwnam(logname) == NULL) {
34017463Sralph 					bombed = NOACCT;
34115811Sralph 					sendmail(line+1, bombed);
34212463Sralph 					goto pass2;
34312463Sralph 				}
34412463Sralph 			}
34512111Sralph 			continue;
34612111Sralph 
34717463Sralph 		case 'S':
34817463Sralph 			cp = line+1;
34917463Sralph 			i = 0;
35017463Sralph 			while (*cp >= '0' && *cp <= '9')
35117463Sralph 				i = i * 10 + (*cp++ - '0');
35217463Sralph 			fdev = i;
35317463Sralph 			cp++;
35417463Sralph 			i = 0;
35517463Sralph 			while (*cp >= '0' && *cp <= '9')
35617463Sralph 				i = i * 10 + (*cp++ - '0');
35717463Sralph 			fino = i;
35817463Sralph 			continue;
35917463Sralph 
36012111Sralph 		case 'J':
36112111Sralph 			if (line[1] != '\0')
36215552Sralph 				strncpy(jobname, line+1, sizeof(jobname)-1);
36312111Sralph 			else
36412111Sralph 				strcpy(jobname, " ");
36512111Sralph 			continue;
36612111Sralph 
36712111Sralph 		case 'C':
36812111Sralph 			if (line[1] != '\0')
36915552Sralph 				strncpy(class, line+1, sizeof(class)-1);
37012111Sralph 			else if (class[0] == '\0')
37115811Sralph 				gethostname(class, sizeof(class));
37212111Sralph 			continue;
37312111Sralph 
37412111Sralph 		case 'T':	/* header title for pr */
37515552Sralph 			strncpy(title, line+1, sizeof(title)-1);
37612111Sralph 			continue;
37712111Sralph 
37812111Sralph 		case 'L':	/* identification line */
37918127Sralph 			if (!SH && !HL)
38012111Sralph 				banner(line+1, jobname);
38112111Sralph 			continue;
38212111Sralph 
38312111Sralph 		case '1':	/* troff fonts */
38412111Sralph 		case '2':
38512111Sralph 		case '3':
38612111Sralph 		case '4':
38712111Sralph 			if (line[1] != '\0')
38812111Sralph 				strcpy(fonts[line[0]-'1'], line+1);
38912111Sralph 			continue;
39012111Sralph 
39112111Sralph 		case 'W':	/* page width */
39215552Sralph 			strncpy(width+2, line+1, sizeof(width)-3);
39312111Sralph 			continue;
39412111Sralph 
39512581Sralph 		case 'I':	/* indent amount */
39615552Sralph 			strncpy(indent+2, line+1, sizeof(indent)-3);
39712581Sralph 			continue;
39812581Sralph 
39912111Sralph 		default:	/* some file to print */
40015811Sralph 			switch (i = print(line[0], line+1)) {
40117463Sralph 			case ERROR:
40217463Sralph 				if (bombed == OK)
40317463Sralph 					bombed = FATALERR;
40415811Sralph 				break;
40517463Sralph 			case REPRINT:
40612111Sralph 				(void) fclose(cfp);
40717463Sralph 				return(REPRINT);
40817463Sralph 			case FILTERERR:
40917463Sralph 			case ACCESS:
41017463Sralph 				bombed = i;
41115811Sralph 				sendmail(logname, bombed);
41215811Sralph 			}
41312111Sralph 			title[0] = '\0';
41412111Sralph 			continue;
41512111Sralph 
41612111Sralph 		case 'N':
41712111Sralph 		case 'U':
41812111Sralph 		case 'M':
41912111Sralph 			continue;
42012111Sralph 		}
42112111Sralph 
42212111Sralph 	/* pass 2 */
42312111Sralph 
42412463Sralph pass2:
42512111Sralph 	fseek(cfp, 0L, 0);
42612111Sralph 	while (getline(cfp))
42712111Sralph 		switch (line[0]) {
42818127Sralph 		case 'L':	/* identification line */
42918127Sralph 			if (!SH && HL)
43018127Sralph 				banner(line+1, jobname);
43118127Sralph 			continue;
43218127Sralph 
43312111Sralph 		case 'M':
43417463Sralph 			if (bombed < NOACCT)	/* already sent if >= NOACCT */
43515811Sralph 				sendmail(line+1, bombed);
43612111Sralph 			continue;
43712111Sralph 
43812111Sralph 		case 'U':
43912111Sralph 			(void) unlink(line+1);
44012111Sralph 		}
44112111Sralph 	/*
44215811Sralph 	 * clean-up in case another control file exists
44312111Sralph 	 */
44412111Sralph 	(void) fclose(cfp);
44512111Sralph 	(void) unlink(file);
44617463Sralph 	return(bombed == OK ? OK : ERROR);
44712111Sralph }
44812111Sralph 
44912111Sralph /*
45012111Sralph  * Print a file.
45113233Sralph  * Set up the chain [ PR [ | {IF, OF} ] ] or {IF, RF, TF, NF, DF, CF, VF}.
45215811Sralph  * Return -1 if a non-recoverable error occured,
45315811Sralph  * 2 if the filter detected some errors (but printed the job anyway),
45415811Sralph  * 1 if we should try to reprint this job and
45512111Sralph  * 0 if all is well.
45612111Sralph  * Note: all filters take stdin as the file, stdout as the printer,
45712111Sralph  * stderr as the log file, and must not ignore SIGINT.
45812111Sralph  */
45955474Sbostic static int
46012111Sralph print(format, file)
46112111Sralph 	int format;
46212111Sralph 	char *file;
46312111Sralph {
46415811Sralph 	register int n;
46512111Sralph 	register char *prog;
46615811Sralph 	int fi, fo;
46739954Smckusick 	FILE *fp;
46812111Sralph 	char *av[15], buf[BUFSIZ];
46912111Sralph 	int pid, p[2], stopped = 0;
47012111Sralph 	union wait status;
47117463Sralph 	struct stat stb;
47212111Sralph 
47317463Sralph 	if (lstat(file, &stb) < 0 || (fi = open(file, O_RDONLY)) < 0)
47417463Sralph 		return(ERROR);
47517463Sralph 	/*
47617463Sralph 	 * Check to see if data file is a symbolic link. If so, it should
47717463Sralph 	 * still point to the same file or someone is trying to print
47817463Sralph 	 * something he shouldn't.
47917463Sralph 	 */
48017463Sralph 	if ((stb.st_mode & S_IFMT) == S_IFLNK && fstat(fi, &stb) == 0 &&
48117463Sralph 	    (stb.st_dev != fdev || stb.st_ino != fino))
48217463Sralph 		return(ACCESS);
48312111Sralph 	if (!SF && !tof) {		/* start on a fresh page */
48412111Sralph 		(void) write(ofd, FF, strlen(FF));
48512111Sralph 		tof = 1;
48612111Sralph 	}
48712111Sralph 	if (IF == NULL && (format == 'f' || format == 'l')) {
48812111Sralph 		tof = 0;
48912111Sralph 		while ((n = read(fi, buf, BUFSIZ)) > 0)
49012111Sralph 			if (write(ofd, buf, n) != n) {
49112111Sralph 				(void) close(fi);
49217463Sralph 				return(REPRINT);
49312111Sralph 			}
49412111Sralph 		(void) close(fi);
49517463Sralph 		return(OK);
49612111Sralph 	}
49712111Sralph 	switch (format) {
49812111Sralph 	case 'p':	/* print file using 'pr' */
49912111Sralph 		if (IF == NULL) {	/* use output filter */
50037968Sbostic 			prog = _PATH_PR;
50112111Sralph 			av[0] = "pr";
50212111Sralph 			av[1] = width;
50312111Sralph 			av[2] = length;
50412111Sralph 			av[3] = "-h";
50512111Sralph 			av[4] = *title ? title : " ";
50612111Sralph 			av[5] = 0;
50712111Sralph 			fo = ofd;
50812111Sralph 			goto start;
50912111Sralph 		}
51012111Sralph 		pipe(p);
51112111Sralph 		if ((prchild = dofork(DORETURN)) == 0) {	/* child */
51212111Sralph 			dup2(fi, 0);		/* file is stdin */
51312111Sralph 			dup2(p[1], 1);		/* pipe is stdout */
514*68972Stef 			closelog();
51512111Sralph 			for (n = 3; n < NOFILE; n++)
51612111Sralph 				(void) close(n);
51737968Sbostic 			execl(_PATH_PR, "pr", width, length,
51837968Sbostic 			    "-h", *title ? title : " ", 0);
51937968Sbostic 			syslog(LOG_ERR, "cannot execl %s", _PATH_PR);
52012111Sralph 			exit(2);
52112111Sralph 		}
52212111Sralph 		(void) close(p[1]);		/* close output side */
52312111Sralph 		(void) close(fi);
52412111Sralph 		if (prchild < 0) {
52512111Sralph 			prchild = 0;
52612111Sralph 			(void) close(p[0]);
52717463Sralph 			return(ERROR);
52812111Sralph 		}
52912111Sralph 		fi = p[0];			/* use pipe for input */
53012111Sralph 	case 'f':	/* print plain text file */
53112111Sralph 		prog = IF;
53212111Sralph 		av[1] = width;
53312111Sralph 		av[2] = length;
53412581Sralph 		av[3] = indent;
53512581Sralph 		n = 4;
53612111Sralph 		break;
53712111Sralph 	case 'l':	/* like 'f' but pass control characters */
53812111Sralph 		prog = IF;
53914325Sralph 		av[1] = "-c";
54012111Sralph 		av[2] = width;
54112111Sralph 		av[3] = length;
54212581Sralph 		av[4] = indent;
54312581Sralph 		n = 5;
54412111Sralph 		break;
54512463Sralph 	case 'r':	/* print a fortran text file */
54612463Sralph 		prog = RF;
54712463Sralph 		av[1] = width;
54812463Sralph 		av[2] = length;
54912463Sralph 		n = 3;
55012463Sralph 		break;
55112111Sralph 	case 't':	/* print troff output */
55213233Sralph 	case 'n':	/* print ditroff output */
55312463Sralph 	case 'd':	/* print tex output */
55412111Sralph 		(void) unlink(".railmag");
55512463Sralph 		if ((fo = creat(".railmag", FILMOD)) < 0) {
55616762Sralph 			syslog(LOG_ERR, "%s: cannot create .railmag", printer);
55712111Sralph 			(void) unlink(".railmag");
55812111Sralph 		} else {
55912111Sralph 			for (n = 0; n < 4; n++) {
56012111Sralph 				if (fonts[n][0] != '/')
56154520Sbostic 					(void) write(fo, _PATH_VFONT,
56254520Sbostic 					    sizeof(_PATH_VFONT) - 1);
56312111Sralph 				(void) write(fo, fonts[n], strlen(fonts[n]));
56412111Sralph 				(void) write(fo, "\n", 1);
56512111Sralph 			}
56612111Sralph 			(void) close(fo);
56712111Sralph 		}
56813233Sralph 		prog = (format == 't') ? TF : (format == 'n') ? NF : DF;
56912463Sralph 		av[1] = pxwidth;
57012463Sralph 		av[2] = pxlength;
57112463Sralph 		n = 3;
57212111Sralph 		break;
57312111Sralph 	case 'c':	/* print cifplot output */
57412111Sralph 		prog = CF;
57512463Sralph 		av[1] = pxwidth;
57612463Sralph 		av[2] = pxlength;
57712463Sralph 		n = 3;
57812111Sralph 		break;
57912111Sralph 	case 'g':	/* print plot(1G) output */
58012111Sralph 		prog = GF;
58112463Sralph 		av[1] = pxwidth;
58212463Sralph 		av[2] = pxlength;
58312463Sralph 		n = 3;
58412111Sralph 		break;
58512111Sralph 	case 'v':	/* print raster output */
58612111Sralph 		prog = VF;
58712463Sralph 		av[1] = pxwidth;
58812463Sralph 		av[2] = pxlength;
58912463Sralph 		n = 3;
59012111Sralph 		break;
59112111Sralph 	default:
59212111Sralph 		(void) close(fi);
59316762Sralph 		syslog(LOG_ERR, "%s: illegal format character '%c'",
59416762Sralph 			printer, format);
59517463Sralph 		return(ERROR);
59612111Sralph 	}
59712111Sralph 	if ((av[0] = rindex(prog, '/')) != NULL)
59812111Sralph 		av[0]++;
59912111Sralph 	else
60012111Sralph 		av[0] = prog;
60112111Sralph 	av[n++] = "-n";
60212111Sralph 	av[n++] = logname;
60312111Sralph 	av[n++] = "-h";
60414150Sralph 	av[n++] = fromhost;
60512111Sralph 	av[n++] = AF;
60612111Sralph 	av[n] = 0;
60712111Sralph 	fo = pfd;
60812111Sralph 	if (ofilter > 0) {		/* stop output filter */
60912111Sralph 		write(ofd, "\031\1", 2);
61046912Sbostic 		while ((pid =
61146912Sbostic 		    wait3((int *)&status, WUNTRACED, 0)) > 0 && pid != ofilter)
61212111Sralph 			;
61312111Sralph 		if (status.w_stopval != WSTOPPED) {
61412111Sralph 			(void) close(fi);
61516762Sralph 			syslog(LOG_WARNING, "%s: output filter died (%d)",
61616762Sralph 				printer, status.w_retcode);
61717463Sralph 			return(REPRINT);
61812111Sralph 		}
61912111Sralph 		stopped++;
62012111Sralph 	}
62112111Sralph start:
62212111Sralph 	if ((child = dofork(DORETURN)) == 0) {	/* child */
62312111Sralph 		dup2(fi, 0);
62412111Sralph 		dup2(fo, 1);
62539954Smckusick 		n = open(tempfile, O_WRONLY|O_CREAT|O_TRUNC, 0664);
62615811Sralph 		if (n >= 0)
62715811Sralph 			dup2(n, 2);
628*68972Stef 		closelog();
62912111Sralph 		for (n = 3; n < NOFILE; n++)
63012111Sralph 			(void) close(n);
63112111Sralph 		execv(prog, av);
63216762Sralph 		syslog(LOG_ERR, "cannot execv %s", prog);
63312111Sralph 		exit(2);
63412111Sralph 	}
63512111Sralph 	(void) close(fi);
63612111Sralph 	if (child < 0)
63712111Sralph 		status.w_retcode = 100;
63812111Sralph 	else
63946912Sbostic 		while ((pid = wait((int *)&status)) > 0 && pid != child)
64012111Sralph 			;
64112111Sralph 	child = 0;
64212111Sralph 	prchild = 0;
64312111Sralph 	if (stopped) {		/* restart output filter */
64412111Sralph 		if (kill(ofilter, SIGCONT) < 0) {
64516762Sralph 			syslog(LOG_ERR, "cannot restart output filter");
64612111Sralph 			exit(1);
64712111Sralph 		}
64812111Sralph 	}
64912111Sralph 	tof = 0;
65039954Smckusick 
65139954Smckusick 	/* Copy filter output to "lf" logfile */
65239954Smckusick 	if (fp = fopen(tempfile, "r")) {
65339954Smckusick 		while (fgets(buf, sizeof(buf), fp))
65439954Smckusick 			fputs(buf, stderr);
65556123Selan 		fclose(fp);
65639954Smckusick 	}
65739954Smckusick 
65815811Sralph 	if (!WIFEXITED(status)) {
65916762Sralph 		syslog(LOG_WARNING, "%s: Daemon filter '%c' terminated (%d)",
66016762Sralph 			printer, format, status.w_termsig);
66117463Sralph 		return(ERROR);
66217463Sralph 	}
66317463Sralph 	switch (status.w_retcode) {
66417463Sralph 	case 0:
66517463Sralph 		tof = 1;
66617463Sralph 		return(OK);
66717463Sralph 	case 1:
66817463Sralph 		return(REPRINT);
66917463Sralph 	default:
67016762Sralph 		syslog(LOG_WARNING, "%s: Daemon filter '%c' exited (%d)",
67116762Sralph 			printer, format, status.w_retcode);
67217463Sralph 	case 2:
67317463Sralph 		return(ERROR);
67417463Sralph 	}
67512111Sralph }
67612111Sralph 
67712111Sralph /*
67812111Sralph  * Send the daemon control file (cf) and any data files.
67912111Sralph  * Return -1 if a non-recoverable error occured, 1 if a recoverable error and
68012111Sralph  * 0 if all is well.
68112111Sralph  */
68255474Sbostic static int
68312111Sralph sendit(file)
68412111Sralph 	char *file;
68512111Sralph {
68617463Sralph 	register int i, err = OK;
68717463Sralph 	char *cp, last[BUFSIZ];
68812111Sralph 
68912111Sralph 	/*
69012111Sralph 	 * open control file
69112111Sralph 	 */
69216762Sralph 	if ((cfp = fopen(file, "r")) == NULL)
69317463Sralph 		return(OK);
69412111Sralph 	/*
69512111Sralph 	 *      read the control file for work to do
69612111Sralph 	 *
69712111Sralph 	 *      file format -- first character in the line is a command
69812111Sralph 	 *      rest of the line is the argument.
69912111Sralph 	 *      commands of interest are:
70012111Sralph 	 *
70112111Sralph 	 *            a-z -- "file name" name of file to print
70212111Sralph 	 *              U -- "unlink" name of file to remove
70312111Sralph 	 *                    (after we print it. (Pass 2 only)).
70412111Sralph 	 */
70512111Sralph 
70612111Sralph 	/*
70712111Sralph 	 * pass 1
70812111Sralph 	 */
70912111Sralph 	while (getline(cfp)) {
71012111Sralph 	again:
71117463Sralph 		if (line[0] == 'S') {
71217463Sralph 			cp = line+1;
71317463Sralph 			i = 0;
71417463Sralph 			while (*cp >= '0' && *cp <= '9')
71517463Sralph 				i = i * 10 + (*cp++ - '0');
71617463Sralph 			fdev = i;
71717463Sralph 			cp++;
71817463Sralph 			i = 0;
71917463Sralph 			while (*cp >= '0' && *cp <= '9')
72017463Sralph 				i = i * 10 + (*cp++ - '0');
72117463Sralph 			fino = i;
72217463Sralph 			continue;
72317463Sralph 		}
72412111Sralph 		if (line[0] >= 'a' && line[0] <= 'z') {
72512111Sralph 			strcpy(last, line);
72617463Sralph 			while (i = getline(cfp))
72712111Sralph 				if (strcmp(last, line))
72812111Sralph 					break;
72917463Sralph 			switch (sendfile('\3', last+1)) {
73017463Sralph 			case OK:
73117463Sralph 				if (i)
73217463Sralph 					goto again;
73317463Sralph 				break;
73417463Sralph 			case REPRINT:
73512111Sralph 				(void) fclose(cfp);
73617463Sralph 				return(REPRINT);
73717463Sralph 			case ACCESS:
73817463Sralph 				sendmail(logname, ACCESS);
73917463Sralph 			case ERROR:
74017463Sralph 				err = ERROR;
74117463Sralph 			}
74212111Sralph 			break;
74312111Sralph 		}
74412111Sralph 	}
74517463Sralph 	if (err == OK && sendfile('\2', file) > 0) {
74612111Sralph 		(void) fclose(cfp);
74717463Sralph 		return(REPRINT);
74812111Sralph 	}
74912111Sralph 	/*
75012111Sralph 	 * pass 2
75112111Sralph 	 */
75212111Sralph 	fseek(cfp, 0L, 0);
75312111Sralph 	while (getline(cfp))
75412111Sralph 		if (line[0] == 'U')
75512111Sralph 			(void) unlink(line+1);
75612111Sralph 	/*
75717463Sralph 	 * clean-up in case another control file exists
75812111Sralph 	 */
75912111Sralph 	(void) fclose(cfp);
76012111Sralph 	(void) unlink(file);
76117463Sralph 	return(err);
76212111Sralph }
76312111Sralph 
76412111Sralph /*
76512111Sralph  * Send a data file to the remote machine and spool it.
76612111Sralph  * Return positive if we should try resending.
76712111Sralph  */
76855474Sbostic static int
76912111Sralph sendfile(type, file)
77055474Sbostic 	int type;
77155474Sbostic 	char *file;
77212111Sralph {
77312111Sralph 	register int f, i, amt;
77412111Sralph 	struct stat stb;
77512111Sralph 	char buf[BUFSIZ];
77616762Sralph 	int sizerr, resp;
77712111Sralph 
77817463Sralph 	if (lstat(file, &stb) < 0 || (f = open(file, O_RDONLY)) < 0)
77917463Sralph 		return(ERROR);
78017463Sralph 	/*
78117463Sralph 	 * Check to see if data file is a symbolic link. If so, it should
78217463Sralph 	 * still point to the same file or someone is trying to print something
78317463Sralph 	 * he shouldn't.
78417463Sralph 	 */
78517463Sralph 	if ((stb.st_mode & S_IFMT) == S_IFLNK && fstat(f, &stb) == 0 &&
78617463Sralph 	    (stb.st_dev != fdev || stb.st_ino != fino))
78717463Sralph 		return(ACCESS);
788*68972Stef 	(void) sprintf(buf, "%c%ld %s\n", type, (long)stb.st_size, file);
78912111Sralph 	amt = strlen(buf);
79016762Sralph 	for (i = 0;  ; i++) {
79116762Sralph 		if (write(pfd, buf, amt) != amt ||
79216762Sralph 		    (resp = response()) < 0 || resp == '\1') {
79316762Sralph 			(void) close(f);
79417463Sralph 			return(REPRINT);
79516762Sralph 		} else if (resp == '\0')
79616762Sralph 			break;
79716762Sralph 		if (i == 0)
79855474Sbostic 			pstatus("no space on remote; waiting for queue to drain");
79916762Sralph 		if (i == 10)
80024861Seric 			syslog(LOG_ALERT, "%s: can't send to %s; queue full",
80116762Sralph 				printer, RM);
80216762Sralph 		sleep(5 * 60);
80312692Sralph 	}
80416762Sralph 	if (i)
80555474Sbostic 		pstatus("sending to %s", RM);
80612111Sralph 	sizerr = 0;
80712111Sralph 	for (i = 0; i < stb.st_size; i += BUFSIZ) {
80812111Sralph 		amt = BUFSIZ;
80912111Sralph 		if (i + amt > stb.st_size)
81012111Sralph 			amt = stb.st_size - i;
81112111Sralph 		if (sizerr == 0 && read(f, buf, amt) != amt)
81212111Sralph 			sizerr = 1;
81312692Sralph 		if (write(pfd, buf, amt) != amt) {
81412692Sralph 			(void) close(f);
81517463Sralph 			return(REPRINT);
81612692Sralph 		}
81712111Sralph 	}
81855474Sbostic 
81955474Sbostic 
82055474Sbostic 
82155474Sbostic 
82212111Sralph 	(void) close(f);
82312111Sralph 	if (sizerr) {
82416762Sralph 		syslog(LOG_INFO, "%s: %s: changed size", printer, file);
82517463Sralph 		/* tell recvjob to ignore this file */
82617463Sralph 		(void) write(pfd, "\1", 1);
82717463Sralph 		return(ERROR);
82817463Sralph 	}
82917463Sralph 	if (write(pfd, "", 1) != 1 || response())
83017463Sralph 		return(REPRINT);
83117463Sralph 	return(OK);
83212111Sralph }
83312111Sralph 
83412111Sralph /*
83512111Sralph  * Check to make sure there have been no errors and that both programs
83612111Sralph  * are in sync with eachother.
83712111Sralph  * Return non-zero if the connection was lost.
83812111Sralph  */
83955474Sbostic static char
84016762Sralph response()
84112111Sralph {
84212111Sralph 	char resp;
84312111Sralph 
84416762Sralph 	if (read(pfd, &resp, 1) != 1) {
84516762Sralph 		syslog(LOG_INFO, "%s: lost connection", printer);
84616762Sralph 		return(-1);
84712111Sralph 	}
84816762Sralph 	return(resp);
84912111Sralph }
85012111Sralph 
85112111Sralph /*
85212111Sralph  * Banner printing stuff
85312111Sralph  */
85455474Sbostic static void
85512111Sralph banner(name1, name2)
85612111Sralph 	char *name1, *name2;
85712111Sralph {
85812111Sralph 	time_t tvec;
85912111Sralph 	extern char *ctime();
86012111Sralph 
86112111Sralph 	time(&tvec);
86212111Sralph 	if (!SF && !tof)
86312111Sralph 		(void) write(ofd, FF, strlen(FF));
86412111Sralph 	if (SB) {	/* short banner only */
86512111Sralph 		if (class[0]) {
86612111Sralph 			(void) write(ofd, class, strlen(class));
86712111Sralph 			(void) write(ofd, ":", 1);
86812111Sralph 		}
86912111Sralph 		(void) write(ofd, name1, strlen(name1));
87012111Sralph 		(void) write(ofd, "  Job: ", 7);
87112111Sralph 		(void) write(ofd, name2, strlen(name2));
87212111Sralph 		(void) write(ofd, "  Date: ", 8);
87312111Sralph 		(void) write(ofd, ctime(&tvec), 24);
87412111Sralph 		(void) write(ofd, "\n", 1);
87512111Sralph 	} else {	/* normal banner */
87612111Sralph 		(void) write(ofd, "\n\n\n", 3);
87712111Sralph 		scan_out(ofd, name1, '\0');
87812111Sralph 		(void) write(ofd, "\n\n", 2);
87912111Sralph 		scan_out(ofd, name2, '\0');
88012111Sralph 		if (class[0]) {
88112111Sralph 			(void) write(ofd,"\n\n\n",3);
88212111Sralph 			scan_out(ofd, class, '\0');
88312111Sralph 		}
88412111Sralph 		(void) write(ofd, "\n\n\n\n\t\t\t\t\tJob:  ", 15);
88512111Sralph 		(void) write(ofd, name2, strlen(name2));
88612111Sralph 		(void) write(ofd, "\n\t\t\t\t\tDate: ", 12);
88712111Sralph 		(void) write(ofd, ctime(&tvec), 24);
88812111Sralph 		(void) write(ofd, "\n", 1);
88912111Sralph 	}
89012111Sralph 	if (!SF)
89112111Sralph 		(void) write(ofd, FF, strlen(FF));
89212111Sralph 	tof = 1;
89312111Sralph }
89412111Sralph 
89555474Sbostic static char *
89612111Sralph scnline(key, p, c)
89755474Sbostic 	register int key;
89855474Sbostic 	register char *p;
89955474Sbostic 	int c;
90012111Sralph {
90112111Sralph 	register scnwidth;
90212111Sralph 
90312111Sralph 	for (scnwidth = WIDTH; --scnwidth;) {
90412111Sralph 		key <<= 1;
90512111Sralph 		*p++ = key & 0200 ? c : BACKGND;
90612111Sralph 	}
90712111Sralph 	return (p);
90812111Sralph }
90912111Sralph 
91012111Sralph #define TRC(q)	(((q)-' ')&0177)
91112111Sralph 
91255474Sbostic static void
91312111Sralph scan_out(scfd, scsp, dlm)
91455474Sbostic 	int scfd, dlm;
91555474Sbostic 	char *scsp;
91612111Sralph {
91712111Sralph 	register char *strp;
91812111Sralph 	register nchrs, j;
91912111Sralph 	char outbuf[LINELEN+1], *sp, c, cc;
92012111Sralph 	int d, scnhgt;
92112111Sralph 	extern char scnkey[][HEIGHT];	/* in lpdchar.c */
92212111Sralph 
92312111Sralph 	for (scnhgt = 0; scnhgt++ < HEIGHT+DROP; ) {
92412111Sralph 		strp = &outbuf[0];
92512111Sralph 		sp = scsp;
92612111Sralph 		for (nchrs = 0; ; ) {
92712111Sralph 			d = dropit(c = TRC(cc = *sp++));
92812111Sralph 			if ((!d && scnhgt > HEIGHT) || (scnhgt <= DROP && d))
92912111Sralph 				for (j = WIDTH; --j;)
93012111Sralph 					*strp++ = BACKGND;
93112111Sralph 			else
93212111Sralph 				strp = scnline(scnkey[c][scnhgt-1-d], strp, cc);
93312111Sralph 			if (*sp == dlm || *sp == '\0' || nchrs++ >= PW/(WIDTH+1)-1)
93412111Sralph 				break;
93512111Sralph 			*strp++ = BACKGND;
93612111Sralph 			*strp++ = BACKGND;
93712111Sralph 		}
93812111Sralph 		while (*--strp == BACKGND && strp >= outbuf)
93912111Sralph 			;
94012111Sralph 		strp++;
94112111Sralph 		*strp++ = '\n';
94212111Sralph 		(void) write(scfd, outbuf, strp-outbuf);
94312111Sralph 	}
94412111Sralph }
94512111Sralph 
94655474Sbostic static int
94712111Sralph dropit(c)
94855474Sbostic 	int c;
94912111Sralph {
95012111Sralph 	switch(c) {
95112111Sralph 
95212111Sralph 	case TRC('_'):
95312111Sralph 	case TRC(';'):
95412111Sralph 	case TRC(','):
95512111Sralph 	case TRC('g'):
95612111Sralph 	case TRC('j'):
95712111Sralph 	case TRC('p'):
95812111Sralph 	case TRC('q'):
95912111Sralph 	case TRC('y'):
96012111Sralph 		return (DROP);
96112111Sralph 
96212111Sralph 	default:
96312111Sralph 		return (0);
96412111Sralph 	}
96512111Sralph }
96612111Sralph 
96712111Sralph /*
96812111Sralph  * sendmail ---
96912111Sralph  *   tell people about job completion
97012111Sralph  */
97155474Sbostic static void
97215811Sralph sendmail(user, bombed)
97315811Sralph 	char *user;
97412111Sralph 	int bombed;
97512111Sralph {
97612111Sralph 	register int i;
97715811Sralph 	int p[2], s;
97812111Sralph 	register char *cp;
97912111Sralph 	char buf[100];
98015811Sralph 	struct stat stb;
98115811Sralph 	FILE *fp;
98212111Sralph 
98312111Sralph 	pipe(p);
98415811Sralph 	if ((s = dofork(DORETURN)) == 0) {		/* child */
98512111Sralph 		dup2(p[0], 0);
986*68972Stef 		closelog();
98712111Sralph 		for (i = 3; i < NOFILE; i++)
98812111Sralph 			(void) close(i);
98937968Sbostic 		if ((cp = rindex(_PATH_SENDMAIL, '/')) != NULL)
99012111Sralph 			cp++;
99155474Sbostic 	else
99237968Sbostic 			cp = _PATH_SENDMAIL;
99315811Sralph 		sprintf(buf, "%s@%s", user, fromhost);
99437968Sbostic 		execl(_PATH_SENDMAIL, cp, buf, 0);
99512111Sralph 		exit(0);
99615811Sralph 	} else if (s > 0) {				/* parent */
99712111Sralph 		dup2(p[1], 1);
99815811Sralph 		printf("To: %s@%s\n", user, fromhost);
99912111Sralph 		printf("Subject: printer job\n\n");
100012111Sralph 		printf("Your printer job ");
100112111Sralph 		if (*jobname)
100212111Sralph 			printf("(%s) ", jobname);
100312463Sralph 		switch (bombed) {
100417463Sralph 		case OK:
100512463Sralph 			printf("\ncompleted successfully\n");
100612463Sralph 			break;
100712463Sralph 		default:
100817463Sralph 		case FATALERR:
100912463Sralph 			printf("\ncould not be printed\n");
101012463Sralph 			break;
101117463Sralph 		case NOACCT:
101212463Sralph 			printf("\ncould not be printed without an account on %s\n", host);
101312463Sralph 			break;
101417463Sralph 		case FILTERERR:
101539954Smckusick 			if (stat(tempfile, &stb) < 0 || stb.st_size == 0 ||
101639954Smckusick 			    (fp = fopen(tempfile, "r")) == NULL) {
101715811Sralph 				printf("\nwas printed but had some errors\n");
101815811Sralph 				break;
101915811Sralph 			}
102015811Sralph 			printf("\nwas printed but had the following errors:\n");
102115811Sralph 			while ((i = getc(fp)) != EOF)
102215811Sralph 				putchar(i);
102315811Sralph 			(void) fclose(fp);
102417463Sralph 			break;
102517463Sralph 		case ACCESS:
102617463Sralph 			printf("\nwas not printed because it was not linked to the original file\n");
102712463Sralph 		}
102812111Sralph 		fflush(stdout);
102912111Sralph 		(void) close(1);
103012111Sralph 	}
103112111Sralph 	(void) close(p[0]);
103212111Sralph 	(void) close(p[1]);
103315811Sralph 	wait(&s);
103412111Sralph }
103512111Sralph 
103612111Sralph /*
103712111Sralph  * dofork - fork with retries on failure
103812111Sralph  */
103955474Sbostic static int
104012111Sralph dofork(action)
104112111Sralph 	int action;
104212111Sralph {
104312111Sralph 	register int i, pid;
104412111Sralph 
104512111Sralph 	for (i = 0; i < 20; i++) {
104612463Sralph 		if ((pid = fork()) < 0) {
104712111Sralph 			sleep((unsigned)(i*i));
104812463Sralph 			continue;
104912463Sralph 		}
105012463Sralph 		/*
105112463Sralph 		 * Child should run as daemon instead of root
105212463Sralph 		 */
105312463Sralph 		if (pid == 0)
105412463Sralph 			setuid(DU);
105512463Sralph 		return(pid);
105612111Sralph 	}
105716762Sralph 	syslog(LOG_ERR, "can't fork");
105812111Sralph 
105912111Sralph 	switch (action) {
106012111Sralph 	case DORETURN:
106112111Sralph 		return (-1);
106212111Sralph 	default:
106316762Sralph 		syslog(LOG_ERR, "bad action (%d) to dofork", action);
106412111Sralph 		/*FALL THRU*/
106512111Sralph 	case DOABORT:
106612111Sralph 		exit(1);
106712111Sralph 	}
106812111Sralph 	/*NOTREACHED*/
106912111Sralph }
107012111Sralph 
107112111Sralph /*
107216762Sralph  * Kill child processes to abort current job.
107312111Sralph  */
107455474Sbostic static void
107555474Sbostic abortpr(signo)
107655474Sbostic 	int signo;
107712111Sralph {
107839954Smckusick 	(void) unlink(tempfile);
107912111Sralph 	kill(0, SIGINT);
108012111Sralph 	if (ofilter > 0)
108112111Sralph 		kill(ofilter, SIGCONT);
108246912Sbostic 	while (wait(NULL) > 0)
108312111Sralph 		;
108412111Sralph 	exit(0);
108512111Sralph }
108612111Sralph 
108755474Sbostic static void
108812111Sralph init()
108912111Sralph {
109012111Sralph 	int status;
109138736Stef 	char *s;
109212111Sralph 
109356123Selan 	if ((status = cgetent(&bp, printcapdb, printer)) == -2) {
109425468Stef 		syslog(LOG_ERR, "can't open printer description file");
109525468Stef 		exit(1);
109656123Selan 	} else if (status == -1) {
109725468Stef 		syslog(LOG_ERR, "unknown printer: %s", printer);
109825468Stef 		exit(1);
109956123Selan 	} else if (status == -3)
110056123Selan 		fatal("potential reference loop detected in printcap file");
110156123Selan 
110256123Selan 	if (cgetstr(bp, "lp", &LP) == -1)
110337968Sbostic 		LP = _PATH_DEFDEVLP;
110456123Selan 	if (cgetstr(bp, "rp", &RP) == -1)
110512463Sralph 		RP = DEFLP;
110656123Selan 	if (cgetstr(bp, "lo", &LO) == -1)
110712111Sralph 		LO = DEFLOCK;
110856123Selan 	if (cgetstr(bp, "st", &ST) == -1)
110912111Sralph 		ST = DEFSTAT;
111056123Selan 	if (cgetstr(bp, "lf", &LF) == -1)
111137968Sbostic 		LF = _PATH_CONSOLE;
111256123Selan 	if (cgetstr(bp, "sd", &SD) == -1)
111337968Sbostic 		SD = _PATH_DEFSPOOL;
111456123Selan 	if (cgetnum(bp, "du", &DU) < 0)
111512111Sralph 		DU = DEFUID;
111656123Selan 	if (cgetstr(bp,"ff", &FF) == -1)
111712111Sralph 		FF = DEFFF;
111856123Selan 	if (cgetnum(bp, "pw", &PW) < 0)
111912111Sralph 		PW = DEFWIDTH;
112012111Sralph 	sprintf(&width[2], "%d", PW);
112156123Selan 	if (cgetnum(bp, "pl", &PL) < 0)
112212111Sralph 		PL = DEFLENGTH;
112312111Sralph 	sprintf(&length[2], "%d", PL);
112456123Selan 	if (cgetnum(bp,"px", &PX) < 0)
112512463Sralph 		PX = 0;
112612463Sralph 	sprintf(&pxwidth[2], "%d", PX);
112756123Selan 	if (cgetnum(bp, "py", &PY) < 0)
112812463Sralph 		PY = 0;
112912463Sralph 	sprintf(&pxlength[2], "%d", PY);
113056123Selan 	cgetstr(bp, "rm", &RM);
113138736Stef 	if (s = checkremote())
113238736Stef 		syslog(LOG_WARNING, s);
113325468Stef 
113456123Selan 	cgetstr(bp, "af", &AF);
113556123Selan 	cgetstr(bp, "of", &OF);
113656123Selan 	cgetstr(bp, "if", &IF);
113756123Selan 	cgetstr(bp, "rf", &RF);
113856123Selan 	cgetstr(bp, "tf", &TF);
113956123Selan 	cgetstr(bp, "nf", &NF);
114056123Selan 	cgetstr(bp, "df", &DF);
114156123Selan 	cgetstr(bp, "gf", &GF);
114256123Selan 	cgetstr(bp, "vf", &VF);
114356123Selan 	cgetstr(bp, "cf", &CF);
114456123Selan 	cgetstr(bp, "tr", &TR);
114556123Selan 
114656123Selan 	RS = (cgetcap(bp, "rs", ':') != NULL);
114756123Selan 	SF = (cgetcap(bp, "sf", ':') != NULL);
114856123Selan 	SH = (cgetcap(bp, "sh", ':') != NULL);
114956123Selan 	SB = (cgetcap(bp, "sb", ':') != NULL);
115056123Selan 	HL = (cgetcap(bp, "hl", ':') != NULL);
115156123Selan 	RW = (cgetcap(bp, "rw", ':') != NULL);
115256123Selan 
115356123Selan 	cgetnum(bp, "br", &BR);
115456123Selan 	if (cgetnum(bp, "fc", &FC) < 0)
115512111Sralph 		FC = 0;
115656123Selan 	if (cgetnum(bp, "fs", &FS) < 0)
115712111Sralph 		FS = 0;
115856123Selan 	if (cgetnum(bp, "xc", &XC) < 0)
115912111Sralph 		XC = 0;
116056123Selan 	if (cgetnum(bp, "xs", &XS) < 0)
116112111Sralph 		XS = 0;
116256123Selan 
116356123Selan 	tof = (cgetcap(bp, "fo", ':') == NULL);
116412111Sralph }
116512111Sralph 
116612463Sralph /*
116712463Sralph  * Acquire line printer or remote connection.
116812463Sralph  */
116955474Sbostic static void
117012463Sralph openpr()
117112463Sralph {
117212463Sralph 	register int i, n;
117316762Sralph 	int resp;
117412463Sralph 
117538736Stef 	if (!sendtorem && *LP) {
117612463Sralph 		for (i = 1; ; i = i < 32 ? i << 1 : i) {
117713148Ssam 			pfd = open(LP, RW ? O_RDWR : O_WRONLY);
117812463Sralph 			if (pfd >= 0)
117912463Sralph 				break;
118012463Sralph 			if (errno == ENOENT) {
118116762Sralph 				syslog(LOG_ERR, "%s: %m", LP);
118212463Sralph 				exit(1);
118312463Sralph 			}
118412463Sralph 			if (i == 1)
118555474Sbostic 				pstatus("waiting for %s to become ready (offline ?)", printer);
118612463Sralph 			sleep(i);
118712463Sralph 		}
118812463Sralph 		if (isatty(pfd))
118912463Sralph 			setty();
119055474Sbostic 		pstatus("%s is ready and printing", printer);
119112463Sralph 	} else if (RM != NULL) {
119216762Sralph 		for (i = 1; ; i = i < 256 ? i << 1 : i) {
119316762Sralph 			resp = -1;
119412528Sralph 			pfd = getport(RM);
119512463Sralph 			if (pfd >= 0) {
119612463Sralph 				(void) sprintf(line, "\2%s\n", RP);
119712463Sralph 				n = strlen(line);
119816762Sralph 				if (write(pfd, line, n) == n &&
119916762Sralph 				    (resp = response()) == '\0')
120012463Sralph 					break;
120116031Sralph 				(void) close(pfd);
120212463Sralph 			}
120316031Sralph 			if (i == 1) {
120416762Sralph 				if (resp < 0)
120555474Sbostic 					pstatus("waiting for %s to come up", RM);
120616762Sralph 				else {
120755474Sbostic 					pstatus("waiting for queue to be enabled on %s", RM);
120816762Sralph 					i = 256;
120916762Sralph 				}
121016031Sralph 			}
121112463Sralph 			sleep(i);
121212463Sralph 		}
121355474Sbostic 		pstatus("sending to %s", RM);
121412463Sralph 		remote = 1;
121512463Sralph 	} else {
121616762Sralph 		syslog(LOG_ERR, "%s: no line printer device or host name",
121716762Sralph 			printer);
121812463Sralph 		exit(1);
121912463Sralph 	}
122012463Sralph 	/*
122112463Sralph 	 * Start up an output filter, if needed.
122212463Sralph 	 */
122340049Stef 	if (!remote && OF) {
122412463Sralph 		int p[2];
122512463Sralph 		char *cp;
122612463Sralph 
122712463Sralph 		pipe(p);
122812463Sralph 		if ((ofilter = dofork(DOABORT)) == 0) {	/* child */
122912463Sralph 			dup2(p[0], 0);		/* pipe is std in */
123012463Sralph 			dup2(pfd, 1);		/* printer is std out */
1231*68972Stef 			closelog();
123212463Sralph 			for (i = 3; i < NOFILE; i++)
123312463Sralph 				(void) close(i);
123412463Sralph 			if ((cp = rindex(OF, '/')) == NULL)
123512463Sralph 				cp = OF;
123612463Sralph 			else
123712463Sralph 				cp++;
123812463Sralph 			execl(OF, cp, width, length, 0);
123916762Sralph 			syslog(LOG_ERR, "%s: %s: %m", printer, OF);
124012463Sralph 			exit(1);
124112463Sralph 		}
124212463Sralph 		(void) close(p[0]);		/* close input side */
124312463Sralph 		ofd = p[1];			/* use pipe for output */
124412463Sralph 	} else {
124512463Sralph 		ofd = pfd;
124612463Sralph 		ofilter = 0;
124712463Sralph 	}
124812463Sralph }
124912463Sralph 
125012111Sralph struct bauds {
125112111Sralph 	int	baud;
125212111Sralph 	int	speed;
125312111Sralph } bauds[] = {
125412111Sralph 	50,	B50,
125512111Sralph 	75,	B75,
125612111Sralph 	110,	B110,
125712111Sralph 	134,	B134,
125812111Sralph 	150,	B150,
125912111Sralph 	200,	B200,
126012111Sralph 	300,	B300,
126112111Sralph 	600,	B600,
126212111Sralph 	1200,	B1200,
126312111Sralph 	1800,	B1800,
126412111Sralph 	2400,	B2400,
126512111Sralph 	4800,	B4800,
126612111Sralph 	9600,	B9600,
126712111Sralph 	19200,	EXTA,
126812111Sralph 	38400,	EXTB,
126912111Sralph 	0,	0
127012111Sralph };
127112111Sralph 
127212111Sralph /*
127312111Sralph  * setup tty lines.
127412111Sralph  */
127555474Sbostic static void
127612111Sralph setty()
127712111Sralph {
127812111Sralph 	struct sgttyb ttybuf;
127912111Sralph 	register struct bauds *bp;
128012111Sralph 
128112111Sralph 	if (ioctl(pfd, TIOCEXCL, (char *)0) < 0) {
128216762Sralph 		syslog(LOG_ERR, "%s: ioctl(TIOCEXCL): %m", printer);
128312111Sralph 		exit(1);
128412111Sralph 	}
128512111Sralph 	if (ioctl(pfd, TIOCGETP, (char *)&ttybuf) < 0) {
128616762Sralph 		syslog(LOG_ERR, "%s: ioctl(TIOCGETP): %m", printer);
128712111Sralph 		exit(1);
128812111Sralph 	}
128912111Sralph 	if (BR > 0) {
129012111Sralph 		for (bp = bauds; bp->baud; bp++)
129112111Sralph 			if (BR == bp->baud)
129212111Sralph 				break;
129312111Sralph 		if (!bp->baud) {
129416762Sralph 			syslog(LOG_ERR, "%s: illegal baud rate %d", printer, BR);
129512111Sralph 			exit(1);
129612111Sralph 		}
129712111Sralph 		ttybuf.sg_ispeed = ttybuf.sg_ospeed = bp->speed;
129812111Sralph 	}
129913169Sralph 	ttybuf.sg_flags &= ~FC;
130013169Sralph 	ttybuf.sg_flags |= FS;
130112111Sralph 	if (ioctl(pfd, TIOCSETP, (char *)&ttybuf) < 0) {
130216762Sralph 		syslog(LOG_ERR, "%s: ioctl(TIOCSETP): %m", printer);
130312111Sralph 		exit(1);
130412111Sralph 	}
130512111Sralph 	if (XC) {
130612111Sralph 		if (ioctl(pfd, TIOCLBIC, &XC) < 0) {
130716762Sralph 			syslog(LOG_ERR, "%s: ioctl(TIOCLBIC): %m", printer);
130812111Sralph 			exit(1);
130912111Sralph 		}
131012111Sralph 	}
131112111Sralph 	if (XS) {
131212111Sralph 		if (ioctl(pfd, TIOCLBIS, &XS) < 0) {
131316762Sralph 			syslog(LOG_ERR, "%s: ioctl(TIOCLBIS): %m", printer);
131412111Sralph 			exit(1);
131512111Sralph 		}
131612111Sralph 	}
131712111Sralph }
131812463Sralph 
131955474Sbostic #if __STDC__
132055474Sbostic #include <stdarg.h>
132155474Sbostic #else
132255474Sbostic #include <varargs.h>
132355474Sbostic #endif
132455474Sbostic 
132555474Sbostic void
132655474Sbostic #if __STDC__
132755474Sbostic pstatus(const char *msg, ...)
132855474Sbostic #else
132955474Sbostic pstatus(msg, va_alist)
133012463Sralph 	char *msg;
133155474Sbostic         va_dcl
133255474Sbostic #endif
133312463Sralph {
133412463Sralph 	register int fd;
133512463Sralph 	char buf[BUFSIZ];
133655474Sbostic 	va_list ap;
133755474Sbostic #if __STDC__
133855474Sbostic 	va_start(ap, msg);
133955474Sbostic #else
134055474Sbostic 	va_start(ap);
134155474Sbostic #endif
134212463Sralph 
134312463Sralph 	umask(0);
134413148Ssam 	fd = open(ST, O_WRONLY|O_CREAT, 0664);
134516762Sralph 	if (fd < 0 || flock(fd, LOCK_EX) < 0) {
134616762Sralph 		syslog(LOG_ERR, "%s: %s: %m", printer, ST);
134716762Sralph 		exit(1);
134816762Sralph 	}
134913148Ssam 	ftruncate(fd, 0);
135055474Sbostic 	(void)vsnprintf(buf, sizeof(buf), msg, ap);
135155474Sbostic 	va_end(ap);
135212463Sralph 	strcat(buf, "\n");
135312463Sralph 	(void) write(fd, buf, strlen(buf));
135412463Sralph 	(void) close(fd);
135512463Sralph }
1356