xref: /csrg-svn/usr.sbin/lpr/lpd/printjob.c (revision 12111)
1*12111Sralph /*	printjob.c	4.1	83/04/29	*/
2*12111Sralph /*
3*12111Sralph  * printjob -- print jobs in the queue.
4*12111Sralph  *
5*12111Sralph  *	NOTE: the lock file is used to pass information to lpq and lprm.
6*12111Sralph  *	it does not need to be removed because file locks are dynamic.
7*12111Sralph  */
8*12111Sralph 
9*12111Sralph #include "lp.h"
10*12111Sralph 
11*12111Sralph #define DORETURN	0	/* absorb fork error */
12*12111Sralph #define DOABORT		1	/* abort if dofork fails */
13*12111Sralph 
14*12111Sralph char	title[80];		/* ``pr'' title */
15*12111Sralph FILE	*cfp;			/* control file */
16*12111Sralph int	pfd;			/* printer file descriptor */
17*12111Sralph int	ofd;			/* output filter file descriptor */
18*12111Sralph int	lfd;			/* lock file descriptor */
19*12111Sralph int	pid;			/* pid of lpd process */
20*12111Sralph int	prchild;		/* id of pr process */
21*12111Sralph int	child;			/* id of any filters */
22*12111Sralph int	ofilter;		/* id of output filter, if any */
23*12111Sralph int	tof = 1;		/* top of form; init true if open does ff */
24*12111Sralph int	remote;			/* non zero if sending files to remote */
25*12111Sralph 
26*12111Sralph extern	banner();		/* big character printer */
27*12111Sralph char	logname[32];		/* user's login name */
28*12111Sralph char	jobname[32];		/* job or file name */
29*12111Sralph char	class[32];		/* classification field */
30*12111Sralph char	width[10] = "-w";	/* page width for `pr' */
31*12111Sralph char	length[10] = "-l";	/* page length for `pr' */
32*12111Sralph 
33*12111Sralph printjob()
34*12111Sralph {
35*12111Sralph 	struct stat stb;
36*12111Sralph 	register struct queue *q, **qp;
37*12111Sralph 	struct queue **queue;
38*12111Sralph 	register int i, nitems;
39*12111Sralph 	long pidoff;
40*12111Sralph 	extern int onintr();
41*12111Sralph 
42*12111Sralph 	name = "printjob";
43*12111Sralph 	init();					/* set up capabilities */
44*12111Sralph 	(void) close(2);			/* set up log file */
45*12111Sralph 	(void) open(LF, FWRONLY|FAPPEND, 0);
46*12111Sralph 	dup2(2, 1);
47*12111Sralph 	pid = getpid();
48*12111Sralph 	setpgrp(0, pid);
49*12111Sralph 	sigset(SIGINT, onintr);			/* for use with lprm */
50*12111Sralph 
51*12111Sralph 	/*
52*12111Sralph 	 * uses short form file names
53*12111Sralph 	 */
54*12111Sralph 	if (chdir(SD) < 0) {
55*12111Sralph 		log("cannot chdir to %s", SD);
56*12111Sralph 		exit(1);
57*12111Sralph 	}
58*12111Sralph 	if ((lfd = open(LO, FWRONLY|FCREATE|FTRUNCATE|FEXLOCK|FNBLOCK, 0664)) < 0) {
59*12111Sralph 		if (errno == EWOULDBLOCK)	/* active deamon present */
60*12111Sralph 			exit(0);
61*12111Sralph 		log("cannot create %s", LO);
62*12111Sralph 		exit(1);
63*12111Sralph 	}
64*12111Sralph 	/*
65*12111Sralph 	 * write process id for others to know
66*12111Sralph 	 */
67*12111Sralph 	sprintf(line, "%u\n", pid);
68*12111Sralph 	pidoff = i = strlen(line);
69*12111Sralph 	if (write(lfd, line, i) != i)
70*12111Sralph 		log("cannot write daemon pid");
71*12111Sralph 	/*
72*12111Sralph 	 * acquire line printer or remote connection
73*12111Sralph  	 */
74*12111Sralph restart:
75*12111Sralph 	if (*LP) {
76*12111Sralph 		for (i = 1; ; i = i < 32 ? i << 1 : i) {
77*12111Sralph 			pfd = open(LP, RW ? FRDWR : FWRONLY, 0);
78*12111Sralph 			if (pfd >= 0)
79*12111Sralph 				break;
80*12111Sralph 			if (errno == ENOENT) {
81*12111Sralph 				log("cannot open %s", LP);
82*12111Sralph 				exit(1);
83*12111Sralph 			}
84*12111Sralph 			if (i == 1)
85*12111Sralph 				status("waiting for %s to become ready (offline ?)", printer);
86*12111Sralph 			sleep(i);
87*12111Sralph 		}
88*12111Sralph 		if (isatty(pfd))
89*12111Sralph 			setty();
90*12111Sralph 		status("%s is ready and printing", printer);
91*12111Sralph 	} else if (RM != NULL) {
92*12111Sralph 		for (i = 1; ; i = i < 512 ? i << 1 : i) {
93*12111Sralph 			pfd = getport();
94*12111Sralph 			if (pfd >= 0) {
95*12111Sralph 				(void) sprintf(line, "\2%s\n", RP);
96*12111Sralph 				nitems = strlen(line);
97*12111Sralph 				if (write(pfd, line, nitems) != nitems)
98*12111Sralph 					break;
99*12111Sralph 				if (noresponse())
100*12111Sralph 					(void) close(pfd);
101*12111Sralph 				else
102*12111Sralph 					break;
103*12111Sralph 			}
104*12111Sralph 			if (i == 1)
105*12111Sralph 				status("waiting for %s to come up", RM);
106*12111Sralph 			sleep(i);
107*12111Sralph 		}
108*12111Sralph 		status("sending to %s", RM);
109*12111Sralph 		remote = 1;
110*12111Sralph 	} else {
111*12111Sralph 		log("no line printer device or remote machine name");
112*12111Sralph 		exit(1);
113*12111Sralph 	}
114*12111Sralph 	/*
115*12111Sralph 	 * Start running as daemon instead of root
116*12111Sralph 	 */
117*12111Sralph 	setuid(DU);
118*12111Sralph 	/*
119*12111Sralph 	 * Start up an output filter, if needed.
120*12111Sralph 	 */
121*12111Sralph 	if (OF) {
122*12111Sralph 		int p[2];
123*12111Sralph 		char *cp;
124*12111Sralph 
125*12111Sralph 		pipe(p);
126*12111Sralph 		if ((ofilter = dofork(DOABORT)) == 0) {	/* child */
127*12111Sralph 			dup2(p[0], 0);		/* pipe is std in */
128*12111Sralph 			dup2(pfd, 1);		/* printer is std out */
129*12111Sralph 			for (i = 3; i < NOFILE; i++)
130*12111Sralph 				(void) close(i);
131*12111Sralph 			if ((cp = rindex(OF, '/')) == NULL)
132*12111Sralph 				cp = OF;
133*12111Sralph 			else
134*12111Sralph 				cp++;
135*12111Sralph 			execl(OF, cp, 0);
136*12111Sralph 			log("can't execl output filter %s", OF);
137*12111Sralph 			exit(1);
138*12111Sralph 		}
139*12111Sralph 		(void) close(p[0]);		/* close input side */
140*12111Sralph 		ofd = p[1];			/* use pipe for output */
141*12111Sralph 	} else {
142*12111Sralph 		ofd = pfd;
143*12111Sralph 		ofilter = 0;
144*12111Sralph 	}
145*12111Sralph 
146*12111Sralph 	/*
147*12111Sralph 	 * search the spool directory for work and sort by queue order.
148*12111Sralph 	 */
149*12111Sralph again:
150*12111Sralph 	if ((nitems = getq(&queue)) < 0) {
151*12111Sralph 		log("can't scan spool directory %s", SD);
152*12111Sralph 		exit(1);
153*12111Sralph 	}
154*12111Sralph 	if (nitems == 0) {		/* EOF => no work to do */
155*12111Sralph 		if (!SF && !tof)
156*12111Sralph 			(void) write(ofd, FF, strlen(FF));
157*12111Sralph 		if (TR != NULL)		/* output trailer */
158*12111Sralph 			(void) write(ofd, TR, strlen(TR));
159*12111Sralph 		exit(0);
160*12111Sralph 	}
161*12111Sralph 
162*12111Sralph 	/*
163*12111Sralph 	 * we found something to do now do it --
164*12111Sralph 	 *    write the name of the current control file into the lock file
165*12111Sralph 	 *    so the spool queue program can tell what we're working on
166*12111Sralph 	 */
167*12111Sralph 	for (qp = queue; nitems--; free((char *) q)) {
168*12111Sralph 		q = *qp++;
169*12111Sralph 		if (stat(q->q_name, &stb) < 0)
170*12111Sralph 			continue;
171*12111Sralph 		(void) lseek(lfd, pidoff, 0);
172*12111Sralph 		(void) sprintf(line, "%s\n", q->q_name);
173*12111Sralph 		i = strlen(line);
174*12111Sralph 		if (write(lfd, line, i) != i)
175*12111Sralph 			log("can't write (%d) control file name", errno);
176*12111Sralph 		if (!remote)
177*12111Sralph 			i = printit(q->q_name);
178*12111Sralph 		else
179*12111Sralph 			i = sendit(q->q_name);
180*12111Sralph 		if (i > 0) {	/* restart daemon to reprint job */
181*12111Sralph 			log("restarting");
182*12111Sralph 			if (ofilter > 0) {
183*12111Sralph 				kill(ofilter, SIGCONT);	/* to be sure */
184*12111Sralph 				(void) close(ofd);
185*12111Sralph 				while ((i = wait(0)) > 0 && i != ofilter)
186*12111Sralph 					;
187*12111Sralph 				ofilter = 0;
188*12111Sralph 			}
189*12111Sralph 			(void) close(pfd);
190*12111Sralph 			free((char *) q);
191*12111Sralph 			while (nitems--)
192*12111Sralph 				free((char *) *qp++);
193*12111Sralph 			free((char *) queue);
194*12111Sralph 			goto restart;
195*12111Sralph 		}
196*12111Sralph 	}
197*12111Sralph 	free((char *) queue);
198*12111Sralph 	goto again;
199*12111Sralph }
200*12111Sralph 
201*12111Sralph char	fonts[4][50];	/* fonts for troff */
202*12111Sralph 
203*12111Sralph static char ifonts[4][18] = {
204*12111Sralph 	"/usr/lib/vfont/R",
205*12111Sralph 	"/usr/lib/vfont/I",
206*12111Sralph 	"/usr/lib/vfont/B",
207*12111Sralph 	"/usr/lib/vfont/S"
208*12111Sralph };
209*12111Sralph 
210*12111Sralph /*
211*12111Sralph  * The remaining part is the reading of the control file (cf)
212*12111Sralph  * and performing the various actions.
213*12111Sralph  * Returns 0 if everthing was OK, 1 if we should try to reprint the job and
214*12111Sralph  * -1 if a non-recoverable error occured.
215*12111Sralph  */
216*12111Sralph printit(file)
217*12111Sralph 	char *file;
218*12111Sralph {
219*12111Sralph 	register int i;
220*12111Sralph 	int bombed = 0;
221*12111Sralph 
222*12111Sralph 	/*
223*12111Sralph 	 * open control file
224*12111Sralph 	 */
225*12111Sralph 	if ((cfp = fopen(file, "r")) == NULL) {
226*12111Sralph 		log("control file (%s) open failure <errno = %d>", file, errno);
227*12111Sralph 		return(0);
228*12111Sralph 	}
229*12111Sralph 	/*
230*12111Sralph 	 * Reset troff fonts.
231*12111Sralph 	 */
232*12111Sralph 	for (i = 0; i < 4; i++)
233*12111Sralph 		strcpy(fonts[i], ifonts[i]);
234*12111Sralph 
235*12111Sralph 	/*
236*12111Sralph 	 *      read the control file for work to do
237*12111Sralph 	 *
238*12111Sralph 	 *      file format -- first character in the line is a command
239*12111Sralph 	 *      rest of the line is the argument.
240*12111Sralph 	 *      valid commands are:
241*12111Sralph 	 *
242*12111Sralph 	 *		J -- "job name" on banner page
243*12111Sralph 	 *		C -- "class name" on banner page
244*12111Sralph 	 *              L -- "literal" user's name to print on banner
245*12111Sralph 	 *		T -- "title" for pr
246*12111Sralph 	 *		H -- "host name" of machine where lpr was done
247*12111Sralph 	 *              P -- "person" user's login name
248*12111Sralph 	 *              I -- "indent" changes default indents driver
249*12111Sralph 	 *                   must have stty/gtty avaialble
250*12111Sralph 	 *              f -- "file name" name of text file to print
251*12111Sralph 	 *		l -- "file name" text file with control chars
252*12111Sralph 	 *		p -- "file name" text file to print with pr(1)
253*12111Sralph 	 *		t -- "file name" troff(1) file to print
254*12111Sralph 	 *		d -- "file name" dvi file to print
255*12111Sralph 	 *		g -- "file name" plot(1G) file to print
256*12111Sralph 	 *		v -- "file name" plain raster file to print
257*12111Sralph 	 *		c -- "file name" cifplot file to print
258*12111Sralph 	 *		1 -- "R font file" for troff
259*12111Sralph 	 *		2 -- "I font file" for troff
260*12111Sralph 	 *		3 -- "B font file" for troff
261*12111Sralph 	 *		4 -- "S font file" for troff
262*12111Sralph 	 *		N -- "name" of file (used by lpq)
263*12111Sralph 	 *              U -- "unlink" name of file to remove
264*12111Sralph 	 *                    (after we print it. (Pass 2 only)).
265*12111Sralph 	 *		M -- "mail" to user when done printing
266*12111Sralph 	 *
267*12111Sralph 	 *      getline reads a line and expands tabs to blanks
268*12111Sralph 	 */
269*12111Sralph 
270*12111Sralph 	/* pass 1 */
271*12111Sralph 
272*12111Sralph 	while (getline(cfp))
273*12111Sralph 		switch (line[0]) {
274*12111Sralph 		case 'H':
275*12111Sralph 			strcpy(host, line+1);
276*12111Sralph 			if (class[0] == '\0')
277*12111Sralph 				strcpy(class, line+1);
278*12111Sralph 			continue;
279*12111Sralph 
280*12111Sralph 		case 'P':
281*12111Sralph 			strcpy(logname, line+1);
282*12111Sralph 			continue;
283*12111Sralph 
284*12111Sralph 		case 'J':
285*12111Sralph 			if (line[1] != '\0')
286*12111Sralph 				strcpy(jobname, line+1);
287*12111Sralph 			else
288*12111Sralph 				strcpy(jobname, " ");
289*12111Sralph 			continue;
290*12111Sralph 
291*12111Sralph 		case 'C':
292*12111Sralph 			if (line[1] != '\0')
293*12111Sralph 				strcpy(class, line+1);
294*12111Sralph 			else if (class[0] == '\0')
295*12111Sralph 				gethostname(class, sizeof (class));
296*12111Sralph 			continue;
297*12111Sralph 
298*12111Sralph 		case 'T':	/* header title for pr */
299*12111Sralph 			strcpy(title, line+1);
300*12111Sralph 			continue;
301*12111Sralph 
302*12111Sralph 		case 'L':	/* identification line */
303*12111Sralph 			if (!SH)
304*12111Sralph 				banner(line+1, jobname);
305*12111Sralph 			continue;
306*12111Sralph 
307*12111Sralph 		case '1':	/* troff fonts */
308*12111Sralph 		case '2':
309*12111Sralph 		case '3':
310*12111Sralph 		case '4':
311*12111Sralph 			if (line[1] != '\0')
312*12111Sralph 				strcpy(fonts[line[0]-'1'], line+1);
313*12111Sralph 			continue;
314*12111Sralph 
315*12111Sralph 		case 'W':	/* page width */
316*12111Sralph 			strcpy(width+2, line+1);
317*12111Sralph 			continue;
318*12111Sralph 
319*12111Sralph 		default:	/* some file to print */
320*12111Sralph 			if ((i = print(line[0], line+1)) > 0) {
321*12111Sralph 				(void) fclose(cfp);
322*12111Sralph 				return(1);
323*12111Sralph 			} else if (i < 0)
324*12111Sralph 				bombed = 1;
325*12111Sralph 			title[0] = '\0';
326*12111Sralph 			continue;
327*12111Sralph 
328*12111Sralph 		case 'I':
329*12111Sralph 		case 'N':
330*12111Sralph 		case 'U':
331*12111Sralph 		case 'M':
332*12111Sralph 			continue;
333*12111Sralph 		}
334*12111Sralph 
335*12111Sralph 	/* pass 2 */
336*12111Sralph 
337*12111Sralph 	fseek(cfp, 0L, 0);
338*12111Sralph 	while (getline(cfp))
339*12111Sralph 		switch (line[0]) {
340*12111Sralph 		case 'M':
341*12111Sralph 			sendmail(bombed);
342*12111Sralph 			continue;
343*12111Sralph 
344*12111Sralph 		case 'U':
345*12111Sralph 			(void) unlink(line+1);
346*12111Sralph 		}
347*12111Sralph 	/*
348*12111Sralph 	 * clean-up incase another control file exists
349*12111Sralph 	 */
350*12111Sralph 	(void) fclose(cfp);
351*12111Sralph 	(void) unlink(file);
352*12111Sralph 	return(0);
353*12111Sralph }
354*12111Sralph 
355*12111Sralph /*
356*12111Sralph  * Print a file.
357*12111Sralph  * Set up the chain [ PR [ | {IF, OF} ] ] or {IF, TF, CF, VF}.
358*12111Sralph  * Return -1 if a non-recoverable error occured, 1 if a recoverable error and
359*12111Sralph  * 0 if all is well.
360*12111Sralph  * Note: all filters take stdin as the file, stdout as the printer,
361*12111Sralph  * stderr as the log file, and must not ignore SIGINT.
362*12111Sralph  */
363*12111Sralph print(format, file)
364*12111Sralph 	int format;
365*12111Sralph 	char *file;
366*12111Sralph {
367*12111Sralph 	register int n, fi, fo;
368*12111Sralph 	register char *prog;
369*12111Sralph 	char *av[15], buf[BUFSIZ];
370*12111Sralph 	int pid, p[2], stopped = 0;
371*12111Sralph 	union wait status;
372*12111Sralph 
373*12111Sralph 	if ((fi = open(file, FRDONLY, 0)) < 0) {
374*12111Sralph 		log("%s: open failure <errno = %d>", file, errno);
375*12111Sralph 		return(-1);
376*12111Sralph 	}
377*12111Sralph 	if (!SF && !tof) {		/* start on a fresh page */
378*12111Sralph 		(void) write(ofd, FF, strlen(FF));
379*12111Sralph 		tof = 1;
380*12111Sralph 	}
381*12111Sralph 	if (IF == NULL && (format == 'f' || format == 'l')) {
382*12111Sralph 		tof = 0;
383*12111Sralph 		while ((n = read(fi, buf, BUFSIZ)) > 0)
384*12111Sralph 			if (write(ofd, buf, n) != n) {
385*12111Sralph 				(void) close(fi);
386*12111Sralph 				return(1);
387*12111Sralph 			}
388*12111Sralph 		(void) close(fi);
389*12111Sralph 		return(0);
390*12111Sralph 	}
391*12111Sralph 	switch (format) {
392*12111Sralph 	case 'p':	/* print file using 'pr' */
393*12111Sralph 		if (IF == NULL) {	/* use output filter */
394*12111Sralph 			prog = PR;
395*12111Sralph 			av[0] = "pr";
396*12111Sralph 			av[1] = width;
397*12111Sralph 			av[2] = length;
398*12111Sralph 			av[3] = "-h";
399*12111Sralph 			av[4] = *title ? title : " ";
400*12111Sralph 			av[5] = 0;
401*12111Sralph 			fo = ofd;
402*12111Sralph 			goto start;
403*12111Sralph 		}
404*12111Sralph 		pipe(p);
405*12111Sralph 		if ((prchild = dofork(DORETURN)) == 0) {	/* child */
406*12111Sralph 			dup2(fi, 0);		/* file is stdin */
407*12111Sralph 			dup2(p[1], 1);		/* pipe is stdout */
408*12111Sralph 			for (n = 3; n < NOFILE; n++)
409*12111Sralph 				(void) close(n);
410*12111Sralph 			execl(PR, "pr", width, length, "-h", *title ? title : " ", 0);
411*12111Sralph 			log("cannot execl %s", PR);
412*12111Sralph 			exit(2);
413*12111Sralph 		}
414*12111Sralph 		(void) close(p[1]);		/* close output side */
415*12111Sralph 		(void) close(fi);
416*12111Sralph 		if (prchild < 0) {
417*12111Sralph 			prchild = 0;
418*12111Sralph 			(void) close(p[0]);
419*12111Sralph 			return(-1);
420*12111Sralph 		}
421*12111Sralph 		fi = p[0];			/* use pipe for input */
422*12111Sralph 	case 'f':	/* print plain text file */
423*12111Sralph 		prog = IF;
424*12111Sralph 		av[1] = width;
425*12111Sralph 		av[2] = length;
426*12111Sralph 		n = 3;
427*12111Sralph 		break;
428*12111Sralph 	case 'l':	/* like 'f' but pass control characters */
429*12111Sralph 		prog = IF;
430*12111Sralph 		av[1] = "-l";
431*12111Sralph 		av[2] = width;
432*12111Sralph 		av[3] = length;
433*12111Sralph 		n = 4;
434*12111Sralph 		break;
435*12111Sralph 	case 't':	/* print troff output */
436*12111Sralph 	case 'd':	/* print troff output */
437*12111Sralph 		(void) unlink(".railmag");
438*12111Sralph 		if ((fo = creat(".railmag", 0666)) < 0) {
439*12111Sralph 			log("cannot create .railmag");
440*12111Sralph 			(void) unlink(".railmag");
441*12111Sralph 		} else {
442*12111Sralph 			for (n = 0; n < 4; n++) {
443*12111Sralph 				if (fonts[n][0] != '/')
444*12111Sralph 					(void) write(fo, "/usr/lib/vfont/", 15);
445*12111Sralph 				(void) write(fo, fonts[n], strlen(fonts[n]));
446*12111Sralph 				(void) write(fo, "\n", 1);
447*12111Sralph 			}
448*12111Sralph 			(void) close(fo);
449*12111Sralph 		}
450*12111Sralph 		prog = (format == 't') ? TF : DF;
451*12111Sralph 		n = 1;
452*12111Sralph 		break;
453*12111Sralph 	case 'c':	/* print cifplot output */
454*12111Sralph 		prog = CF;
455*12111Sralph 		n = 1;
456*12111Sralph 		break;
457*12111Sralph 	case 'g':	/* print plot(1G) output */
458*12111Sralph 		prog = GF;
459*12111Sralph 		n = 1;
460*12111Sralph 		break;
461*12111Sralph 	case 'v':	/* print raster output */
462*12111Sralph 		prog = VF;
463*12111Sralph 		n = 1;
464*12111Sralph 		break;
465*12111Sralph 	default:
466*12111Sralph 		(void) close(fi);
467*12111Sralph 		log("illegal format character '%c'", format);
468*12111Sralph 		return(-1);
469*12111Sralph 	}
470*12111Sralph 	if ((av[0] = rindex(prog, '/')) != NULL)
471*12111Sralph 		av[0]++;
472*12111Sralph 	else
473*12111Sralph 		av[0] = prog;
474*12111Sralph 	av[n++] = "-n";
475*12111Sralph 	av[n++] = logname;
476*12111Sralph 	av[n++] = "-h";
477*12111Sralph 	av[n++] = host;
478*12111Sralph 	av[n++] = AF;
479*12111Sralph 	av[n] = 0;
480*12111Sralph 	fo = pfd;
481*12111Sralph 	if (ofilter > 0) {		/* stop output filter */
482*12111Sralph 		write(ofd, "\031\1", 2);
483*12111Sralph 		while ((pid = wait3(&status, WUNTRACED, 0)) > 0 && pid != ofilter)
484*12111Sralph 			;
485*12111Sralph 		if (status.w_stopval != WSTOPPED) {
486*12111Sralph 			(void) close(fi);
487*12111Sralph 			log("output filter died (%d)", status.w_retcode);
488*12111Sralph 			return(1);
489*12111Sralph 		}
490*12111Sralph 		stopped++;
491*12111Sralph 	}
492*12111Sralph start:
493*12111Sralph 	if ((child = dofork(DORETURN)) == 0) {	/* child */
494*12111Sralph 		dup2(fi, 0);
495*12111Sralph 		dup2(fo, 1);
496*12111Sralph 		for (n = 3; n < NOFILE; n++)
497*12111Sralph 			(void) close(n);
498*12111Sralph 		execv(prog, av);
499*12111Sralph 		log("cannot execl %s", prog);
500*12111Sralph 		exit(2);
501*12111Sralph 	}
502*12111Sralph 	(void) close(fi);
503*12111Sralph 	if (child < 0)
504*12111Sralph 		status.w_retcode = 100;
505*12111Sralph 	else
506*12111Sralph 		while ((pid = wait(&status)) > 0 && pid != child)
507*12111Sralph 			;
508*12111Sralph 	child = 0;
509*12111Sralph 	prchild = 0;
510*12111Sralph 	if (stopped) {		/* restart output filter */
511*12111Sralph 		if (kill(ofilter, SIGCONT) < 0) {
512*12111Sralph 			log("cannot restart output filter");
513*12111Sralph 			exit(1);
514*12111Sralph 		}
515*12111Sralph 	}
516*12111Sralph 	tof = 0;
517*12111Sralph 	if (!WIFEXITED(status) || status.w_retcode > 1) {
518*12111Sralph 		log("Daemon Filter '%c' Malfunction (%d)", format, status.w_retcode);
519*12111Sralph 		return(-1);
520*12111Sralph 	} else if (status.w_retcode == 1)
521*12111Sralph 		return(1);
522*12111Sralph 	tof = 1;
523*12111Sralph 	return(0);
524*12111Sralph }
525*12111Sralph 
526*12111Sralph /*
527*12111Sralph  * Send the daemon control file (cf) and any data files.
528*12111Sralph  * Return -1 if a non-recoverable error occured, 1 if a recoverable error and
529*12111Sralph  * 0 if all is well.
530*12111Sralph  */
531*12111Sralph sendit(file)
532*12111Sralph 	char *file;
533*12111Sralph {
534*12111Sralph 	register int linelen, err = 0;
535*12111Sralph 	char last[132];
536*12111Sralph 
537*12111Sralph 	/*
538*12111Sralph 	 * open control file
539*12111Sralph 	 */
540*12111Sralph 	if ((cfp = fopen(file, "r")) == NULL) {
541*12111Sralph 		log("control file (%s) open failure <errno = %d>", file, errno);
542*12111Sralph 		return(0);
543*12111Sralph 	}
544*12111Sralph 	/*
545*12111Sralph 	 *      read the control file for work to do
546*12111Sralph 	 *
547*12111Sralph 	 *      file format -- first character in the line is a command
548*12111Sralph 	 *      rest of the line is the argument.
549*12111Sralph 	 *      commands of interest are:
550*12111Sralph 	 *
551*12111Sralph 	 *            a-z -- "file name" name of file to print
552*12111Sralph 	 *              U -- "unlink" name of file to remove
553*12111Sralph 	 *                    (after we print it. (Pass 2 only)).
554*12111Sralph 	 */
555*12111Sralph 
556*12111Sralph 	/*
557*12111Sralph 	 * pass 1
558*12111Sralph 	 */
559*12111Sralph 	while (getline(cfp)) {
560*12111Sralph 	again:
561*12111Sralph 		if (line[0] >= 'a' && line[0] <= 'z') {
562*12111Sralph 			strcpy(last, line);
563*12111Sralph 			while (linelen = getline(cfp))
564*12111Sralph 				if (strcmp(last, line))
565*12111Sralph 					break;
566*12111Sralph 			if ((err = sendfile('\3', last+1)) > 0) {
567*12111Sralph 				(void) fclose(cfp);
568*12111Sralph 				return(1);
569*12111Sralph 			} else if (err)
570*12111Sralph 				break;
571*12111Sralph 			if (linelen)
572*12111Sralph 				goto again;
573*12111Sralph 			break;
574*12111Sralph 		}
575*12111Sralph 	}
576*12111Sralph 	if (!err && sendfile('\2', file) > 0) {
577*12111Sralph 		(void) fclose(cfp);
578*12111Sralph 		return(1);
579*12111Sralph 	}
580*12111Sralph 	/*
581*12111Sralph 	 * pass 2
582*12111Sralph 	 */
583*12111Sralph 	fseek(cfp, 0L, 0);
584*12111Sralph 	while (getline(cfp))
585*12111Sralph 		if (line[0] == 'U')
586*12111Sralph 			(void) unlink(line+1);
587*12111Sralph 	/*
588*12111Sralph 	 * clean-up incase another control file exists
589*12111Sralph 	 */
590*12111Sralph 	(void) fclose(cfp);
591*12111Sralph 	(void) unlink(file);
592*12111Sralph 	return(0);
593*12111Sralph }
594*12111Sralph 
595*12111Sralph /*
596*12111Sralph  * Send a data file to the remote machine and spool it.
597*12111Sralph  * Return positive if we should try resending.
598*12111Sralph  */
599*12111Sralph sendfile(type, file)
600*12111Sralph 	char type, *file;
601*12111Sralph {
602*12111Sralph 	register int f, i, amt;
603*12111Sralph 	struct stat stb;
604*12111Sralph 	char buf[BUFSIZ];
605*12111Sralph 	int sizerr;
606*12111Sralph 
607*12111Sralph 	if ((f = open(file, FRDONLY, 0)) < 0 || fstat(f, &stb) < 0) {
608*12111Sralph 		log("file (%s) open failure <errno = %d>", file, errno);
609*12111Sralph 		return(-1);
610*12111Sralph 	}
611*12111Sralph 	(void) sprintf(buf, "%c%d %s\n", type, stb.st_size, file);
612*12111Sralph 	amt = strlen(buf);
613*12111Sralph 	if (write(pfd, buf, amt) != amt)
614*12111Sralph 		return(1);
615*12111Sralph 	if (noresponse())
616*12111Sralph 		return(1);
617*12111Sralph 	sizerr = 0;
618*12111Sralph 	for (i = 0; i < stb.st_size; i += BUFSIZ) {
619*12111Sralph 		amt = BUFSIZ;
620*12111Sralph 		if (i + amt > stb.st_size)
621*12111Sralph 			amt = stb.st_size - i;
622*12111Sralph 		if (sizerr == 0 && read(f, buf, amt) != amt)
623*12111Sralph 			sizerr = 1;
624*12111Sralph 		if (write(pfd, buf, amt) != amt)
625*12111Sralph 			return(1);
626*12111Sralph 	}
627*12111Sralph 	(void) close(f);
628*12111Sralph 	if (sizerr) {
629*12111Sralph 		log("%s: changed size", file);
630*12111Sralph 		(void) write(pfd, "\1", 1);  /* tell recvjob to ignore this file */
631*12111Sralph 		return(-1);
632*12111Sralph 	}
633*12111Sralph 	if (write(pfd, "", 1) != 1)
634*12111Sralph 		return(1);
635*12111Sralph 	if (noresponse())
636*12111Sralph 		return(1);
637*12111Sralph 	return(0);
638*12111Sralph }
639*12111Sralph 
640*12111Sralph /*
641*12111Sralph  * Check to make sure there have been no errors and that both programs
642*12111Sralph  * are in sync with eachother.
643*12111Sralph  * Return non-zero if the connection was lost.
644*12111Sralph  */
645*12111Sralph static
646*12111Sralph noresponse()
647*12111Sralph {
648*12111Sralph 	char resp;
649*12111Sralph 
650*12111Sralph 	if (read(pfd, &resp, 1) != 1 || resp != '\0') {
651*12111Sralph 		log("lost connection or error in recvjob");
652*12111Sralph 		return(1);
653*12111Sralph 	}
654*12111Sralph 	return(0);
655*12111Sralph }
656*12111Sralph 
657*12111Sralph /*
658*12111Sralph  * Banner printing stuff
659*12111Sralph  */
660*12111Sralph banner(name1, name2)
661*12111Sralph 	char *name1, *name2;
662*12111Sralph {
663*12111Sralph 	time_t tvec;
664*12111Sralph 	extern char *ctime();
665*12111Sralph 
666*12111Sralph 	time(&tvec);
667*12111Sralph 	if (!SF && !tof)
668*12111Sralph 		(void) write(ofd, FF, strlen(FF));
669*12111Sralph 	if (SB) {	/* short banner only */
670*12111Sralph 		if (class[0]) {
671*12111Sralph 			(void) write(ofd, class, strlen(class));
672*12111Sralph 			(void) write(ofd, ":", 1);
673*12111Sralph 		}
674*12111Sralph 		(void) write(ofd, name1, strlen(name1));
675*12111Sralph 		(void) write(ofd, "  Job: ", 7);
676*12111Sralph 		(void) write(ofd, name2, strlen(name2));
677*12111Sralph 		(void) write(ofd, "  Date: ", 8);
678*12111Sralph 		(void) write(ofd, ctime(&tvec), 24);
679*12111Sralph 		(void) write(ofd, "\n", 1);
680*12111Sralph 	} else {	/* normal banner */
681*12111Sralph 		(void) write(ofd, "\n\n\n", 3);
682*12111Sralph 		scan_out(ofd, name1, '\0');
683*12111Sralph 		(void) write(ofd, "\n\n", 2);
684*12111Sralph 		scan_out(ofd, name2, '\0');
685*12111Sralph 		if (class[0]) {
686*12111Sralph 			(void) write(ofd,"\n\n\n",3);
687*12111Sralph 			scan_out(ofd, class, '\0');
688*12111Sralph 		}
689*12111Sralph 		(void) write(ofd, "\n\n\n\n\t\t\t\t\tJob:  ", 15);
690*12111Sralph 		(void) write(ofd, name2, strlen(name2));
691*12111Sralph 		(void) write(ofd, "\n\t\t\t\t\tDate: ", 12);
692*12111Sralph 		(void) write(ofd, ctime(&tvec), 24);
693*12111Sralph 		(void) write(ofd, "\n", 1);
694*12111Sralph 	}
695*12111Sralph 	if (!SF)
696*12111Sralph 		(void) write(ofd, FF, strlen(FF));
697*12111Sralph 	tof = 1;
698*12111Sralph }
699*12111Sralph 
700*12111Sralph char *
701*12111Sralph scnline(key, p, c)
702*12111Sralph 	register char key, *p;
703*12111Sralph 	char c;
704*12111Sralph {
705*12111Sralph 	register scnwidth;
706*12111Sralph 
707*12111Sralph 	for (scnwidth = WIDTH; --scnwidth;) {
708*12111Sralph 		key <<= 1;
709*12111Sralph 		*p++ = key & 0200 ? c : BACKGND;
710*12111Sralph 	}
711*12111Sralph 	return (p);
712*12111Sralph }
713*12111Sralph 
714*12111Sralph #define TRC(q)	(((q)-' ')&0177)
715*12111Sralph 
716*12111Sralph scan_out(scfd, scsp, dlm)
717*12111Sralph 	int scfd;
718*12111Sralph 	char *scsp, dlm;
719*12111Sralph {
720*12111Sralph 	register char *strp;
721*12111Sralph 	register nchrs, j;
722*12111Sralph 	char outbuf[LINELEN+1], *sp, c, cc;
723*12111Sralph 	int d, scnhgt;
724*12111Sralph 	extern char scnkey[][HEIGHT];	/* in lpdchar.c */
725*12111Sralph 
726*12111Sralph 	for (scnhgt = 0; scnhgt++ < HEIGHT+DROP; ) {
727*12111Sralph 		strp = &outbuf[0];
728*12111Sralph 		sp = scsp;
729*12111Sralph 		for (nchrs = 0; ; ) {
730*12111Sralph 			d = dropit(c = TRC(cc = *sp++));
731*12111Sralph 			if ((!d && scnhgt > HEIGHT) || (scnhgt <= DROP && d))
732*12111Sralph 				for (j = WIDTH; --j;)
733*12111Sralph 					*strp++ = BACKGND;
734*12111Sralph 			else
735*12111Sralph 				strp = scnline(scnkey[c][scnhgt-1-d], strp, cc);
736*12111Sralph 			if (*sp == dlm || *sp == '\0' || nchrs++ >= PW/(WIDTH+1)-1)
737*12111Sralph 				break;
738*12111Sralph 			*strp++ = BACKGND;
739*12111Sralph 			*strp++ = BACKGND;
740*12111Sralph 		}
741*12111Sralph 		while (*--strp == BACKGND && strp >= outbuf)
742*12111Sralph 			;
743*12111Sralph 		strp++;
744*12111Sralph 		*strp++ = '\n';
745*12111Sralph 		(void) write(scfd, outbuf, strp-outbuf);
746*12111Sralph 	}
747*12111Sralph }
748*12111Sralph 
749*12111Sralph dropit(c)
750*12111Sralph 	char c;
751*12111Sralph {
752*12111Sralph 	switch(c) {
753*12111Sralph 
754*12111Sralph 	case TRC('_'):
755*12111Sralph 	case TRC(';'):
756*12111Sralph 	case TRC(','):
757*12111Sralph 	case TRC('g'):
758*12111Sralph 	case TRC('j'):
759*12111Sralph 	case TRC('p'):
760*12111Sralph 	case TRC('q'):
761*12111Sralph 	case TRC('y'):
762*12111Sralph 		return (DROP);
763*12111Sralph 
764*12111Sralph 	default:
765*12111Sralph 		return (0);
766*12111Sralph 	}
767*12111Sralph }
768*12111Sralph 
769*12111Sralph /*
770*12111Sralph  * sendmail ---
771*12111Sralph  *   tell people about job completion
772*12111Sralph  */
773*12111Sralph sendmail(bombed)
774*12111Sralph 	int bombed;
775*12111Sralph {
776*12111Sralph 	static int p[2];
777*12111Sralph 	register int i;
778*12111Sralph 	int stat;
779*12111Sralph 	register char *cp;
780*12111Sralph 	char buf[100];
781*12111Sralph 
782*12111Sralph 	pipe(p);
783*12111Sralph 	if ((stat = dofork(DORETURN)) == 0) {		/* child */
784*12111Sralph 		dup2(p[0], 0);
785*12111Sralph 		for (i = 3; i < NOFILE; i++)
786*12111Sralph 			(void) close(i);
787*12111Sralph 		if ((cp = rindex(MAIL, '/')) != NULL)
788*12111Sralph 			cp++;
789*12111Sralph 		else
790*12111Sralph 			cp = MAIL;
791*12111Sralph 		sprintf(buf, "%s@%s", line+1, host);
792*12111Sralph 		execl(MAIL, cp, buf, 0);
793*12111Sralph 		exit(0);
794*12111Sralph 	} else if (stat > 0) {				/* parent */
795*12111Sralph 		dup2(p[1], 1);
796*12111Sralph 		printf("To: %s\n", line+1);
797*12111Sralph 		printf("Subject: printer job\n\n");
798*12111Sralph 		printf("Your printer job ");
799*12111Sralph 		if (*jobname)
800*12111Sralph 			printf("(%s) ", jobname);
801*12111Sralph 		if (bombed)
802*12111Sralph 			printf("bombed\n");
803*12111Sralph 		else
804*12111Sralph 			printf("is done\n");
805*12111Sralph 		fflush(stdout);
806*12111Sralph 		(void) close(1);
807*12111Sralph 	}
808*12111Sralph 	(void) close(p[0]);
809*12111Sralph 	(void) close(p[1]);
810*12111Sralph 	wait(&stat);
811*12111Sralph }
812*12111Sralph 
813*12111Sralph /*
814*12111Sralph  * dofork - fork with retries on failure
815*12111Sralph  */
816*12111Sralph dofork(action)
817*12111Sralph 	int action;
818*12111Sralph {
819*12111Sralph 	register int i, pid;
820*12111Sralph 
821*12111Sralph 	for (i = 0; i < 20; i++) {
822*12111Sralph 		if ((pid = fork()) < 0)
823*12111Sralph 			sleep((unsigned)(i*i));
824*12111Sralph 		else
825*12111Sralph 			return(pid);
826*12111Sralph 	}
827*12111Sralph 	log("can't fork");
828*12111Sralph 
829*12111Sralph 	switch (action) {
830*12111Sralph 	case DORETURN:
831*12111Sralph 		return (-1);
832*12111Sralph 	default:
833*12111Sralph 		log("bad action (%d) to dofork", action);
834*12111Sralph 		/*FALL THRU*/
835*12111Sralph 	case DOABORT:
836*12111Sralph 		exit(1);
837*12111Sralph 	}
838*12111Sralph 	/*NOTREACHED*/
839*12111Sralph }
840*12111Sralph 
841*12111Sralph /*
842*12111Sralph  * Cleanup child processes when a SIGINT is caught.
843*12111Sralph  */
844*12111Sralph onintr()
845*12111Sralph {
846*12111Sralph 	kill(0, SIGINT);
847*12111Sralph 	if (ofilter > 0)
848*12111Sralph 		kill(ofilter, SIGCONT);
849*12111Sralph 	while (wait(0) > 0)
850*12111Sralph 		;
851*12111Sralph 	exit(0);
852*12111Sralph }
853*12111Sralph 
854*12111Sralph init()
855*12111Sralph {
856*12111Sralph 	int status;
857*12111Sralph 
858*12111Sralph 	if ((status = pgetent(line, printer)) < 0) {
859*12111Sralph 		log("can't open printer description file");
860*12111Sralph 		exit(1);
861*12111Sralph 	} else if (status == 0) {
862*12111Sralph 		log("unknown printer");
863*12111Sralph 		exit(1);
864*12111Sralph 	}
865*12111Sralph 	if ((LP = pgetstr("lp", &bp)) == NULL)
866*12111Sralph 		LP = DEFDEVLP;
867*12111Sralph 	if ((RP = pgetstr("rp", &bp)) == NULL)
868*12111Sralph 		RP = printer;
869*12111Sralph 	if ((LO = pgetstr("lo", &bp)) == NULL)
870*12111Sralph 		LO = DEFLOCK;
871*12111Sralph 	if ((ST = pgetstr("st", &bp)) == NULL)
872*12111Sralph 		ST = DEFSTAT;
873*12111Sralph 	if ((LF = pgetstr("lf", &bp)) == NULL)
874*12111Sralph 		LF = DEFLOGF;
875*12111Sralph 	if ((SD = pgetstr("sd", &bp)) == NULL)
876*12111Sralph 		SD = DEFSPOOL;
877*12111Sralph 	if ((DU = pgetnum("du")) < 0)
878*12111Sralph 		DU = DEFUID;
879*12111Sralph 	if ((FF = pgetstr("ff", &bp)) == NULL)
880*12111Sralph 		FF = DEFFF;
881*12111Sralph 	if ((PW = pgetnum("pw")) < 0)
882*12111Sralph 		PW = DEFWIDTH;
883*12111Sralph 	sprintf(&width[2], "%d", PW);
884*12111Sralph 	if ((PL = pgetnum("pl")) < 0)
885*12111Sralph 		PL = DEFLENGTH;
886*12111Sralph 	sprintf(&length[2], "%d", PL);
887*12111Sralph 	RM = pgetstr("rm", &bp);
888*12111Sralph 	AF = pgetstr("af", &bp);
889*12111Sralph 	OF = pgetstr("of", &bp);
890*12111Sralph 	IF = pgetstr("if", &bp);
891*12111Sralph 	TF = pgetstr("tf", &bp);
892*12111Sralph 	DF = pgetstr("df", &bp);
893*12111Sralph 	GF = pgetstr("gf", &bp);
894*12111Sralph 	VF = pgetstr("vf", &bp);
895*12111Sralph 	CF = pgetstr("cf", &bp);
896*12111Sralph 	TR = pgetstr("tr", &bp);
897*12111Sralph 	SF = pgetflag("sf");
898*12111Sralph 	SH = pgetflag("sh");
899*12111Sralph 	SB = pgetflag("sb");
900*12111Sralph 	RW = pgetflag("rw");
901*12111Sralph 	BR = pgetnum("br");
902*12111Sralph 	if ((FC = pgetnum("fc")) < 0)
903*12111Sralph 		FC = 0;
904*12111Sralph 	if ((FS = pgetnum("fs")) < 0)
905*12111Sralph 		FS = 0;
906*12111Sralph 	if ((XC = pgetnum("xc")) < 0)
907*12111Sralph 		XC = 0;
908*12111Sralph 	if ((XS = pgetnum("xs")) < 0)
909*12111Sralph 		XS = 0;
910*12111Sralph }
911*12111Sralph 
912*12111Sralph struct bauds {
913*12111Sralph 	int	baud;
914*12111Sralph 	int	speed;
915*12111Sralph } bauds[] = {
916*12111Sralph 	50,	B50,
917*12111Sralph 	75,	B75,
918*12111Sralph 	110,	B110,
919*12111Sralph 	134,	B134,
920*12111Sralph 	150,	B150,
921*12111Sralph 	200,	B200,
922*12111Sralph 	300,	B300,
923*12111Sralph 	600,	B600,
924*12111Sralph 	1200,	B1200,
925*12111Sralph 	1800,	B1800,
926*12111Sralph 	2400,	B2400,
927*12111Sralph 	4800,	B4800,
928*12111Sralph 	9600,	B9600,
929*12111Sralph 	19200,	EXTA,
930*12111Sralph 	38400,	EXTB,
931*12111Sralph 	0,	0
932*12111Sralph };
933*12111Sralph 
934*12111Sralph /*
935*12111Sralph  * setup tty lines.
936*12111Sralph  */
937*12111Sralph setty()
938*12111Sralph {
939*12111Sralph 	struct sgttyb ttybuf;
940*12111Sralph 	register struct bauds *bp;
941*12111Sralph 
942*12111Sralph 	if (ioctl(pfd, TIOCEXCL, (char *)0) < 0) {
943*12111Sralph 		log("cannot set exclusive-use");
944*12111Sralph 		exit(1);
945*12111Sralph 	}
946*12111Sralph 	if (ioctl(pfd, TIOCGETP, (char *)&ttybuf) < 0) {
947*12111Sralph 		log("cannot get tty parameters");
948*12111Sralph 		exit(1);
949*12111Sralph 	}
950*12111Sralph 	if (BR > 0) {
951*12111Sralph 		for (bp = bauds; bp->baud; bp++)
952*12111Sralph 			if (BR == bp->baud)
953*12111Sralph 				break;
954*12111Sralph 		if (!bp->baud) {
955*12111Sralph 			log("illegal baud rate %d", BR);
956*12111Sralph 			exit(1);
957*12111Sralph 		}
958*12111Sralph 		ttybuf.sg_ispeed = ttybuf.sg_ospeed = bp->speed;
959*12111Sralph 	}
960*12111Sralph 	if (FC)
961*12111Sralph 		ttybuf.sg_flags &= ~FC;
962*12111Sralph 	if (FS)
963*12111Sralph 		ttybuf.sg_flags |= FS;
964*12111Sralph 	if (ioctl(pfd, TIOCSETP, (char *)&ttybuf) < 0) {
965*12111Sralph 		log("cannot set tty parameters");
966*12111Sralph 		exit(1);
967*12111Sralph 	}
968*12111Sralph 	if (XC) {
969*12111Sralph 		if (ioctl(pfd, TIOCLBIC, &XC) < 0) {
970*12111Sralph 			log("cannot set local tty parameters");
971*12111Sralph 			exit(1);
972*12111Sralph 		}
973*12111Sralph 	}
974*12111Sralph 	if (XS) {
975*12111Sralph 		if (ioctl(pfd, TIOCLBIS, &XS) < 0) {
976*12111Sralph 			log("cannot set local tty parameters");
977*12111Sralph 			exit(1);
978*12111Sralph 		}
979*12111Sralph 	}
980*12111Sralph }
981