xref: /csrg-svn/usr.sbin/lpr/lpd/printjob.c (revision 12581)
1*12581Sralph /*	printjob.c	4.4	83/05/19	*/
212111Sralph /*
312111Sralph  * printjob -- print jobs in the queue.
412111Sralph  *
512111Sralph  *	NOTE: the lock file is used to pass information to lpq and lprm.
612111Sralph  *	it does not need to be removed because file locks are dynamic.
712111Sralph  */
812111Sralph 
912111Sralph #include "lp.h"
1012111Sralph 
1112111Sralph #define DORETURN	0	/* absorb fork error */
1212111Sralph #define DOABORT		1	/* abort if dofork fails */
1312111Sralph 
1412111Sralph char	title[80];		/* ``pr'' title */
1512111Sralph FILE	*cfp;			/* control file */
1612111Sralph int	pfd;			/* printer file descriptor */
1712111Sralph int	ofd;			/* output filter file descriptor */
1812111Sralph int	lfd;			/* lock file descriptor */
1912111Sralph int	pid;			/* pid of lpd process */
2012111Sralph int	prchild;		/* id of pr process */
2112111Sralph int	child;			/* id of any filters */
2212111Sralph int	ofilter;		/* id of output filter, if any */
23*12581Sralph int	tof;			/* true if at top of form */
2412111Sralph int	remote;			/* non zero if sending files to remote */
2512111Sralph 
2612111Sralph extern	banner();		/* big character printer */
2712111Sralph char	logname[32];		/* user's login name */
2812111Sralph char	jobname[32];		/* job or file name */
2912111Sralph char	class[32];		/* classification field */
3012463Sralph char	width[10] = "-w";	/* page width in characters */
3112463Sralph char	length[10] = "-l";	/* page length in lines */
3212463Sralph char	pxwidth[10] = "-x";	/* page width in pixels */
3312463Sralph char	pxlength[10] = "-y";	/* page length in pixels */
34*12581Sralph char	indent[10] = "-i0";	/* indentation size in characters */
3512111Sralph 
3612111Sralph printjob()
3712111Sralph {
3812111Sralph 	struct stat stb;
3912111Sralph 	register struct queue *q, **qp;
4012111Sralph 	struct queue **queue;
4112111Sralph 	register int i, nitems;
4212111Sralph 	long pidoff;
4312111Sralph 	extern int onintr();
4412111Sralph 
4512111Sralph 	init();					/* set up capabilities */
4612111Sralph 	(void) close(2);			/* set up log file */
4712111Sralph 	(void) open(LF, FWRONLY|FAPPEND, 0);
4812463Sralph 	dup2(2, 1);				/* closes original connection */
4912463Sralph 	pid = getpid();				/* for use with lprm */
5012111Sralph 	setpgrp(0, pid);
5112463Sralph 	sigset(SIGINT, onintr);
5212111Sralph 
5312111Sralph 	/*
5412111Sralph 	 * uses short form file names
5512111Sralph 	 */
5612111Sralph 	if (chdir(SD) < 0) {
5712111Sralph 		log("cannot chdir to %s", SD);
5812111Sralph 		exit(1);
5912111Sralph 	}
6012463Sralph 	if (stat(LO, &stb) == 0 && (stb.st_mode & 0100))
6112463Sralph 		exit(0);		/* printing disabled */
6212111Sralph 	if ((lfd = open(LO, FWRONLY|FCREATE|FTRUNCATE|FEXLOCK|FNBLOCK, 0664)) < 0) {
6312111Sralph 		if (errno == EWOULDBLOCK)	/* active deamon present */
6412111Sralph 			exit(0);
6512111Sralph 		log("cannot create %s", LO);
6612111Sralph 		exit(1);
6712111Sralph 	}
6812111Sralph 	/*
6912111Sralph 	 * write process id for others to know
7012111Sralph 	 */
7112111Sralph 	sprintf(line, "%u\n", pid);
7212111Sralph 	pidoff = i = strlen(line);
7312463Sralph 	if (write(lfd, line, i) != i) {
7412111Sralph 		log("cannot write daemon pid");
7512111Sralph 		exit(1);
7612111Sralph 	}
7712111Sralph 	/*
7812111Sralph 	 * search the spool directory for work and sort by queue order.
7912111Sralph 	 */
8012111Sralph 	if ((nitems = getq(&queue)) < 0) {
8112111Sralph 		log("can't scan spool directory %s", SD);
8212111Sralph 		exit(1);
8312111Sralph 	}
8412463Sralph 	if (nitems == 0)		/* no work to do */
8512111Sralph 		exit(0);
8612463Sralph 	openpr();			/* open printer or remote */
8712463Sralph again:
8812111Sralph 	/*
8912111Sralph 	 * we found something to do now do it --
9012111Sralph 	 *    write the name of the current control file into the lock file
9112111Sralph 	 *    so the spool queue program can tell what we're working on
9212111Sralph 	 */
9312111Sralph 	for (qp = queue; nitems--; free((char *) q)) {
9412111Sralph 		q = *qp++;
9512111Sralph 		if (stat(q->q_name, &stb) < 0)
9612111Sralph 			continue;
9712463Sralph 	restart:
9812111Sralph 		(void) lseek(lfd, pidoff, 0);
9912111Sralph 		(void) sprintf(line, "%s\n", q->q_name);
10012111Sralph 		i = strlen(line);
10112111Sralph 		if (write(lfd, line, i) != i)
10212111Sralph 			log("can't write (%d) control file name", errno);
10312111Sralph 		if (!remote)
10412111Sralph 			i = printit(q->q_name);
10512111Sralph 		else
10612111Sralph 			i = sendit(q->q_name);
10712463Sralph 		/*
10812463Sralph 		 * Check to see if we are supposed to stop printing.
10912463Sralph 		 */
11012463Sralph 		if (stat(LO, &stb) == 0 && (stb.st_mode & 0100))
11112463Sralph 			goto done;
11212463Sralph 		/*
11312463Sralph 		 * Check to see if we should try reprinting the job.
11412463Sralph 		 */
11512463Sralph 		if (i > 0) {
11612111Sralph 			log("restarting");
11712111Sralph 			if (ofilter > 0) {
11812111Sralph 				kill(ofilter, SIGCONT);	/* to be sure */
11912111Sralph 				(void) close(ofd);
12012111Sralph 				while ((i = wait(0)) > 0 && i != ofilter)
12112111Sralph 					;
12212111Sralph 				ofilter = 0;
12312111Sralph 			}
12412463Sralph 			(void) close(pfd);	/* close printer */
12512463Sralph 			(void) lseek(lfd, pidoff, 0);
12612463Sralph 			if (write(lfd, "\n", 1) != 1)
12712463Sralph 				log("can't write (%d) control file name", errno);
12812463Sralph 			openpr();		/* try to reopen printer */
12912111Sralph 			goto restart;
13012111Sralph 		}
13112111Sralph 	}
13212111Sralph 	free((char *) queue);
13312463Sralph 	/*
13412463Sralph 	 * search the spool directory for more work.
13512463Sralph 	 */
13612463Sralph 	if ((nitems = getq(&queue)) < 0) {
13712463Sralph 		log("can't scan spool directory %s", SD);
13812463Sralph 		exit(1);
13912463Sralph 	}
14012463Sralph 	if (nitems == 0) {		/* no more work to do */
14112463Sralph 	done:
14212463Sralph 		if (!SF && !tof)
14312463Sralph 			(void) write(ofd, FF, strlen(FF));
14412463Sralph 		if (TR != NULL)		/* output trailer */
14512463Sralph 			(void) write(ofd, TR, strlen(TR));
14612463Sralph 		exit(0);
14712463Sralph 	}
14812111Sralph 	goto again;
14912111Sralph }
15012111Sralph 
15112111Sralph char	fonts[4][50];	/* fonts for troff */
15212111Sralph 
15312111Sralph static char ifonts[4][18] = {
15412111Sralph 	"/usr/lib/vfont/R",
15512111Sralph 	"/usr/lib/vfont/I",
15612111Sralph 	"/usr/lib/vfont/B",
15712111Sralph 	"/usr/lib/vfont/S"
15812111Sralph };
15912111Sralph 
16012111Sralph /*
16112111Sralph  * The remaining part is the reading of the control file (cf)
16212111Sralph  * and performing the various actions.
16312111Sralph  * Returns 0 if everthing was OK, 1 if we should try to reprint the job and
16412111Sralph  * -1 if a non-recoverable error occured.
16512111Sralph  */
16612111Sralph printit(file)
16712111Sralph 	char *file;
16812111Sralph {
16912111Sralph 	register int i;
17012111Sralph 	int bombed = 0;
17112111Sralph 
17212111Sralph 	/*
17312111Sralph 	 * open control file
17412111Sralph 	 */
17512111Sralph 	if ((cfp = fopen(file, "r")) == NULL) {
17612111Sralph 		log("control file (%s) open failure <errno = %d>", file, errno);
17712111Sralph 		return(0);
17812111Sralph 	}
17912111Sralph 	/*
18012111Sralph 	 * Reset troff fonts.
18112111Sralph 	 */
18212111Sralph 	for (i = 0; i < 4; i++)
18312111Sralph 		strcpy(fonts[i], ifonts[i]);
18412111Sralph 
18512111Sralph 	/*
18612111Sralph 	 *      read the control file for work to do
18712111Sralph 	 *
18812111Sralph 	 *      file format -- first character in the line is a command
18912111Sralph 	 *      rest of the line is the argument.
19012111Sralph 	 *      valid commands are:
19112111Sralph 	 *
19212111Sralph 	 *		J -- "job name" on banner page
19312111Sralph 	 *		C -- "class name" on banner page
19412111Sralph 	 *              L -- "literal" user's name to print on banner
19512111Sralph 	 *		T -- "title" for pr
19612111Sralph 	 *		H -- "host name" of machine where lpr was done
19712111Sralph 	 *              P -- "person" user's login name
198*12581Sralph 	 *              I -- "indent" amount to indent output
19912111Sralph 	 *              f -- "file name" name of text file to print
20012111Sralph 	 *		l -- "file name" text file with control chars
20112111Sralph 	 *		p -- "file name" text file to print with pr(1)
20212111Sralph 	 *		t -- "file name" troff(1) file to print
20312111Sralph 	 *		d -- "file name" dvi file to print
20412111Sralph 	 *		g -- "file name" plot(1G) file to print
20512111Sralph 	 *		v -- "file name" plain raster file to print
20612111Sralph 	 *		c -- "file name" cifplot file to print
20712111Sralph 	 *		1 -- "R font file" for troff
20812111Sralph 	 *		2 -- "I font file" for troff
20912111Sralph 	 *		3 -- "B font file" for troff
21012111Sralph 	 *		4 -- "S font file" for troff
21112111Sralph 	 *		N -- "name" of file (used by lpq)
21212111Sralph 	 *              U -- "unlink" name of file to remove
21312111Sralph 	 *                    (after we print it. (Pass 2 only)).
21412111Sralph 	 *		M -- "mail" to user when done printing
21512111Sralph 	 *
21612111Sralph 	 *      getline reads a line and expands tabs to blanks
21712111Sralph 	 */
21812111Sralph 
21912111Sralph 	/* pass 1 */
22012111Sralph 
22112111Sralph 	while (getline(cfp))
22212111Sralph 		switch (line[0]) {
22312111Sralph 		case 'H':
22412111Sralph 			strcpy(host, line+1);
22512111Sralph 			if (class[0] == '\0')
22612111Sralph 				strcpy(class, line+1);
22712111Sralph 			continue;
22812111Sralph 
22912111Sralph 		case 'P':
23012111Sralph 			strcpy(logname, line+1);
23112463Sralph 			if (RS) {			/* restricted */
23212463Sralph 				if (getpwnam(logname) == (struct passwd *)0) {
23312463Sralph 					bombed = 2;
23412463Sralph 					sendmail(bombed);
23512463Sralph 					goto pass2;
23612463Sralph 				}
23712463Sralph 			}
23812111Sralph 			continue;
23912111Sralph 
24012111Sralph 		case 'J':
24112111Sralph 			if (line[1] != '\0')
24212111Sralph 				strcpy(jobname, line+1);
24312111Sralph 			else
24412111Sralph 				strcpy(jobname, " ");
24512111Sralph 			continue;
24612111Sralph 
24712111Sralph 		case 'C':
24812111Sralph 			if (line[1] != '\0')
24912111Sralph 				strcpy(class, line+1);
25012111Sralph 			else if (class[0] == '\0')
25112111Sralph 				gethostname(class, sizeof (class));
25212111Sralph 			continue;
25312111Sralph 
25412111Sralph 		case 'T':	/* header title for pr */
25512111Sralph 			strcpy(title, line+1);
25612111Sralph 			continue;
25712111Sralph 
25812111Sralph 		case 'L':	/* identification line */
25912111Sralph 			if (!SH)
26012111Sralph 				banner(line+1, jobname);
26112111Sralph 			continue;
26212111Sralph 
26312111Sralph 		case '1':	/* troff fonts */
26412111Sralph 		case '2':
26512111Sralph 		case '3':
26612111Sralph 		case '4':
26712111Sralph 			if (line[1] != '\0')
26812111Sralph 				strcpy(fonts[line[0]-'1'], line+1);
26912111Sralph 			continue;
27012111Sralph 
27112111Sralph 		case 'W':	/* page width */
27212111Sralph 			strcpy(width+2, line+1);
27312111Sralph 			continue;
27412111Sralph 
275*12581Sralph 		case 'I':	/* indent amount */
276*12581Sralph 			strcpy(indent+2, line+1);
277*12581Sralph 			continue;
278*12581Sralph 
27912111Sralph 		default:	/* some file to print */
28012111Sralph 			if ((i = print(line[0], line+1)) > 0) {
28112111Sralph 				(void) fclose(cfp);
28212111Sralph 				return(1);
28312111Sralph 			} else if (i < 0)
28412111Sralph 				bombed = 1;
28512111Sralph 			title[0] = '\0';
28612111Sralph 			continue;
28712111Sralph 
28812111Sralph 		case 'N':
28912111Sralph 		case 'U':
29012111Sralph 		case 'M':
29112111Sralph 			continue;
29212111Sralph 		}
29312111Sralph 
29412111Sralph 	/* pass 2 */
29512111Sralph 
29612463Sralph pass2:
29712111Sralph 	fseek(cfp, 0L, 0);
29812111Sralph 	while (getline(cfp))
29912111Sralph 		switch (line[0]) {
30012111Sralph 		case 'M':
30112463Sralph 			if (bombed != 2)		/* already sent if 2 */
30212463Sralph 				sendmail(bombed);
30312111Sralph 			continue;
30412111Sralph 
30512111Sralph 		case 'U':
30612111Sralph 			(void) unlink(line+1);
30712111Sralph 		}
30812111Sralph 	/*
30912111Sralph 	 * clean-up incase another control file exists
31012111Sralph 	 */
31112111Sralph 	(void) fclose(cfp);
31212111Sralph 	(void) unlink(file);
31312111Sralph 	return(0);
31412111Sralph }
31512111Sralph 
31612111Sralph /*
31712111Sralph  * Print a file.
31812111Sralph  * Set up the chain [ PR [ | {IF, OF} ] ] or {IF, TF, CF, VF}.
31912111Sralph  * Return -1 if a non-recoverable error occured, 1 if a recoverable error and
32012111Sralph  * 0 if all is well.
32112111Sralph  * Note: all filters take stdin as the file, stdout as the printer,
32212111Sralph  * stderr as the log file, and must not ignore SIGINT.
32312111Sralph  */
32412111Sralph print(format, file)
32512111Sralph 	int format;
32612111Sralph 	char *file;
32712111Sralph {
32812111Sralph 	register int n, fi, fo;
32912111Sralph 	register char *prog;
33012111Sralph 	char *av[15], buf[BUFSIZ];
33112111Sralph 	int pid, p[2], stopped = 0;
33212111Sralph 	union wait status;
33312111Sralph 
33412111Sralph 	if ((fi = open(file, FRDONLY, 0)) < 0) {
33512111Sralph 		log("%s: open failure <errno = %d>", file, errno);
33612111Sralph 		return(-1);
33712111Sralph 	}
33812111Sralph 	if (!SF && !tof) {		/* start on a fresh page */
33912111Sralph 		(void) write(ofd, FF, strlen(FF));
34012111Sralph 		tof = 1;
34112111Sralph 	}
34212111Sralph 	if (IF == NULL && (format == 'f' || format == 'l')) {
34312111Sralph 		tof = 0;
34412111Sralph 		while ((n = read(fi, buf, BUFSIZ)) > 0)
34512111Sralph 			if (write(ofd, buf, n) != n) {
34612111Sralph 				(void) close(fi);
34712111Sralph 				return(1);
34812111Sralph 			}
34912111Sralph 		(void) close(fi);
35012111Sralph 		return(0);
35112111Sralph 	}
35212111Sralph 	switch (format) {
35312111Sralph 	case 'p':	/* print file using 'pr' */
35412111Sralph 		if (IF == NULL) {	/* use output filter */
35512111Sralph 			prog = PR;
35612111Sralph 			av[0] = "pr";
35712111Sralph 			av[1] = width;
35812111Sralph 			av[2] = length;
35912111Sralph 			av[3] = "-h";
36012111Sralph 			av[4] = *title ? title : " ";
36112111Sralph 			av[5] = 0;
36212111Sralph 			fo = ofd;
36312111Sralph 			goto start;
36412111Sralph 		}
36512111Sralph 		pipe(p);
36612111Sralph 		if ((prchild = dofork(DORETURN)) == 0) {	/* child */
36712111Sralph 			dup2(fi, 0);		/* file is stdin */
36812111Sralph 			dup2(p[1], 1);		/* pipe is stdout */
36912111Sralph 			for (n = 3; n < NOFILE; n++)
37012111Sralph 				(void) close(n);
37112111Sralph 			execl(PR, "pr", width, length, "-h", *title ? title : " ", 0);
37212111Sralph 			log("cannot execl %s", PR);
37312111Sralph 			exit(2);
37412111Sralph 		}
37512111Sralph 		(void) close(p[1]);		/* close output side */
37612111Sralph 		(void) close(fi);
37712111Sralph 		if (prchild < 0) {
37812111Sralph 			prchild = 0;
37912111Sralph 			(void) close(p[0]);
38012111Sralph 			return(-1);
38112111Sralph 		}
38212111Sralph 		fi = p[0];			/* use pipe for input */
38312111Sralph 	case 'f':	/* print plain text file */
38412111Sralph 		prog = IF;
38512111Sralph 		av[1] = width;
38612111Sralph 		av[2] = length;
387*12581Sralph 		av[3] = indent;
388*12581Sralph 		n = 4;
38912111Sralph 		break;
39012111Sralph 	case 'l':	/* like 'f' but pass control characters */
39112111Sralph 		prog = IF;
39212111Sralph 		av[1] = "-l";
39312111Sralph 		av[2] = width;
39412111Sralph 		av[3] = length;
395*12581Sralph 		av[4] = indent;
396*12581Sralph 		n = 5;
39712111Sralph 		break;
39812463Sralph 	case 'r':	/* print a fortran text file */
39912463Sralph 		prog = RF;
40012463Sralph 		av[1] = width;
40112463Sralph 		av[2] = length;
40212463Sralph 		n = 3;
40312463Sralph 		break;
40412111Sralph 	case 't':	/* print troff output */
40512463Sralph 	case 'd':	/* print tex output */
40612111Sralph 		(void) unlink(".railmag");
40712463Sralph 		if ((fo = creat(".railmag", FILMOD)) < 0) {
40812111Sralph 			log("cannot create .railmag");
40912111Sralph 			(void) unlink(".railmag");
41012111Sralph 		} else {
41112111Sralph 			for (n = 0; n < 4; n++) {
41212111Sralph 				if (fonts[n][0] != '/')
41312111Sralph 					(void) write(fo, "/usr/lib/vfont/", 15);
41412111Sralph 				(void) write(fo, fonts[n], strlen(fonts[n]));
41512111Sralph 				(void) write(fo, "\n", 1);
41612111Sralph 			}
41712111Sralph 			(void) close(fo);
41812111Sralph 		}
41912111Sralph 		prog = (format == 't') ? TF : DF;
42012463Sralph 		av[1] = pxwidth;
42112463Sralph 		av[2] = pxlength;
42212463Sralph 		n = 3;
42312111Sralph 		break;
42412111Sralph 	case 'c':	/* print cifplot output */
42512111Sralph 		prog = CF;
42612463Sralph 		av[1] = pxwidth;
42712463Sralph 		av[2] = pxlength;
42812463Sralph 		n = 3;
42912111Sralph 		break;
43012111Sralph 	case 'g':	/* print plot(1G) output */
43112111Sralph 		prog = GF;
43212463Sralph 		av[1] = pxwidth;
43312463Sralph 		av[2] = pxlength;
43412463Sralph 		n = 3;
43512111Sralph 		break;
43612111Sralph 	case 'v':	/* print raster output */
43712111Sralph 		prog = VF;
43812463Sralph 		av[1] = pxwidth;
43912463Sralph 		av[2] = pxlength;
44012463Sralph 		n = 3;
44112111Sralph 		break;
44212111Sralph 	default:
44312111Sralph 		(void) close(fi);
44412111Sralph 		log("illegal format character '%c'", format);
44512111Sralph 		return(-1);
44612111Sralph 	}
44712111Sralph 	if ((av[0] = rindex(prog, '/')) != NULL)
44812111Sralph 		av[0]++;
44912111Sralph 	else
45012111Sralph 		av[0] = prog;
45112111Sralph 	av[n++] = "-n";
45212111Sralph 	av[n++] = logname;
45312111Sralph 	av[n++] = "-h";
45412111Sralph 	av[n++] = host;
45512111Sralph 	av[n++] = AF;
45612111Sralph 	av[n] = 0;
45712111Sralph 	fo = pfd;
45812111Sralph 	if (ofilter > 0) {		/* stop output filter */
45912111Sralph 		write(ofd, "\031\1", 2);
46012111Sralph 		while ((pid = wait3(&status, WUNTRACED, 0)) > 0 && pid != ofilter)
46112111Sralph 			;
46212111Sralph 		if (status.w_stopval != WSTOPPED) {
46312111Sralph 			(void) close(fi);
46412111Sralph 			log("output filter died (%d)", status.w_retcode);
46512111Sralph 			return(1);
46612111Sralph 		}
46712111Sralph 		stopped++;
46812111Sralph 	}
46912111Sralph start:
47012111Sralph 	if ((child = dofork(DORETURN)) == 0) {	/* child */
47112111Sralph 		dup2(fi, 0);
47212111Sralph 		dup2(fo, 1);
47312111Sralph 		for (n = 3; n < NOFILE; n++)
47412111Sralph 			(void) close(n);
47512111Sralph 		execv(prog, av);
47612111Sralph 		log("cannot execl %s", prog);
47712111Sralph 		exit(2);
47812111Sralph 	}
47912111Sralph 	(void) close(fi);
48012111Sralph 	if (child < 0)
48112111Sralph 		status.w_retcode = 100;
48212111Sralph 	else
48312111Sralph 		while ((pid = wait(&status)) > 0 && pid != child)
48412111Sralph 			;
48512111Sralph 	child = 0;
48612111Sralph 	prchild = 0;
48712111Sralph 	if (stopped) {		/* restart output filter */
48812111Sralph 		if (kill(ofilter, SIGCONT) < 0) {
48912111Sralph 			log("cannot restart output filter");
49012111Sralph 			exit(1);
49112111Sralph 		}
49212111Sralph 	}
49312111Sralph 	tof = 0;
49412111Sralph 	if (!WIFEXITED(status) || status.w_retcode > 1) {
49512111Sralph 		log("Daemon Filter '%c' Malfunction (%d)", format, status.w_retcode);
49612111Sralph 		return(-1);
49712111Sralph 	} else if (status.w_retcode == 1)
49812111Sralph 		return(1);
49912111Sralph 	tof = 1;
50012111Sralph 	return(0);
50112111Sralph }
50212111Sralph 
50312111Sralph /*
50412111Sralph  * Send the daemon control file (cf) and any data files.
50512111Sralph  * Return -1 if a non-recoverable error occured, 1 if a recoverable error and
50612111Sralph  * 0 if all is well.
50712111Sralph  */
50812111Sralph sendit(file)
50912111Sralph 	char *file;
51012111Sralph {
51112111Sralph 	register int linelen, err = 0;
51212111Sralph 	char last[132];
51312111Sralph 
51412111Sralph 	/*
51512111Sralph 	 * open control file
51612111Sralph 	 */
51712111Sralph 	if ((cfp = fopen(file, "r")) == NULL) {
51812111Sralph 		log("control file (%s) open failure <errno = %d>", file, errno);
51912111Sralph 		return(0);
52012111Sralph 	}
52112111Sralph 	/*
52212111Sralph 	 *      read the control file for work to do
52312111Sralph 	 *
52412111Sralph 	 *      file format -- first character in the line is a command
52512111Sralph 	 *      rest of the line is the argument.
52612111Sralph 	 *      commands of interest are:
52712111Sralph 	 *
52812111Sralph 	 *            a-z -- "file name" name of file to print
52912111Sralph 	 *              U -- "unlink" name of file to remove
53012111Sralph 	 *                    (after we print it. (Pass 2 only)).
53112111Sralph 	 */
53212111Sralph 
53312111Sralph 	/*
53412111Sralph 	 * pass 1
53512111Sralph 	 */
53612111Sralph 	while (getline(cfp)) {
53712111Sralph 	again:
53812111Sralph 		if (line[0] >= 'a' && line[0] <= 'z') {
53912111Sralph 			strcpy(last, line);
54012111Sralph 			while (linelen = getline(cfp))
54112111Sralph 				if (strcmp(last, line))
54212111Sralph 					break;
54312111Sralph 			if ((err = sendfile('\3', last+1)) > 0) {
54412111Sralph 				(void) fclose(cfp);
54512111Sralph 				return(1);
54612111Sralph 			} else if (err)
54712111Sralph 				break;
54812111Sralph 			if (linelen)
54912111Sralph 				goto again;
55012111Sralph 			break;
55112111Sralph 		}
55212111Sralph 	}
55312111Sralph 	if (!err && sendfile('\2', file) > 0) {
55412111Sralph 		(void) fclose(cfp);
55512111Sralph 		return(1);
55612111Sralph 	}
55712111Sralph 	/*
55812111Sralph 	 * pass 2
55912111Sralph 	 */
56012111Sralph 	fseek(cfp, 0L, 0);
56112111Sralph 	while (getline(cfp))
56212111Sralph 		if (line[0] == 'U')
56312111Sralph 			(void) unlink(line+1);
56412111Sralph 	/*
56512111Sralph 	 * clean-up incase another control file exists
56612111Sralph 	 */
56712111Sralph 	(void) fclose(cfp);
56812111Sralph 	(void) unlink(file);
56912111Sralph 	return(0);
57012111Sralph }
57112111Sralph 
57212111Sralph /*
57312111Sralph  * Send a data file to the remote machine and spool it.
57412111Sralph  * Return positive if we should try resending.
57512111Sralph  */
57612111Sralph sendfile(type, file)
57712111Sralph 	char type, *file;
57812111Sralph {
57912111Sralph 	register int f, i, amt;
58012111Sralph 	struct stat stb;
58112111Sralph 	char buf[BUFSIZ];
58212111Sralph 	int sizerr;
58312111Sralph 
58412111Sralph 	if ((f = open(file, FRDONLY, 0)) < 0 || fstat(f, &stb) < 0) {
58512111Sralph 		log("file (%s) open failure <errno = %d>", file, errno);
58612111Sralph 		return(-1);
58712111Sralph 	}
58812111Sralph 	(void) sprintf(buf, "%c%d %s\n", type, stb.st_size, file);
58912111Sralph 	amt = strlen(buf);
59012111Sralph 	if (write(pfd, buf, amt) != amt)
59112111Sralph 		return(1);
59212111Sralph 	if (noresponse())
59312111Sralph 		return(1);
59412111Sralph 	sizerr = 0;
59512111Sralph 	for (i = 0; i < stb.st_size; i += BUFSIZ) {
59612111Sralph 		amt = BUFSIZ;
59712111Sralph 		if (i + amt > stb.st_size)
59812111Sralph 			amt = stb.st_size - i;
59912111Sralph 		if (sizerr == 0 && read(f, buf, amt) != amt)
60012111Sralph 			sizerr = 1;
60112111Sralph 		if (write(pfd, buf, amt) != amt)
60212111Sralph 			return(1);
60312111Sralph 	}
60412111Sralph 	(void) close(f);
60512111Sralph 	if (sizerr) {
60612111Sralph 		log("%s: changed size", file);
60712111Sralph 		(void) write(pfd, "\1", 1);  /* tell recvjob to ignore this file */
60812111Sralph 		return(-1);
60912111Sralph 	}
61012111Sralph 	if (write(pfd, "", 1) != 1)
61112111Sralph 		return(1);
61212111Sralph 	if (noresponse())
61312111Sralph 		return(1);
61412111Sralph 	return(0);
61512111Sralph }
61612111Sralph 
61712111Sralph /*
61812111Sralph  * Check to make sure there have been no errors and that both programs
61912111Sralph  * are in sync with eachother.
62012111Sralph  * Return non-zero if the connection was lost.
62112111Sralph  */
62212111Sralph static
62312111Sralph noresponse()
62412111Sralph {
62512111Sralph 	char resp;
62612111Sralph 
62712111Sralph 	if (read(pfd, &resp, 1) != 1 || resp != '\0') {
62812111Sralph 		log("lost connection or error in recvjob");
62912111Sralph 		return(1);
63012111Sralph 	}
63112111Sralph 	return(0);
63212111Sralph }
63312111Sralph 
63412111Sralph /*
63512111Sralph  * Banner printing stuff
63612111Sralph  */
63712111Sralph banner(name1, name2)
63812111Sralph 	char *name1, *name2;
63912111Sralph {
64012111Sralph 	time_t tvec;
64112111Sralph 	extern char *ctime();
64212111Sralph 
64312111Sralph 	time(&tvec);
64412111Sralph 	if (!SF && !tof)
64512111Sralph 		(void) write(ofd, FF, strlen(FF));
64612111Sralph 	if (SB) {	/* short banner only */
64712111Sralph 		if (class[0]) {
64812111Sralph 			(void) write(ofd, class, strlen(class));
64912111Sralph 			(void) write(ofd, ":", 1);
65012111Sralph 		}
65112111Sralph 		(void) write(ofd, name1, strlen(name1));
65212111Sralph 		(void) write(ofd, "  Job: ", 7);
65312111Sralph 		(void) write(ofd, name2, strlen(name2));
65412111Sralph 		(void) write(ofd, "  Date: ", 8);
65512111Sralph 		(void) write(ofd, ctime(&tvec), 24);
65612111Sralph 		(void) write(ofd, "\n", 1);
65712111Sralph 	} else {	/* normal banner */
65812111Sralph 		(void) write(ofd, "\n\n\n", 3);
65912111Sralph 		scan_out(ofd, name1, '\0');
66012111Sralph 		(void) write(ofd, "\n\n", 2);
66112111Sralph 		scan_out(ofd, name2, '\0');
66212111Sralph 		if (class[0]) {
66312111Sralph 			(void) write(ofd,"\n\n\n",3);
66412111Sralph 			scan_out(ofd, class, '\0');
66512111Sralph 		}
66612111Sralph 		(void) write(ofd, "\n\n\n\n\t\t\t\t\tJob:  ", 15);
66712111Sralph 		(void) write(ofd, name2, strlen(name2));
66812111Sralph 		(void) write(ofd, "\n\t\t\t\t\tDate: ", 12);
66912111Sralph 		(void) write(ofd, ctime(&tvec), 24);
67012111Sralph 		(void) write(ofd, "\n", 1);
67112111Sralph 	}
67212111Sralph 	if (!SF)
67312111Sralph 		(void) write(ofd, FF, strlen(FF));
67412111Sralph 	tof = 1;
67512111Sralph }
67612111Sralph 
67712111Sralph char *
67812111Sralph scnline(key, p, c)
67912111Sralph 	register char key, *p;
68012111Sralph 	char c;
68112111Sralph {
68212111Sralph 	register scnwidth;
68312111Sralph 
68412111Sralph 	for (scnwidth = WIDTH; --scnwidth;) {
68512111Sralph 		key <<= 1;
68612111Sralph 		*p++ = key & 0200 ? c : BACKGND;
68712111Sralph 	}
68812111Sralph 	return (p);
68912111Sralph }
69012111Sralph 
69112111Sralph #define TRC(q)	(((q)-' ')&0177)
69212111Sralph 
69312111Sralph scan_out(scfd, scsp, dlm)
69412111Sralph 	int scfd;
69512111Sralph 	char *scsp, dlm;
69612111Sralph {
69712111Sralph 	register char *strp;
69812111Sralph 	register nchrs, j;
69912111Sralph 	char outbuf[LINELEN+1], *sp, c, cc;
70012111Sralph 	int d, scnhgt;
70112111Sralph 	extern char scnkey[][HEIGHT];	/* in lpdchar.c */
70212111Sralph 
70312111Sralph 	for (scnhgt = 0; scnhgt++ < HEIGHT+DROP; ) {
70412111Sralph 		strp = &outbuf[0];
70512111Sralph 		sp = scsp;
70612111Sralph 		for (nchrs = 0; ; ) {
70712111Sralph 			d = dropit(c = TRC(cc = *sp++));
70812111Sralph 			if ((!d && scnhgt > HEIGHT) || (scnhgt <= DROP && d))
70912111Sralph 				for (j = WIDTH; --j;)
71012111Sralph 					*strp++ = BACKGND;
71112111Sralph 			else
71212111Sralph 				strp = scnline(scnkey[c][scnhgt-1-d], strp, cc);
71312111Sralph 			if (*sp == dlm || *sp == '\0' || nchrs++ >= PW/(WIDTH+1)-1)
71412111Sralph 				break;
71512111Sralph 			*strp++ = BACKGND;
71612111Sralph 			*strp++ = BACKGND;
71712111Sralph 		}
71812111Sralph 		while (*--strp == BACKGND && strp >= outbuf)
71912111Sralph 			;
72012111Sralph 		strp++;
72112111Sralph 		*strp++ = '\n';
72212111Sralph 		(void) write(scfd, outbuf, strp-outbuf);
72312111Sralph 	}
72412111Sralph }
72512111Sralph 
72612111Sralph dropit(c)
72712111Sralph 	char c;
72812111Sralph {
72912111Sralph 	switch(c) {
73012111Sralph 
73112111Sralph 	case TRC('_'):
73212111Sralph 	case TRC(';'):
73312111Sralph 	case TRC(','):
73412111Sralph 	case TRC('g'):
73512111Sralph 	case TRC('j'):
73612111Sralph 	case TRC('p'):
73712111Sralph 	case TRC('q'):
73812111Sralph 	case TRC('y'):
73912111Sralph 		return (DROP);
74012111Sralph 
74112111Sralph 	default:
74212111Sralph 		return (0);
74312111Sralph 	}
74412111Sralph }
74512111Sralph 
74612111Sralph /*
74712111Sralph  * sendmail ---
74812111Sralph  *   tell people about job completion
74912111Sralph  */
75012111Sralph sendmail(bombed)
75112111Sralph 	int bombed;
75212111Sralph {
75312111Sralph 	static int p[2];
75412111Sralph 	register int i;
75512111Sralph 	int stat;
75612111Sralph 	register char *cp;
75712111Sralph 	char buf[100];
75812111Sralph 
75912111Sralph 	pipe(p);
76012111Sralph 	if ((stat = dofork(DORETURN)) == 0) {		/* child */
76112111Sralph 		dup2(p[0], 0);
76212111Sralph 		for (i = 3; i < NOFILE; i++)
76312111Sralph 			(void) close(i);
76412111Sralph 		if ((cp = rindex(MAIL, '/')) != NULL)
76512111Sralph 			cp++;
76612111Sralph 		else
76712111Sralph 			cp = MAIL;
76812111Sralph 		sprintf(buf, "%s@%s", line+1, host);
76912111Sralph 		execl(MAIL, cp, buf, 0);
77012111Sralph 		exit(0);
77112111Sralph 	} else if (stat > 0) {				/* parent */
77212111Sralph 		dup2(p[1], 1);
77312111Sralph 		printf("To: %s\n", line+1);
77412111Sralph 		printf("Subject: printer job\n\n");
77512111Sralph 		printf("Your printer job ");
77612111Sralph 		if (*jobname)
77712111Sralph 			printf("(%s) ", jobname);
77812463Sralph 		switch (bombed) {
77912463Sralph 		case 0:
78012463Sralph 			printf("\ncompleted successfully\n");
78112463Sralph 			break;
78212463Sralph 		default:
78312463Sralph 		case 1:
78412463Sralph 			printf("\ncould not be printed\n");
78512463Sralph 			break;
78612463Sralph 		case 2:
78712463Sralph 			printf("\ncould not be printed without an account on %s\n", host);
78812463Sralph 			break;
78912463Sralph 		}
79012111Sralph 		fflush(stdout);
79112111Sralph 		(void) close(1);
79212111Sralph 	}
79312111Sralph 	(void) close(p[0]);
79412111Sralph 	(void) close(p[1]);
79512111Sralph 	wait(&stat);
79612111Sralph }
79712111Sralph 
79812111Sralph /*
79912111Sralph  * dofork - fork with retries on failure
80012111Sralph  */
80112111Sralph dofork(action)
80212111Sralph 	int action;
80312111Sralph {
80412111Sralph 	register int i, pid;
80512111Sralph 
80612111Sralph 	for (i = 0; i < 20; i++) {
80712463Sralph 		if ((pid = fork()) < 0) {
80812111Sralph 			sleep((unsigned)(i*i));
80912463Sralph 			continue;
81012463Sralph 		}
81112463Sralph 		/*
81212463Sralph 		 * Child should run as daemon instead of root
81312463Sralph 		 */
81412463Sralph 		if (pid == 0)
81512463Sralph 			setuid(DU);
81612463Sralph 		return(pid);
81712111Sralph 	}
81812111Sralph 	log("can't fork");
81912111Sralph 
82012111Sralph 	switch (action) {
82112111Sralph 	case DORETURN:
82212111Sralph 		return (-1);
82312111Sralph 	default:
82412111Sralph 		log("bad action (%d) to dofork", action);
82512111Sralph 		/*FALL THRU*/
82612111Sralph 	case DOABORT:
82712111Sralph 		exit(1);
82812111Sralph 	}
82912111Sralph 	/*NOTREACHED*/
83012111Sralph }
83112111Sralph 
83212111Sralph /*
83312111Sralph  * Cleanup child processes when a SIGINT is caught.
83412111Sralph  */
83512111Sralph onintr()
83612111Sralph {
83712111Sralph 	kill(0, SIGINT);
83812111Sralph 	if (ofilter > 0)
83912111Sralph 		kill(ofilter, SIGCONT);
84012111Sralph 	while (wait(0) > 0)
84112111Sralph 		;
84212111Sralph 	exit(0);
84312111Sralph }
84412111Sralph 
84512111Sralph init()
84612111Sralph {
84712111Sralph 	int status;
84812111Sralph 
84912111Sralph 	if ((status = pgetent(line, printer)) < 0) {
85012111Sralph 		log("can't open printer description file");
85112111Sralph 		exit(1);
85212111Sralph 	} else if (status == 0) {
85312111Sralph 		log("unknown printer");
85412111Sralph 		exit(1);
85512111Sralph 	}
85612111Sralph 	if ((LP = pgetstr("lp", &bp)) == NULL)
85712111Sralph 		LP = DEFDEVLP;
85812111Sralph 	if ((RP = pgetstr("rp", &bp)) == NULL)
85912463Sralph 		RP = DEFLP;
86012111Sralph 	if ((LO = pgetstr("lo", &bp)) == NULL)
86112111Sralph 		LO = DEFLOCK;
86212111Sralph 	if ((ST = pgetstr("st", &bp)) == NULL)
86312111Sralph 		ST = DEFSTAT;
86412111Sralph 	if ((LF = pgetstr("lf", &bp)) == NULL)
86512111Sralph 		LF = DEFLOGF;
86612111Sralph 	if ((SD = pgetstr("sd", &bp)) == NULL)
86712111Sralph 		SD = DEFSPOOL;
86812111Sralph 	if ((DU = pgetnum("du")) < 0)
86912111Sralph 		DU = DEFUID;
87012111Sralph 	if ((FF = pgetstr("ff", &bp)) == NULL)
87112111Sralph 		FF = DEFFF;
87212111Sralph 	if ((PW = pgetnum("pw")) < 0)
87312111Sralph 		PW = DEFWIDTH;
87412111Sralph 	sprintf(&width[2], "%d", PW);
87512111Sralph 	if ((PL = pgetnum("pl")) < 0)
87612111Sralph 		PL = DEFLENGTH;
87712111Sralph 	sprintf(&length[2], "%d", PL);
87812463Sralph 	if ((PX = pgetnum("px")) < 0)
87912463Sralph 		PX = 0;
88012463Sralph 	sprintf(&pxwidth[2], "%d", PX);
88112463Sralph 	if ((PY = pgetnum("py")) < 0)
88212463Sralph 		PY = 0;
88312463Sralph 	sprintf(&pxlength[2], "%d", PY);
88412111Sralph 	RM = pgetstr("rm", &bp);
88512111Sralph 	AF = pgetstr("af", &bp);
88612111Sralph 	OF = pgetstr("of", &bp);
88712111Sralph 	IF = pgetstr("if", &bp);
88812463Sralph 	RF = pgetstr("rf", &bp);
88912111Sralph 	TF = pgetstr("tf", &bp);
89012111Sralph 	DF = pgetstr("df", &bp);
89112111Sralph 	GF = pgetstr("gf", &bp);
89212111Sralph 	VF = pgetstr("vf", &bp);
89312111Sralph 	CF = pgetstr("cf", &bp);
89412111Sralph 	TR = pgetstr("tr", &bp);
89512463Sralph 	RS = pgetflag("rs");
89612111Sralph 	SF = pgetflag("sf");
89712111Sralph 	SH = pgetflag("sh");
89812111Sralph 	SB = pgetflag("sb");
89912111Sralph 	RW = pgetflag("rw");
90012111Sralph 	BR = pgetnum("br");
90112111Sralph 	if ((FC = pgetnum("fc")) < 0)
90212111Sralph 		FC = 0;
90312111Sralph 	if ((FS = pgetnum("fs")) < 0)
90412111Sralph 		FS = 0;
90512111Sralph 	if ((XC = pgetnum("xc")) < 0)
90612111Sralph 		XC = 0;
90712111Sralph 	if ((XS = pgetnum("xs")) < 0)
90812111Sralph 		XS = 0;
909*12581Sralph 	tof = !pgetflag("fo");
91012111Sralph }
91112111Sralph 
91212463Sralph /*
91312463Sralph  * Acquire line printer or remote connection.
91412463Sralph  */
91512463Sralph openpr()
91612463Sralph {
91712463Sralph 	register int i, n;
91812463Sralph 
91912463Sralph 	if (*LP) {
92012463Sralph 		for (i = 1; ; i = i < 32 ? i << 1 : i) {
92112463Sralph 			pfd = open(LP, RW ? FRDWR : FWRONLY, 0);
92212463Sralph 			if (pfd >= 0)
92312463Sralph 				break;
92412463Sralph 			if (errno == ENOENT) {
92512463Sralph 				log("cannot open %s", LP);
92612463Sralph 				exit(1);
92712463Sralph 			}
92812463Sralph 			if (i == 1)
92912463Sralph 				status("waiting for %s to become ready (offline ?)", printer);
93012463Sralph 			sleep(i);
93112463Sralph 		}
93212463Sralph 		if (isatty(pfd))
93312463Sralph 			setty();
93412463Sralph 		status("%s is ready and printing", printer);
93512463Sralph 	} else if (RM != NULL) {
93612463Sralph 		for (i = 1; ; i = i < 512 ? i << 1 : i) {
93712528Sralph 			pfd = getport(RM);
93812463Sralph 			if (pfd >= 0) {
93912463Sralph 				(void) sprintf(line, "\2%s\n", RP);
94012463Sralph 				n = strlen(line);
94112463Sralph 				if (write(pfd, line, n) != n)
94212463Sralph 					break;
94312463Sralph 				if (noresponse())
94412463Sralph 					(void) close(pfd);
94512463Sralph 				else
94612463Sralph 					break;
94712463Sralph 			}
94812463Sralph 			if (i == 1)
94912463Sralph 				status("waiting for %s to come up", RM);
95012463Sralph 			sleep(i);
95112463Sralph 		}
95212463Sralph 		status("sending to %s", RM);
95312463Sralph 		remote = 1;
95412463Sralph 	} else {
95512463Sralph 		log("no line printer device or remote machine name");
95612463Sralph 		exit(1);
95712463Sralph 	}
95812463Sralph 	/*
95912463Sralph 	 * Start up an output filter, if needed.
96012463Sralph 	 */
96112463Sralph 	if (OF) {
96212463Sralph 		int p[2];
96312463Sralph 		char *cp;
96412463Sralph 
96512463Sralph 		pipe(p);
96612463Sralph 		if ((ofilter = dofork(DOABORT)) == 0) {	/* child */
96712463Sralph 			dup2(p[0], 0);		/* pipe is std in */
96812463Sralph 			dup2(pfd, 1);		/* printer is std out */
96912463Sralph 			for (i = 3; i < NOFILE; i++)
97012463Sralph 				(void) close(i);
97112463Sralph 			if ((cp = rindex(OF, '/')) == NULL)
97212463Sralph 				cp = OF;
97312463Sralph 			else
97412463Sralph 				cp++;
97512463Sralph 			execl(OF, cp, width, length, 0);
97612463Sralph 			log("can't execl output filter %s", OF);
97712463Sralph 			exit(1);
97812463Sralph 		}
97912463Sralph 		(void) close(p[0]);		/* close input side */
98012463Sralph 		ofd = p[1];			/* use pipe for output */
98112463Sralph 	} else {
98212463Sralph 		ofd = pfd;
98312463Sralph 		ofilter = 0;
98412463Sralph 	}
98512463Sralph }
98612463Sralph 
98712111Sralph struct bauds {
98812111Sralph 	int	baud;
98912111Sralph 	int	speed;
99012111Sralph } bauds[] = {
99112111Sralph 	50,	B50,
99212111Sralph 	75,	B75,
99312111Sralph 	110,	B110,
99412111Sralph 	134,	B134,
99512111Sralph 	150,	B150,
99612111Sralph 	200,	B200,
99712111Sralph 	300,	B300,
99812111Sralph 	600,	B600,
99912111Sralph 	1200,	B1200,
100012111Sralph 	1800,	B1800,
100112111Sralph 	2400,	B2400,
100212111Sralph 	4800,	B4800,
100312111Sralph 	9600,	B9600,
100412111Sralph 	19200,	EXTA,
100512111Sralph 	38400,	EXTB,
100612111Sralph 	0,	0
100712111Sralph };
100812111Sralph 
100912111Sralph /*
101012111Sralph  * setup tty lines.
101112111Sralph  */
101212111Sralph setty()
101312111Sralph {
101412111Sralph 	struct sgttyb ttybuf;
101512111Sralph 	register struct bauds *bp;
101612111Sralph 
101712111Sralph 	if (ioctl(pfd, TIOCEXCL, (char *)0) < 0) {
101812111Sralph 		log("cannot set exclusive-use");
101912111Sralph 		exit(1);
102012111Sralph 	}
102112111Sralph 	if (ioctl(pfd, TIOCGETP, (char *)&ttybuf) < 0) {
102212111Sralph 		log("cannot get tty parameters");
102312111Sralph 		exit(1);
102412111Sralph 	}
102512111Sralph 	if (BR > 0) {
102612111Sralph 		for (bp = bauds; bp->baud; bp++)
102712111Sralph 			if (BR == bp->baud)
102812111Sralph 				break;
102912111Sralph 		if (!bp->baud) {
103012111Sralph 			log("illegal baud rate %d", BR);
103112111Sralph 			exit(1);
103212111Sralph 		}
103312111Sralph 		ttybuf.sg_ispeed = ttybuf.sg_ospeed = bp->speed;
103412111Sralph 	}
103512111Sralph 	if (FC)
103612111Sralph 		ttybuf.sg_flags &= ~FC;
103712111Sralph 	if (FS)
103812111Sralph 		ttybuf.sg_flags |= FS;
103912111Sralph 	if (ioctl(pfd, TIOCSETP, (char *)&ttybuf) < 0) {
104012111Sralph 		log("cannot set tty parameters");
104112111Sralph 		exit(1);
104212111Sralph 	}
104312111Sralph 	if (XC) {
104412111Sralph 		if (ioctl(pfd, TIOCLBIC, &XC) < 0) {
104512111Sralph 			log("cannot set local tty parameters");
104612111Sralph 			exit(1);
104712111Sralph 		}
104812111Sralph 	}
104912111Sralph 	if (XS) {
105012111Sralph 		if (ioctl(pfd, TIOCLBIS, &XS) < 0) {
105112111Sralph 			log("cannot set local tty parameters");
105212111Sralph 			exit(1);
105312111Sralph 		}
105412111Sralph 	}
105512111Sralph }
105612463Sralph 
105712463Sralph /*VARARGS1*/
105812463Sralph static
105912463Sralph status(msg, a1, a2, a3)
106012463Sralph 	char *msg;
106112463Sralph {
106212463Sralph 	register int fd;
106312463Sralph 	char buf[BUFSIZ];
106412463Sralph 
106512463Sralph 	umask(0);
106612463Sralph 	if ((fd = open(ST, FWRONLY|FCREATE|FTRUNCATE|FEXLOCK, 0664)) < 0)
106712463Sralph 		fatal("cannot create status file");
106812463Sralph 	sprintf(buf, msg, a1, a2, a3);
106912463Sralph 	strcat(buf, "\n");
107012463Sralph 	(void) write(fd, buf, strlen(buf));
107112463Sralph 	(void) close(fd);
107212463Sralph }
1073