xref: /csrg-svn/usr.sbin/lpr/lpd/printjob.c (revision 12692)
1*12692Sralph /*	printjob.c	4.5	83/05/23	*/
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 */
2312581Sralph 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 */
3412581Sralph 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
19812581Sralph 	 *              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 
27512581Sralph 		case 'I':	/* indent amount */
27612581Sralph 			strcpy(indent+2, line+1);
27712581Sralph 			continue;
27812581Sralph 
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;
38712581Sralph 		av[3] = indent;
38812581Sralph 		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;
39512581Sralph 		av[4] = indent;
39612581Sralph 		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);
590*12692Sralph 	if (write(pfd, buf, amt) != amt) {
591*12692Sralph 		(void) close(f);
59212111Sralph 		return(1);
593*12692Sralph 	}
594*12692Sralph 	if (noresponse()) {
595*12692Sralph 		(void) close(f);
59612111Sralph 		return(1);
597*12692Sralph 	}
59812111Sralph 	sizerr = 0;
59912111Sralph 	for (i = 0; i < stb.st_size; i += BUFSIZ) {
60012111Sralph 		amt = BUFSIZ;
60112111Sralph 		if (i + amt > stb.st_size)
60212111Sralph 			amt = stb.st_size - i;
60312111Sralph 		if (sizerr == 0 && read(f, buf, amt) != amt)
60412111Sralph 			sizerr = 1;
605*12692Sralph 		if (write(pfd, buf, amt) != amt) {
606*12692Sralph 			(void) close(f);
60712111Sralph 			return(1);
608*12692Sralph 		}
60912111Sralph 	}
61012111Sralph 	(void) close(f);
61112111Sralph 	if (sizerr) {
61212111Sralph 		log("%s: changed size", file);
61312111Sralph 		(void) write(pfd, "\1", 1);  /* tell recvjob to ignore this file */
61412111Sralph 		return(-1);
61512111Sralph 	}
61612111Sralph 	if (write(pfd, "", 1) != 1)
61712111Sralph 		return(1);
61812111Sralph 	if (noresponse())
61912111Sralph 		return(1);
62012111Sralph 	return(0);
62112111Sralph }
62212111Sralph 
62312111Sralph /*
62412111Sralph  * Check to make sure there have been no errors and that both programs
62512111Sralph  * are in sync with eachother.
62612111Sralph  * Return non-zero if the connection was lost.
62712111Sralph  */
62812111Sralph static
62912111Sralph noresponse()
63012111Sralph {
63112111Sralph 	char resp;
63212111Sralph 
63312111Sralph 	if (read(pfd, &resp, 1) != 1 || resp != '\0') {
63412111Sralph 		log("lost connection or error in recvjob");
63512111Sralph 		return(1);
63612111Sralph 	}
63712111Sralph 	return(0);
63812111Sralph }
63912111Sralph 
64012111Sralph /*
64112111Sralph  * Banner printing stuff
64212111Sralph  */
64312111Sralph banner(name1, name2)
64412111Sralph 	char *name1, *name2;
64512111Sralph {
64612111Sralph 	time_t tvec;
64712111Sralph 	extern char *ctime();
64812111Sralph 
64912111Sralph 	time(&tvec);
65012111Sralph 	if (!SF && !tof)
65112111Sralph 		(void) write(ofd, FF, strlen(FF));
65212111Sralph 	if (SB) {	/* short banner only */
65312111Sralph 		if (class[0]) {
65412111Sralph 			(void) write(ofd, class, strlen(class));
65512111Sralph 			(void) write(ofd, ":", 1);
65612111Sralph 		}
65712111Sralph 		(void) write(ofd, name1, strlen(name1));
65812111Sralph 		(void) write(ofd, "  Job: ", 7);
65912111Sralph 		(void) write(ofd, name2, strlen(name2));
66012111Sralph 		(void) write(ofd, "  Date: ", 8);
66112111Sralph 		(void) write(ofd, ctime(&tvec), 24);
66212111Sralph 		(void) write(ofd, "\n", 1);
66312111Sralph 	} else {	/* normal banner */
66412111Sralph 		(void) write(ofd, "\n\n\n", 3);
66512111Sralph 		scan_out(ofd, name1, '\0');
66612111Sralph 		(void) write(ofd, "\n\n", 2);
66712111Sralph 		scan_out(ofd, name2, '\0');
66812111Sralph 		if (class[0]) {
66912111Sralph 			(void) write(ofd,"\n\n\n",3);
67012111Sralph 			scan_out(ofd, class, '\0');
67112111Sralph 		}
67212111Sralph 		(void) write(ofd, "\n\n\n\n\t\t\t\t\tJob:  ", 15);
67312111Sralph 		(void) write(ofd, name2, strlen(name2));
67412111Sralph 		(void) write(ofd, "\n\t\t\t\t\tDate: ", 12);
67512111Sralph 		(void) write(ofd, ctime(&tvec), 24);
67612111Sralph 		(void) write(ofd, "\n", 1);
67712111Sralph 	}
67812111Sralph 	if (!SF)
67912111Sralph 		(void) write(ofd, FF, strlen(FF));
68012111Sralph 	tof = 1;
68112111Sralph }
68212111Sralph 
68312111Sralph char *
68412111Sralph scnline(key, p, c)
68512111Sralph 	register char key, *p;
68612111Sralph 	char c;
68712111Sralph {
68812111Sralph 	register scnwidth;
68912111Sralph 
69012111Sralph 	for (scnwidth = WIDTH; --scnwidth;) {
69112111Sralph 		key <<= 1;
69212111Sralph 		*p++ = key & 0200 ? c : BACKGND;
69312111Sralph 	}
69412111Sralph 	return (p);
69512111Sralph }
69612111Sralph 
69712111Sralph #define TRC(q)	(((q)-' ')&0177)
69812111Sralph 
69912111Sralph scan_out(scfd, scsp, dlm)
70012111Sralph 	int scfd;
70112111Sralph 	char *scsp, dlm;
70212111Sralph {
70312111Sralph 	register char *strp;
70412111Sralph 	register nchrs, j;
70512111Sralph 	char outbuf[LINELEN+1], *sp, c, cc;
70612111Sralph 	int d, scnhgt;
70712111Sralph 	extern char scnkey[][HEIGHT];	/* in lpdchar.c */
70812111Sralph 
70912111Sralph 	for (scnhgt = 0; scnhgt++ < HEIGHT+DROP; ) {
71012111Sralph 		strp = &outbuf[0];
71112111Sralph 		sp = scsp;
71212111Sralph 		for (nchrs = 0; ; ) {
71312111Sralph 			d = dropit(c = TRC(cc = *sp++));
71412111Sralph 			if ((!d && scnhgt > HEIGHT) || (scnhgt <= DROP && d))
71512111Sralph 				for (j = WIDTH; --j;)
71612111Sralph 					*strp++ = BACKGND;
71712111Sralph 			else
71812111Sralph 				strp = scnline(scnkey[c][scnhgt-1-d], strp, cc);
71912111Sralph 			if (*sp == dlm || *sp == '\0' || nchrs++ >= PW/(WIDTH+1)-1)
72012111Sralph 				break;
72112111Sralph 			*strp++ = BACKGND;
72212111Sralph 			*strp++ = BACKGND;
72312111Sralph 		}
72412111Sralph 		while (*--strp == BACKGND && strp >= outbuf)
72512111Sralph 			;
72612111Sralph 		strp++;
72712111Sralph 		*strp++ = '\n';
72812111Sralph 		(void) write(scfd, outbuf, strp-outbuf);
72912111Sralph 	}
73012111Sralph }
73112111Sralph 
73212111Sralph dropit(c)
73312111Sralph 	char c;
73412111Sralph {
73512111Sralph 	switch(c) {
73612111Sralph 
73712111Sralph 	case TRC('_'):
73812111Sralph 	case TRC(';'):
73912111Sralph 	case TRC(','):
74012111Sralph 	case TRC('g'):
74112111Sralph 	case TRC('j'):
74212111Sralph 	case TRC('p'):
74312111Sralph 	case TRC('q'):
74412111Sralph 	case TRC('y'):
74512111Sralph 		return (DROP);
74612111Sralph 
74712111Sralph 	default:
74812111Sralph 		return (0);
74912111Sralph 	}
75012111Sralph }
75112111Sralph 
75212111Sralph /*
75312111Sralph  * sendmail ---
75412111Sralph  *   tell people about job completion
75512111Sralph  */
75612111Sralph sendmail(bombed)
75712111Sralph 	int bombed;
75812111Sralph {
75912111Sralph 	static int p[2];
76012111Sralph 	register int i;
76112111Sralph 	int stat;
76212111Sralph 	register char *cp;
76312111Sralph 	char buf[100];
76412111Sralph 
76512111Sralph 	pipe(p);
76612111Sralph 	if ((stat = dofork(DORETURN)) == 0) {		/* child */
76712111Sralph 		dup2(p[0], 0);
76812111Sralph 		for (i = 3; i < NOFILE; i++)
76912111Sralph 			(void) close(i);
77012111Sralph 		if ((cp = rindex(MAIL, '/')) != NULL)
77112111Sralph 			cp++;
77212111Sralph 		else
77312111Sralph 			cp = MAIL;
77412111Sralph 		sprintf(buf, "%s@%s", line+1, host);
77512111Sralph 		execl(MAIL, cp, buf, 0);
77612111Sralph 		exit(0);
77712111Sralph 	} else if (stat > 0) {				/* parent */
77812111Sralph 		dup2(p[1], 1);
77912111Sralph 		printf("To: %s\n", line+1);
78012111Sralph 		printf("Subject: printer job\n\n");
78112111Sralph 		printf("Your printer job ");
78212111Sralph 		if (*jobname)
78312111Sralph 			printf("(%s) ", jobname);
78412463Sralph 		switch (bombed) {
78512463Sralph 		case 0:
78612463Sralph 			printf("\ncompleted successfully\n");
78712463Sralph 			break;
78812463Sralph 		default:
78912463Sralph 		case 1:
79012463Sralph 			printf("\ncould not be printed\n");
79112463Sralph 			break;
79212463Sralph 		case 2:
79312463Sralph 			printf("\ncould not be printed without an account on %s\n", host);
79412463Sralph 			break;
79512463Sralph 		}
79612111Sralph 		fflush(stdout);
79712111Sralph 		(void) close(1);
79812111Sralph 	}
79912111Sralph 	(void) close(p[0]);
80012111Sralph 	(void) close(p[1]);
80112111Sralph 	wait(&stat);
80212111Sralph }
80312111Sralph 
80412111Sralph /*
80512111Sralph  * dofork - fork with retries on failure
80612111Sralph  */
80712111Sralph dofork(action)
80812111Sralph 	int action;
80912111Sralph {
81012111Sralph 	register int i, pid;
81112111Sralph 
81212111Sralph 	for (i = 0; i < 20; i++) {
81312463Sralph 		if ((pid = fork()) < 0) {
81412111Sralph 			sleep((unsigned)(i*i));
81512463Sralph 			continue;
81612463Sralph 		}
81712463Sralph 		/*
81812463Sralph 		 * Child should run as daemon instead of root
81912463Sralph 		 */
82012463Sralph 		if (pid == 0)
82112463Sralph 			setuid(DU);
82212463Sralph 		return(pid);
82312111Sralph 	}
82412111Sralph 	log("can't fork");
82512111Sralph 
82612111Sralph 	switch (action) {
82712111Sralph 	case DORETURN:
82812111Sralph 		return (-1);
82912111Sralph 	default:
83012111Sralph 		log("bad action (%d) to dofork", action);
83112111Sralph 		/*FALL THRU*/
83212111Sralph 	case DOABORT:
83312111Sralph 		exit(1);
83412111Sralph 	}
83512111Sralph 	/*NOTREACHED*/
83612111Sralph }
83712111Sralph 
83812111Sralph /*
83912111Sralph  * Cleanup child processes when a SIGINT is caught.
84012111Sralph  */
84112111Sralph onintr()
84212111Sralph {
84312111Sralph 	kill(0, SIGINT);
84412111Sralph 	if (ofilter > 0)
84512111Sralph 		kill(ofilter, SIGCONT);
84612111Sralph 	while (wait(0) > 0)
84712111Sralph 		;
84812111Sralph 	exit(0);
84912111Sralph }
85012111Sralph 
85112111Sralph init()
85212111Sralph {
85312111Sralph 	int status;
85412111Sralph 
85512111Sralph 	if ((status = pgetent(line, printer)) < 0) {
85612111Sralph 		log("can't open printer description file");
85712111Sralph 		exit(1);
85812111Sralph 	} else if (status == 0) {
85912111Sralph 		log("unknown printer");
86012111Sralph 		exit(1);
86112111Sralph 	}
86212111Sralph 	if ((LP = pgetstr("lp", &bp)) == NULL)
86312111Sralph 		LP = DEFDEVLP;
86412111Sralph 	if ((RP = pgetstr("rp", &bp)) == NULL)
86512463Sralph 		RP = DEFLP;
86612111Sralph 	if ((LO = pgetstr("lo", &bp)) == NULL)
86712111Sralph 		LO = DEFLOCK;
86812111Sralph 	if ((ST = pgetstr("st", &bp)) == NULL)
86912111Sralph 		ST = DEFSTAT;
87012111Sralph 	if ((LF = pgetstr("lf", &bp)) == NULL)
87112111Sralph 		LF = DEFLOGF;
87212111Sralph 	if ((SD = pgetstr("sd", &bp)) == NULL)
87312111Sralph 		SD = DEFSPOOL;
87412111Sralph 	if ((DU = pgetnum("du")) < 0)
87512111Sralph 		DU = DEFUID;
87612111Sralph 	if ((FF = pgetstr("ff", &bp)) == NULL)
87712111Sralph 		FF = DEFFF;
87812111Sralph 	if ((PW = pgetnum("pw")) < 0)
87912111Sralph 		PW = DEFWIDTH;
88012111Sralph 	sprintf(&width[2], "%d", PW);
88112111Sralph 	if ((PL = pgetnum("pl")) < 0)
88212111Sralph 		PL = DEFLENGTH;
88312111Sralph 	sprintf(&length[2], "%d", PL);
88412463Sralph 	if ((PX = pgetnum("px")) < 0)
88512463Sralph 		PX = 0;
88612463Sralph 	sprintf(&pxwidth[2], "%d", PX);
88712463Sralph 	if ((PY = pgetnum("py")) < 0)
88812463Sralph 		PY = 0;
88912463Sralph 	sprintf(&pxlength[2], "%d", PY);
89012111Sralph 	RM = pgetstr("rm", &bp);
89112111Sralph 	AF = pgetstr("af", &bp);
89212111Sralph 	OF = pgetstr("of", &bp);
89312111Sralph 	IF = pgetstr("if", &bp);
89412463Sralph 	RF = pgetstr("rf", &bp);
89512111Sralph 	TF = pgetstr("tf", &bp);
89612111Sralph 	DF = pgetstr("df", &bp);
89712111Sralph 	GF = pgetstr("gf", &bp);
89812111Sralph 	VF = pgetstr("vf", &bp);
89912111Sralph 	CF = pgetstr("cf", &bp);
90012111Sralph 	TR = pgetstr("tr", &bp);
90112463Sralph 	RS = pgetflag("rs");
90212111Sralph 	SF = pgetflag("sf");
90312111Sralph 	SH = pgetflag("sh");
90412111Sralph 	SB = pgetflag("sb");
90512111Sralph 	RW = pgetflag("rw");
90612111Sralph 	BR = pgetnum("br");
90712111Sralph 	if ((FC = pgetnum("fc")) < 0)
90812111Sralph 		FC = 0;
90912111Sralph 	if ((FS = pgetnum("fs")) < 0)
91012111Sralph 		FS = 0;
91112111Sralph 	if ((XC = pgetnum("xc")) < 0)
91212111Sralph 		XC = 0;
91312111Sralph 	if ((XS = pgetnum("xs")) < 0)
91412111Sralph 		XS = 0;
91512581Sralph 	tof = !pgetflag("fo");
91612111Sralph }
91712111Sralph 
91812463Sralph /*
91912463Sralph  * Acquire line printer or remote connection.
92012463Sralph  */
92112463Sralph openpr()
92212463Sralph {
92312463Sralph 	register int i, n;
92412463Sralph 
92512463Sralph 	if (*LP) {
92612463Sralph 		for (i = 1; ; i = i < 32 ? i << 1 : i) {
92712463Sralph 			pfd = open(LP, RW ? FRDWR : FWRONLY, 0);
92812463Sralph 			if (pfd >= 0)
92912463Sralph 				break;
93012463Sralph 			if (errno == ENOENT) {
93112463Sralph 				log("cannot open %s", LP);
93212463Sralph 				exit(1);
93312463Sralph 			}
93412463Sralph 			if (i == 1)
93512463Sralph 				status("waiting for %s to become ready (offline ?)", printer);
93612463Sralph 			sleep(i);
93712463Sralph 		}
93812463Sralph 		if (isatty(pfd))
93912463Sralph 			setty();
94012463Sralph 		status("%s is ready and printing", printer);
94112463Sralph 	} else if (RM != NULL) {
94212463Sralph 		for (i = 1; ; i = i < 512 ? i << 1 : i) {
94312528Sralph 			pfd = getport(RM);
94412463Sralph 			if (pfd >= 0) {
94512463Sralph 				(void) sprintf(line, "\2%s\n", RP);
94612463Sralph 				n = strlen(line);
94712463Sralph 				if (write(pfd, line, n) != n)
94812463Sralph 					break;
94912463Sralph 				if (noresponse())
95012463Sralph 					(void) close(pfd);
95112463Sralph 				else
95212463Sralph 					break;
95312463Sralph 			}
95412463Sralph 			if (i == 1)
95512463Sralph 				status("waiting for %s to come up", RM);
95612463Sralph 			sleep(i);
95712463Sralph 		}
95812463Sralph 		status("sending to %s", RM);
95912463Sralph 		remote = 1;
96012463Sralph 	} else {
96112463Sralph 		log("no line printer device or remote machine name");
96212463Sralph 		exit(1);
96312463Sralph 	}
96412463Sralph 	/*
96512463Sralph 	 * Start up an output filter, if needed.
96612463Sralph 	 */
96712463Sralph 	if (OF) {
96812463Sralph 		int p[2];
96912463Sralph 		char *cp;
97012463Sralph 
97112463Sralph 		pipe(p);
97212463Sralph 		if ((ofilter = dofork(DOABORT)) == 0) {	/* child */
97312463Sralph 			dup2(p[0], 0);		/* pipe is std in */
97412463Sralph 			dup2(pfd, 1);		/* printer is std out */
97512463Sralph 			for (i = 3; i < NOFILE; i++)
97612463Sralph 				(void) close(i);
97712463Sralph 			if ((cp = rindex(OF, '/')) == NULL)
97812463Sralph 				cp = OF;
97912463Sralph 			else
98012463Sralph 				cp++;
98112463Sralph 			execl(OF, cp, width, length, 0);
98212463Sralph 			log("can't execl output filter %s", OF);
98312463Sralph 			exit(1);
98412463Sralph 		}
98512463Sralph 		(void) close(p[0]);		/* close input side */
98612463Sralph 		ofd = p[1];			/* use pipe for output */
98712463Sralph 	} else {
98812463Sralph 		ofd = pfd;
98912463Sralph 		ofilter = 0;
99012463Sralph 	}
99112463Sralph }
99212463Sralph 
99312111Sralph struct bauds {
99412111Sralph 	int	baud;
99512111Sralph 	int	speed;
99612111Sralph } bauds[] = {
99712111Sralph 	50,	B50,
99812111Sralph 	75,	B75,
99912111Sralph 	110,	B110,
100012111Sralph 	134,	B134,
100112111Sralph 	150,	B150,
100212111Sralph 	200,	B200,
100312111Sralph 	300,	B300,
100412111Sralph 	600,	B600,
100512111Sralph 	1200,	B1200,
100612111Sralph 	1800,	B1800,
100712111Sralph 	2400,	B2400,
100812111Sralph 	4800,	B4800,
100912111Sralph 	9600,	B9600,
101012111Sralph 	19200,	EXTA,
101112111Sralph 	38400,	EXTB,
101212111Sralph 	0,	0
101312111Sralph };
101412111Sralph 
101512111Sralph /*
101612111Sralph  * setup tty lines.
101712111Sralph  */
101812111Sralph setty()
101912111Sralph {
102012111Sralph 	struct sgttyb ttybuf;
102112111Sralph 	register struct bauds *bp;
102212111Sralph 
102312111Sralph 	if (ioctl(pfd, TIOCEXCL, (char *)0) < 0) {
102412111Sralph 		log("cannot set exclusive-use");
102512111Sralph 		exit(1);
102612111Sralph 	}
102712111Sralph 	if (ioctl(pfd, TIOCGETP, (char *)&ttybuf) < 0) {
102812111Sralph 		log("cannot get tty parameters");
102912111Sralph 		exit(1);
103012111Sralph 	}
103112111Sralph 	if (BR > 0) {
103212111Sralph 		for (bp = bauds; bp->baud; bp++)
103312111Sralph 			if (BR == bp->baud)
103412111Sralph 				break;
103512111Sralph 		if (!bp->baud) {
103612111Sralph 			log("illegal baud rate %d", BR);
103712111Sralph 			exit(1);
103812111Sralph 		}
103912111Sralph 		ttybuf.sg_ispeed = ttybuf.sg_ospeed = bp->speed;
104012111Sralph 	}
104112111Sralph 	if (FC)
104212111Sralph 		ttybuf.sg_flags &= ~FC;
104312111Sralph 	if (FS)
104412111Sralph 		ttybuf.sg_flags |= FS;
104512111Sralph 	if (ioctl(pfd, TIOCSETP, (char *)&ttybuf) < 0) {
104612111Sralph 		log("cannot set tty parameters");
104712111Sralph 		exit(1);
104812111Sralph 	}
104912111Sralph 	if (XC) {
105012111Sralph 		if (ioctl(pfd, TIOCLBIC, &XC) < 0) {
105112111Sralph 			log("cannot set local tty parameters");
105212111Sralph 			exit(1);
105312111Sralph 		}
105412111Sralph 	}
105512111Sralph 	if (XS) {
105612111Sralph 		if (ioctl(pfd, TIOCLBIS, &XS) < 0) {
105712111Sralph 			log("cannot set local tty parameters");
105812111Sralph 			exit(1);
105912111Sralph 		}
106012111Sralph 	}
106112111Sralph }
106212463Sralph 
106312463Sralph /*VARARGS1*/
106412463Sralph static
106512463Sralph status(msg, a1, a2, a3)
106612463Sralph 	char *msg;
106712463Sralph {
106812463Sralph 	register int fd;
106912463Sralph 	char buf[BUFSIZ];
107012463Sralph 
107112463Sralph 	umask(0);
107212463Sralph 	if ((fd = open(ST, FWRONLY|FCREATE|FTRUNCATE|FEXLOCK, 0664)) < 0)
107312463Sralph 		fatal("cannot create status file");
107412463Sralph 	sprintf(buf, msg, a1, a2, a3);
107512463Sralph 	strcat(buf, "\n");
107612463Sralph 	(void) write(fd, buf, strlen(buf));
107712463Sralph 	(void) close(fd);
107812463Sralph }
1079