xref: /freebsd/usr.sbin/lpr/lpd/printjob.c (revision 8e6b01171e30297084bb0b4457c4183c2746aacc)
1 /*
2  * Copyright (c) 1983, 1993
3  *	The Regents of the University of California.  All rights reserved.
4  *
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  * 3. All advertising materials mentioning features or use of this software
15  *    must display the following acknowledgement:
16  *	This product includes software developed by the University of
17  *	California, Berkeley and its contributors.
18  * 4. Neither the name of the University nor the names of its contributors
19  *    may be used to endorse or promote products derived from this software
20  *    without specific prior written permission.
21  *
22  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32  * SUCH DAMAGE.
33  */
34 
35 #ifndef lint
36 static char copyright[] =
37 "@(#) Copyright (c) 1983, 1993\n\
38 	The Regents of the University of California.  All rights reserved.\n";
39 #endif /* not lint */
40 
41 #ifndef lint
42 static char sccsid[] = "@(#)printjob.c	8.2 (Berkeley) 4/16/94";
43 #endif /* not lint */
44 
45 
46 /*
47  * printjob -- print jobs in the queue.
48  *
49  *	NOTE: the lock file is used to pass information to lpq and lprm.
50  *	it does not need to be removed because file locks are dynamic.
51  */
52 
53 #include <sys/param.h>
54 #include <sys/wait.h>
55 #include <sys/stat.h>
56 #include <sys/types.h>
57 
58 #include <pwd.h>
59 #include <unistd.h>
60 #include <signal.h>
61 #include <sgtty.h>
62 #include <syslog.h>
63 #include <fcntl.h>
64 #include <dirent.h>
65 #include <errno.h>
66 #include <stdio.h>
67 #include <string.h>
68 #include <stdlib.h>
69 #include "lp.h"
70 #include "lp.local.h"
71 #include "pathnames.h"
72 #include "extern.h"
73 
74 #define DORETURN	0	/* absorb fork error */
75 #define DOABORT		1	/* abort if dofork fails */
76 
77 /*
78  * Error tokens
79  */
80 #define REPRINT		-2
81 #define ERROR		-1
82 #define	OK		0
83 #define	FATALERR	1
84 #define	NOACCT		2
85 #define	FILTERERR	3
86 #define	ACCESS		4
87 
88 static dev_t	 fdev;		/* device of file pointed to by symlink */
89 static ino_t	 fino;		/* inode of file pointed to by symlink */
90 static FILE	*cfp;		/* control file */
91 static int	 child;		/* id of any filters */
92 static int	 lfd;		/* lock file descriptor */
93 static int	 ofd;		/* output filter file descriptor */
94 static int	 ofilter;	/* id of output filter, if any */
95 static int	 pfd;		/* prstatic inter file descriptor */
96 static int	 pid;		/* pid of lpd process */
97 static int	 prchild;	/* id of pr process */
98 static int	 remote;	/* true if sending files to remote */
99 static char	 title[80];	/* ``pr'' title */
100 static int	 tof;		/* true if at top of form */
101 
102 static char	class[32];		/* classification field */
103 static char	fromhost[32];		/* user's host machine */
104 				/* indentation size in static characters */
105 static char	indent[10] = "-i0";
106 static char	jobname[100];		/* job or file name */
107 static char	length[10] = "-l";	/* page length in lines */
108 static char	logname[32];		/* user's login name */
109 static char	pxlength[10] = "-y";	/* page length in pixels */
110 static char	pxwidth[10] = "-x";	/* page width in pixels */
111 static char	tempfile[] = "errsXXXXXX"; /* file name for filter output */
112 static char	width[10] = "-w";	/* page width in static characters */
113 
114 static void       abortpr __P((int));
115 static void       banner __P((char *, char *));
116 static int        dofork __P((int));
117 static int        dropit __P((int));
118 static void       init __P((void));
119 static void       openpr __P((void));
120 static int        print __P((int, char *));
121 static int        printit __P((char *));
122 static void       pstatus __P((const char *, ...));
123 static char       response __P((void));
124 static void       scan_out __P((int, char *, int));
125 static char      *scnline __P((int, char *, int));
126 static int        sendfile __P((int, char *));
127 static int        sendit __P((char *));
128 static void       sendmail __P((char *, int));
129 static void       setty __P((void));
130 
131 void
132 printjob()
133 {
134 	struct stat stb;
135 	register struct queue *q, **qp;
136 	struct queue **queue;
137 	register int i, nitems;
138 	long pidoff;
139 	int count = 0;
140 
141 	init();					/* set up capabilities */
142 	(void) write(1, "", 1);			/* ack that daemon is started */
143 	(void) close(2);			/* set up log file */
144 	if (open(LF, O_WRONLY|O_APPEND, 0664) < 0) {
145 		syslog(LOG_ERR, "%s: %m", LF);
146 		(void) open(_PATH_DEVNULL, O_WRONLY);
147 	}
148 	setgid(getegid());
149 	pid = getpid();				/* for use with lprm */
150 	setpgrp(0, pid);
151 	signal(SIGHUP, abortpr);
152 	signal(SIGINT, abortpr);
153 	signal(SIGQUIT, abortpr);
154 	signal(SIGTERM, abortpr);
155 
156 	(void) mktemp(tempfile);
157 
158 	/*
159 	 * uses short form file names
160 	 */
161 	if (chdir(SD) < 0) {
162 		syslog(LOG_ERR, "%s: %m", SD);
163 		exit(1);
164 	}
165 	if (stat(LO, &stb) == 0 && (stb.st_mode & 0100))
166 		exit(0);		/* printing disabled */
167 	lfd = open(LO, O_WRONLY|O_CREAT, 0644);
168 	if (lfd < 0) {
169 		syslog(LOG_ERR, "%s: %s: %m", printer, LO);
170 		exit(1);
171 	}
172 	if (flock(lfd, LOCK_EX|LOCK_NB) < 0) {
173 		if (errno == EWOULDBLOCK)	/* active deamon present */
174 			exit(0);
175 		syslog(LOG_ERR, "%s: %s: %m", printer, LO);
176 		exit(1);
177 	}
178 	ftruncate(lfd, 0);
179 	/*
180 	 * write process id for others to know
181 	 */
182 	sprintf(line, "%u\n", pid);
183 	pidoff = i = strlen(line);
184 	if (write(lfd, line, i) != i) {
185 		syslog(LOG_ERR, "%s: %s: %m", printer, LO);
186 		exit(1);
187 	}
188 	/*
189 	 * search the spool directory for work and sort by queue order.
190 	 */
191 	if ((nitems = getq(&queue)) < 0) {
192 		syslog(LOG_ERR, "%s: can't scan %s", printer, SD);
193 		exit(1);
194 	}
195 	if (nitems == 0)		/* no work to do */
196 		exit(0);
197 	if (stb.st_mode & 01) {		/* reset queue flag */
198 		if (fchmod(lfd, stb.st_mode & 0776) < 0)
199 			syslog(LOG_ERR, "%s: %s: %m", printer, LO);
200 	}
201 	openpr();			/* open printer or remote */
202 again:
203 	/*
204 	 * we found something to do now do it --
205 	 *    write the name of the current control file into the lock file
206 	 *    so the spool queue program can tell what we're working on
207 	 */
208 	for (qp = queue; nitems--; free((char *) q)) {
209 		q = *qp++;
210 		if (stat(q->q_name, &stb) < 0)
211 			continue;
212 	restart:
213 		(void) lseek(lfd, (off_t)pidoff, 0);
214 		(void) sprintf(line, "%s\n", q->q_name);
215 		i = strlen(line);
216 		if (write(lfd, line, i) != i)
217 			syslog(LOG_ERR, "%s: %s: %m", printer, LO);
218 		if (!remote)
219 			i = printit(q->q_name);
220 		else
221 			i = sendit(q->q_name);
222 		/*
223 		 * Check to see if we are supposed to stop printing or
224 		 * if we are to rebuild the queue.
225 		 */
226 		if (fstat(lfd, &stb) == 0) {
227 			/* stop printing before starting next job? */
228 			if (stb.st_mode & 0100)
229 				goto done;
230 			/* rebuild queue (after lpc topq) */
231 			if (stb.st_mode & 01) {
232 				for (free((char *) q); nitems--; free((char *) q))
233 					q = *qp++;
234 				if (fchmod(lfd, stb.st_mode & 0776) < 0)
235 					syslog(LOG_WARNING, "%s: %s: %m",
236 						printer, LO);
237 				break;
238 			}
239 		}
240 		if (i == OK)		/* file ok and printed */
241 			count++;
242 		else if (i == REPRINT) { /* try reprinting the job */
243 			syslog(LOG_INFO, "restarting %s", printer);
244 			if (ofilter > 0) {
245 				kill(ofilter, SIGCONT);	/* to be sure */
246 				(void) close(ofd);
247 				while ((i = wait(0)) > 0 && i != ofilter)
248 					;
249 				ofilter = 0;
250 			}
251 			(void) close(pfd);	/* close printer */
252 			if (ftruncate(lfd, pidoff) < 0)
253 				syslog(LOG_WARNING, "%s: %s: %m", printer, LO);
254 			openpr();		/* try to reopen printer */
255 			goto restart;
256 		}
257 	}
258 	free((char *) queue);
259 	/*
260 	 * search the spool directory for more work.
261 	 */
262 	if ((nitems = getq(&queue)) < 0) {
263 		syslog(LOG_ERR, "%s: can't scan %s", printer, SD);
264 		exit(1);
265 	}
266 	if (nitems == 0) {		/* no more work to do */
267 	done:
268 		if (count > 0) {	/* Files actually printed */
269 			if (!SF && !tof)
270 				(void) write(ofd, FF, strlen(FF));
271 			if (TR != NULL)		/* output trailer */
272 				(void) write(ofd, TR, strlen(TR));
273 		}
274 		(void) unlink(tempfile);
275 		exit(0);
276 	}
277 	goto again;
278 }
279 
280 char	fonts[4][50];	/* fonts for troff */
281 
282 char ifonts[4][40] = {
283 	_PATH_VFONTR,
284 	_PATH_VFONTI,
285 	_PATH_VFONTB,
286 	_PATH_VFONTS,
287 };
288 
289 /*
290  * The remaining part is the reading of the control file (cf)
291  * and performing the various actions.
292  */
293 static int
294 printit(file)
295 	char *file;
296 {
297 	register int i;
298 	char *cp;
299 	int bombed = OK;
300 
301 	/*
302 	 * open control file; ignore if no longer there.
303 	 */
304 	if ((cfp = fopen(file, "r")) == NULL) {
305 		syslog(LOG_INFO, "%s: %s: %m", printer, file);
306 		return(OK);
307 	}
308 	/*
309 	 * Reset troff fonts.
310 	 */
311 	for (i = 0; i < 4; i++)
312 		strcpy(fonts[i], ifonts[i]);
313 	sprintf(&width[2], "%d", PW);
314 	strcpy(indent+2, "0");
315 
316 	/*
317 	 *      read the control file for work to do
318 	 *
319 	 *      file format -- first character in the line is a command
320 	 *      rest of the line is the argument.
321 	 *      valid commands are:
322 	 *
323 	 *		S -- "stat info" for symbolic link protection
324 	 *		J -- "job name" on banner page
325 	 *		C -- "class name" on banner page
326 	 *              L -- "literal" user's name to print on banner
327 	 *		T -- "title" for pr
328 	 *		H -- "host name" of machine where lpr was done
329 	 *              P -- "person" user's login name
330 	 *              I -- "indent" amount to indent output
331 	 *              f -- "file name" name of text file to print
332 	 *		l -- "file name" text file with control chars
333 	 *		p -- "file name" text file to print with pr(1)
334 	 *		t -- "file name" troff(1) file to print
335 	 *		n -- "file name" ditroff(1) file to print
336 	 *		d -- "file name" dvi file to print
337 	 *		g -- "file name" plot(1G) file to print
338 	 *		v -- "file name" plain raster file to print
339 	 *		c -- "file name" cifplot file to print
340 	 *		1 -- "R font file" for troff
341 	 *		2 -- "I font file" for troff
342 	 *		3 -- "B font file" for troff
343 	 *		4 -- "S font file" for troff
344 	 *		N -- "name" of file (used by lpq)
345 	 *              U -- "unlink" name of file to remove
346 	 *                    (after we print it. (Pass 2 only)).
347 	 *		M -- "mail" to user when done printing
348 	 *
349 	 *      getline reads a line and expands tabs to blanks
350 	 */
351 
352 	/* pass 1 */
353 
354 	while (getline(cfp))
355 		switch (line[0]) {
356 		case 'H':
357 			strcpy(fromhost, line+1);
358 			if (class[0] == '\0')
359 				strncpy(class, line+1, sizeof(class)-1);
360 			continue;
361 
362 		case 'P':
363 			strncpy(logname, line+1, sizeof(logname)-1);
364 			if (RS) {			/* restricted */
365 				if (getpwnam(logname) == NULL) {
366 					bombed = NOACCT;
367 					sendmail(line+1, bombed);
368 					goto pass2;
369 				}
370 			}
371 			continue;
372 
373 		case 'S':
374 			cp = line+1;
375 			i = 0;
376 			while (*cp >= '0' && *cp <= '9')
377 				i = i * 10 + (*cp++ - '0');
378 			fdev = i;
379 			cp++;
380 			i = 0;
381 			while (*cp >= '0' && *cp <= '9')
382 				i = i * 10 + (*cp++ - '0');
383 			fino = i;
384 			continue;
385 
386 		case 'J':
387 			if (line[1] != '\0')
388 				strncpy(jobname, line+1, sizeof(jobname)-1);
389 			else
390 				strcpy(jobname, " ");
391 			continue;
392 
393 		case 'C':
394 			if (line[1] != '\0')
395 				strncpy(class, line+1, sizeof(class)-1);
396 			else if (class[0] == '\0')
397 				gethostname(class, sizeof(class));
398 			continue;
399 
400 		case 'T':	/* header title for pr */
401 			strncpy(title, line+1, sizeof(title)-1);
402 			continue;
403 
404 		case 'L':	/* identification line */
405 			if (!SH && !HL)
406 				banner(line+1, jobname);
407 			continue;
408 
409 		case '1':	/* troff fonts */
410 		case '2':
411 		case '3':
412 		case '4':
413 			if (line[1] != '\0')
414 				strcpy(fonts[line[0]-'1'], line+1);
415 			continue;
416 
417 		case 'W':	/* page width */
418 			strncpy(width+2, line+1, sizeof(width)-3);
419 			continue;
420 
421 		case 'I':	/* indent amount */
422 			strncpy(indent+2, line+1, sizeof(indent)-3);
423 			continue;
424 
425 		default:	/* some file to print */
426 			switch (i = print(line[0], line+1)) {
427 			case ERROR:
428 				if (bombed == OK)
429 					bombed = FATALERR;
430 				break;
431 			case REPRINT:
432 				(void) fclose(cfp);
433 				return(REPRINT);
434 			case FILTERERR:
435 			case ACCESS:
436 				bombed = i;
437 				sendmail(logname, bombed);
438 			}
439 			title[0] = '\0';
440 			continue;
441 
442 		case 'N':
443 		case 'U':
444 		case 'M':
445 			continue;
446 		}
447 
448 	/* pass 2 */
449 
450 pass2:
451 	fseek(cfp, 0L, 0);
452 	while (getline(cfp))
453 		switch (line[0]) {
454 		case 'L':	/* identification line */
455 			if (!SH && HL)
456 				banner(line+1, jobname);
457 			continue;
458 
459 		case 'M':
460 			if (bombed < NOACCT)	/* already sent if >= NOACCT */
461 				sendmail(line+1, bombed);
462 			continue;
463 
464 		case 'U':
465 			(void) unlink(line+1);
466 		}
467 	/*
468 	 * clean-up in case another control file exists
469 	 */
470 	(void) fclose(cfp);
471 	(void) unlink(file);
472 	return(bombed == OK ? OK : ERROR);
473 }
474 
475 /*
476  * Print a file.
477  * Set up the chain [ PR [ | {IF, OF} ] ] or {IF, RF, TF, NF, DF, CF, VF}.
478  * Return -1 if a non-recoverable error occured,
479  * 2 if the filter detected some errors (but printed the job anyway),
480  * 1 if we should try to reprint this job and
481  * 0 if all is well.
482  * Note: all filters take stdin as the file, stdout as the printer,
483  * stderr as the log file, and must not ignore SIGINT.
484  */
485 static int
486 print(format, file)
487 	int format;
488 	char *file;
489 {
490 	register int n;
491 	register char *prog;
492 	int fi, fo;
493 	FILE *fp;
494 	char *av[15], buf[BUFSIZ];
495 	int pid, p[2], stopped = 0;
496 	union wait status;
497 	struct stat stb;
498 
499 	if (lstat(file, &stb) < 0 || (fi = open(file, O_RDONLY)) < 0)
500 		return(ERROR);
501 	/*
502 	 * Check to see if data file is a symbolic link. If so, it should
503 	 * still point to the same file or someone is trying to print
504 	 * something he shouldn't.
505 	 */
506 	if ((stb.st_mode & S_IFMT) == S_IFLNK && fstat(fi, &stb) == 0 &&
507 	    (stb.st_dev != fdev || stb.st_ino != fino))
508 		return(ACCESS);
509 	if (!SF && !tof) {		/* start on a fresh page */
510 		(void) write(ofd, FF, strlen(FF));
511 		tof = 1;
512 	}
513 	if (IF == NULL && (format == 'f' || format == 'l')) {
514 		tof = 0;
515 		while ((n = read(fi, buf, BUFSIZ)) > 0)
516 			if (write(ofd, buf, n) != n) {
517 				(void) close(fi);
518 				return(REPRINT);
519 			}
520 		(void) close(fi);
521 		return(OK);
522 	}
523 	switch (format) {
524 	case 'p':	/* print file using 'pr' */
525 		if (IF == NULL) {	/* use output filter */
526 			prog = _PATH_PR;
527 			av[0] = "pr";
528 			av[1] = width;
529 			av[2] = length;
530 			av[3] = "-h";
531 			av[4] = *title ? title : " ";
532 			av[5] = "-F";
533 			av[6] = 0;
534 			fo = ofd;
535 			goto start;
536 		}
537 		pipe(p);
538 		if ((prchild = dofork(DORETURN)) == 0) {	/* child */
539 			dup2(fi, 0);		/* file is stdin */
540 			dup2(p[1], 1);		/* pipe is stdout */
541 			closelog();
542 			for (n = 3; n < NOFILE; n++)
543 				(void) close(n);
544 			execl(_PATH_PR, "pr", width, length,
545 			    "-h", *title ? title : " ", "-F", 0);
546 			openlog("lpd", LOG_PID, LOG_LPR);
547 			syslog(LOG_ERR, "cannot execl %s", _PATH_PR);
548 			exit(2);
549 		}
550 		(void) close(p[1]);		/* close output side */
551 		(void) close(fi);
552 		if (prchild < 0) {
553 			prchild = 0;
554 			(void) close(p[0]);
555 			return(ERROR);
556 		}
557 		fi = p[0];			/* use pipe for input */
558 	case 'f':	/* print plain text file */
559 		prog = IF;
560 		av[1] = width;
561 		av[2] = length;
562 		av[3] = indent;
563 		n = 4;
564 		break;
565 	case 'l':	/* like 'f' but pass control characters */
566 		prog = IF;
567 		av[1] = "-c";
568 		av[2] = width;
569 		av[3] = length;
570 		av[4] = indent;
571 		n = 5;
572 		break;
573 	case 'r':	/* print a fortran text file */
574 		prog = RF;
575 		av[1] = width;
576 		av[2] = length;
577 		n = 3;
578 		break;
579 	case 't':	/* print troff output */
580 	case 'n':	/* print ditroff output */
581 	case 'd':	/* print tex output */
582 		(void) unlink(".railmag");
583 		if ((fo = creat(".railmag", FILMOD)) < 0) {
584 			syslog(LOG_ERR, "%s: cannot create .railmag", printer);
585 			(void) unlink(".railmag");
586 		} else {
587 			for (n = 0; n < 4; n++) {
588 				if (fonts[n][0] != '/')
589 					(void) write(fo, _PATH_VFONT,
590 					    sizeof(_PATH_VFONT) - 1);
591 				(void) write(fo, fonts[n], strlen(fonts[n]));
592 				(void) write(fo, "\n", 1);
593 			}
594 			(void) close(fo);
595 		}
596 		prog = (format == 't') ? TF : (format == 'n') ? NF : DF;
597 		av[1] = pxwidth;
598 		av[2] = pxlength;
599 		n = 3;
600 		break;
601 	case 'c':	/* print cifplot output */
602 		prog = CF;
603 		av[1] = pxwidth;
604 		av[2] = pxlength;
605 		n = 3;
606 		break;
607 	case 'g':	/* print plot(1G) output */
608 		prog = GF;
609 		av[1] = pxwidth;
610 		av[2] = pxlength;
611 		n = 3;
612 		break;
613 	case 'v':	/* print raster output */
614 		prog = VF;
615 		av[1] = pxwidth;
616 		av[2] = pxlength;
617 		n = 3;
618 		break;
619 	default:
620 		(void) close(fi);
621 		syslog(LOG_ERR, "%s: illegal format character '%c'",
622 			printer, format);
623 		return(ERROR);
624 	}
625 	if ((av[0] = rindex(prog, '/')) != NULL)
626 		av[0]++;
627 	else
628 		av[0] = prog;
629 	av[n++] = "-n";
630 	av[n++] = logname;
631 	av[n++] = "-h";
632 	av[n++] = fromhost;
633 	av[n++] = AF;
634 	av[n] = 0;
635 	fo = pfd;
636 	if (ofilter > 0) {		/* stop output filter */
637 		write(ofd, "\031\1", 2);
638 		while ((pid =
639 		    wait3((int *)&status, WUNTRACED, 0)) > 0 && pid != ofilter)
640 			;
641 		if (status.w_stopval != WSTOPPED) {
642 			(void) close(fi);
643 			syslog(LOG_WARNING, "%s: output filter died (%d)",
644 				printer, status.w_retcode);
645 			return(REPRINT);
646 		}
647 		stopped++;
648 	}
649 start:
650 	if ((child = dofork(DORETURN)) == 0) {	/* child */
651 		dup2(fi, 0);
652 		dup2(fo, 1);
653 		n = open(tempfile, O_WRONLY|O_CREAT|O_TRUNC, 0664);
654 		if (n >= 0)
655 			dup2(n, 2);
656 		closelog();
657 		for (n = 3; n < NOFILE; n++)
658 			(void) close(n);
659 		execv(prog, av);
660 		openlog("lpd", LOG_PID, LOG_LPR);
661 		syslog(LOG_ERR, "cannot execv %s", prog);
662 		exit(2);
663 	}
664 	(void) close(fi);
665 	if (child < 0)
666 		status.w_retcode = 100;
667 	else
668 		while ((pid = wait((int *)&status)) > 0 && pid != child)
669 			;
670 	child = 0;
671 	prchild = 0;
672 	if (stopped) {		/* restart output filter */
673 		if (kill(ofilter, SIGCONT) < 0) {
674 			syslog(LOG_ERR, "cannot restart output filter");
675 			exit(1);
676 		}
677 	}
678 	tof = 0;
679 
680 	/* Copy filter output to "lf" logfile */
681 	if (fp = fopen(tempfile, "r")) {
682 		while (fgets(buf, sizeof(buf), fp))
683 			fputs(buf, stderr);
684 		fclose(fp);
685 	}
686 
687 	if (!WIFEXITED(status)) {
688 		syslog(LOG_WARNING, "%s: Daemon filter '%c' terminated (%d)",
689 			printer, format, status.w_termsig);
690 		return(ERROR);
691 	}
692 	switch (status.w_retcode) {
693 	case 0:
694 		tof = 1;
695 		return(OK);
696 	case 1:
697 		return(REPRINT);
698 	default:
699 		syslog(LOG_WARNING, "%s: Daemon filter '%c' exited (%d)",
700 			printer, format, status.w_retcode);
701 	case 2:
702 		return(ERROR);
703 	}
704 }
705 
706 /*
707  * Send the daemon control file (cf) and any data files.
708  * Return -1 if a non-recoverable error occured, 1 if a recoverable error and
709  * 0 if all is well.
710  */
711 static int
712 sendit(file)
713 	char *file;
714 {
715 	register int i, err = OK;
716 	char *cp, last[BUFSIZ];
717 
718 	/*
719 	 * open control file
720 	 */
721 	if ((cfp = fopen(file, "r")) == NULL)
722 		return(OK);
723 	/*
724 	 *      read the control file for work to do
725 	 *
726 	 *      file format -- first character in the line is a command
727 	 *      rest of the line is the argument.
728 	 *      commands of interest are:
729 	 *
730 	 *            a-z -- "file name" name of file to print
731 	 *              U -- "unlink" name of file to remove
732 	 *                    (after we print it. (Pass 2 only)).
733 	 */
734 
735 	/*
736 	 * pass 1
737 	 */
738 	while (getline(cfp)) {
739 	again:
740 		if (line[0] == 'S') {
741 			cp = line+1;
742 			i = 0;
743 			while (*cp >= '0' && *cp <= '9')
744 				i = i * 10 + (*cp++ - '0');
745 			fdev = i;
746 			cp++;
747 			i = 0;
748 			while (*cp >= '0' && *cp <= '9')
749 				i = i * 10 + (*cp++ - '0');
750 			fino = i;
751 			continue;
752 		}
753 		if (line[0] >= 'a' && line[0] <= 'z') {
754 			strcpy(last, line);
755 			while (i = getline(cfp))
756 				if (strcmp(last, line))
757 					break;
758 			switch (sendfile('\3', last+1)) {
759 			case OK:
760 				if (i)
761 					goto again;
762 				break;
763 			case REPRINT:
764 				(void) fclose(cfp);
765 				return(REPRINT);
766 			case ACCESS:
767 				sendmail(logname, ACCESS);
768 			case ERROR:
769 				err = ERROR;
770 			}
771 			break;
772 		}
773 	}
774 	if (err == OK && sendfile('\2', file) > 0) {
775 		(void) fclose(cfp);
776 		return(REPRINT);
777 	}
778 	/*
779 	 * pass 2
780 	 */
781 	fseek(cfp, 0L, 0);
782 	while (getline(cfp))
783 		if (line[0] == 'U')
784 			(void) unlink(line+1);
785 	/*
786 	 * clean-up in case another control file exists
787 	 */
788 	(void) fclose(cfp);
789 	(void) unlink(file);
790 	return(err);
791 }
792 
793 /*
794  * Send a data file to the remote machine and spool it.
795  * Return positive if we should try resending.
796  */
797 static int
798 sendfile(type, file)
799 	int type;
800 	char *file;
801 {
802 	register int f, i, amt;
803 	struct stat stb;
804 	char buf[BUFSIZ];
805 	int sizerr, resp;
806 
807 	if (lstat(file, &stb) < 0 || (f = open(file, O_RDONLY)) < 0)
808 		return(ERROR);
809 	/*
810 	 * Check to see if data file is a symbolic link. If so, it should
811 	 * still point to the same file or someone is trying to print something
812 	 * he shouldn't.
813 	 */
814 	if ((stb.st_mode & S_IFMT) == S_IFLNK && fstat(f, &stb) == 0 &&
815 	    (stb.st_dev != fdev || stb.st_ino != fino))
816 		return(ACCESS);
817 	(void) sprintf(buf, "%c%qd %s\n", type, stb.st_size, file);
818 	amt = strlen(buf);
819 	for (i = 0;  ; i++) {
820 		if (write(pfd, buf, amt) != amt ||
821 		    (resp = response()) < 0 || resp == '\1') {
822 			(void) close(f);
823 			return(REPRINT);
824 		} else if (resp == '\0')
825 			break;
826 		if (i == 0)
827 			pstatus("no space on remote; waiting for queue to drain");
828 		if (i == 10)
829 			syslog(LOG_ALERT, "%s: can't send to %s; queue full",
830 				printer, RM);
831 		sleep(5 * 60);
832 	}
833 	if (i)
834 		pstatus("sending to %s", RM);
835 	sizerr = 0;
836 	for (i = 0; i < stb.st_size; i += BUFSIZ) {
837 		amt = BUFSIZ;
838 		if (i + amt > stb.st_size)
839 			amt = stb.st_size - i;
840 		if (sizerr == 0 && read(f, buf, amt) != amt)
841 			sizerr = 1;
842 		if (write(pfd, buf, amt) != amt) {
843 			(void) close(f);
844 			return(REPRINT);
845 		}
846 	}
847 
848 
849 
850 
851 	(void) close(f);
852 	if (sizerr) {
853 		syslog(LOG_INFO, "%s: %s: changed size", printer, file);
854 		/* tell recvjob to ignore this file */
855 		(void) write(pfd, "\1", 1);
856 		return(ERROR);
857 	}
858 	if (write(pfd, "", 1) != 1 || response())
859 		return(REPRINT);
860 	return(OK);
861 }
862 
863 /*
864  * Check to make sure there have been no errors and that both programs
865  * are in sync with eachother.
866  * Return non-zero if the connection was lost.
867  */
868 static char
869 response()
870 {
871 	char resp;
872 
873 	if (read(pfd, &resp, 1) != 1) {
874 		syslog(LOG_INFO, "%s: lost connection", printer);
875 		return(-1);
876 	}
877 	return(resp);
878 }
879 
880 /*
881  * Banner printing stuff
882  */
883 static void
884 banner(name1, name2)
885 	char *name1, *name2;
886 {
887 	time_t tvec;
888 	extern char *ctime();
889 
890 	time(&tvec);
891 	if (!SF && !tof)
892 		(void) write(ofd, FF, strlen(FF));
893 	if (SB) {	/* short banner only */
894 		if (class[0]) {
895 			(void) write(ofd, class, strlen(class));
896 			(void) write(ofd, ":", 1);
897 		}
898 		(void) write(ofd, name1, strlen(name1));
899 		(void) write(ofd, "  Job: ", 7);
900 		(void) write(ofd, name2, strlen(name2));
901 		(void) write(ofd, "  Date: ", 8);
902 		(void) write(ofd, ctime(&tvec), 24);
903 		(void) write(ofd, "\n", 1);
904 	} else {	/* normal banner */
905 		(void) write(ofd, "\n\n\n", 3);
906 		scan_out(ofd, name1, '\0');
907 		(void) write(ofd, "\n\n", 2);
908 		scan_out(ofd, name2, '\0');
909 		if (class[0]) {
910 			(void) write(ofd,"\n\n\n",3);
911 			scan_out(ofd, class, '\0');
912 		}
913 		(void) write(ofd, "\n\n\n\n\t\t\t\t\tJob:  ", 15);
914 		(void) write(ofd, name2, strlen(name2));
915 		(void) write(ofd, "\n\t\t\t\t\tDate: ", 12);
916 		(void) write(ofd, ctime(&tvec), 24);
917 		(void) write(ofd, "\n", 1);
918 	}
919 	if (!SF)
920 		(void) write(ofd, FF, strlen(FF));
921 	tof = 1;
922 }
923 
924 static char *
925 scnline(key, p, c)
926 	register int key;
927 	register char *p;
928 	int c;
929 {
930 	register scnwidth;
931 
932 	for (scnwidth = WIDTH; --scnwidth;) {
933 		key <<= 1;
934 		*p++ = key & 0200 ? c : BACKGND;
935 	}
936 	return (p);
937 }
938 
939 #define TRC(q)	(((q)-' ')&0177)
940 
941 static void
942 scan_out(scfd, scsp, dlm)
943 	int scfd, dlm;
944 	char *scsp;
945 {
946 	register char *strp;
947 	register nchrs, j;
948 	char outbuf[LINELEN+1], *sp, c, cc;
949 	int d, scnhgt;
950 	extern char scnkey[][HEIGHT];	/* in lpdchar.c */
951 
952 	for (scnhgt = 0; scnhgt++ < HEIGHT+DROP; ) {
953 		strp = &outbuf[0];
954 		sp = scsp;
955 		for (nchrs = 0; ; ) {
956 			d = dropit(c = TRC(cc = *sp++));
957 			if ((!d && scnhgt > HEIGHT) || (scnhgt <= DROP && d))
958 				for (j = WIDTH; --j;)
959 					*strp++ = BACKGND;
960 			else
961 				strp = scnline(scnkey[c][scnhgt-1-d], strp, cc);
962 			if (*sp == dlm || *sp == '\0' || nchrs++ >= PW/(WIDTH+1)-1)
963 				break;
964 			*strp++ = BACKGND;
965 			*strp++ = BACKGND;
966 		}
967 		while (*--strp == BACKGND && strp >= outbuf)
968 			;
969 		strp++;
970 		*strp++ = '\n';
971 		(void) write(scfd, outbuf, strp-outbuf);
972 	}
973 }
974 
975 static int
976 dropit(c)
977 	int c;
978 {
979 	switch(c) {
980 
981 	case TRC('_'):
982 	case TRC(';'):
983 	case TRC(','):
984 	case TRC('g'):
985 	case TRC('j'):
986 	case TRC('p'):
987 	case TRC('q'):
988 	case TRC('y'):
989 		return (DROP);
990 
991 	default:
992 		return (0);
993 	}
994 }
995 
996 /*
997  * sendmail ---
998  *   tell people about job completion
999  */
1000 static void
1001 sendmail(user, bombed)
1002 	char *user;
1003 	int bombed;
1004 {
1005 	register int i;
1006 	int p[2], s;
1007 	register char *cp;
1008 	char buf[100];
1009 	struct stat stb;
1010 	FILE *fp;
1011 
1012 	pipe(p);
1013 	if ((s = dofork(DORETURN)) == 0) {		/* child */
1014 		dup2(p[0], 0);
1015 		closelog();
1016 		for (i = 3; i < NOFILE; i++)
1017 			(void) close(i);
1018 		if ((cp = rindex(_PATH_SENDMAIL, '/')) != NULL)
1019 			cp++;
1020 	else
1021 			cp = _PATH_SENDMAIL;
1022 		sprintf(buf, "%s@%s", user, fromhost);
1023 		execl(_PATH_SENDMAIL, cp, buf, 0);
1024 		openlog("lpd", LOG_PID, LOG_LPR);
1025 		syslog(LOG_ERR, "cannot execl %s", _PATH_SENDMAIL);
1026 		exit(0);
1027 	} else if (s > 0) {				/* parent */
1028 		dup2(p[1], 1);
1029 		printf("To: %s@%s\n", user, fromhost);
1030 		printf("Subject: printer job\n\n");
1031 		printf("Your printer job ");
1032 		if (*jobname)
1033 			printf("(%s) ", jobname);
1034 		switch (bombed) {
1035 		case OK:
1036 			printf("\ncompleted successfully\n");
1037 			break;
1038 		default:
1039 		case FATALERR:
1040 			printf("\ncould not be printed\n");
1041 			break;
1042 		case NOACCT:
1043 			printf("\ncould not be printed without an account on %s\n", host);
1044 			break;
1045 		case FILTERERR:
1046 			if (stat(tempfile, &stb) < 0 || stb.st_size == 0 ||
1047 			    (fp = fopen(tempfile, "r")) == NULL) {
1048 				printf("\nwas printed but had some errors\n");
1049 				break;
1050 			}
1051 			printf("\nwas printed but had the following errors:\n");
1052 			while ((i = getc(fp)) != EOF)
1053 				putchar(i);
1054 			(void) fclose(fp);
1055 			break;
1056 		case ACCESS:
1057 			printf("\nwas not printed because it was not linked to the original file\n");
1058 		}
1059 		fflush(stdout);
1060 		(void) close(1);
1061 	}
1062 	(void) close(p[0]);
1063 	(void) close(p[1]);
1064 	wait(&s);
1065 }
1066 
1067 /*
1068  * dofork - fork with retries on failure
1069  */
1070 static int
1071 dofork(action)
1072 	int action;
1073 {
1074 	register int i, pid;
1075 	struct passwd *pwd;
1076 
1077 	for (i = 0; i < 20; i++) {
1078 		if ((pid = fork()) < 0) {
1079 			sleep((unsigned)(i*i));
1080 			continue;
1081 		}
1082 		/*
1083 		 * Child should run as daemon instead of root
1084 		 */
1085 		if (pid == 0) {
1086 			if ((pwd = getpwuid(DU)) == NULL) {
1087 				syslog(LOG_ERR, "Can't lookup default uid in password file");
1088 				break;
1089 			}
1090 			initgroups(pwd->pw_name, pwd->pw_gid);
1091 			setgid(pwd->pw_gid);
1092 			setuid(DU);
1093 		}
1094 		return(pid);
1095 	}
1096 	syslog(LOG_ERR, "can't fork");
1097 
1098 	switch (action) {
1099 	case DORETURN:
1100 		return (-1);
1101 	default:
1102 		syslog(LOG_ERR, "bad action (%d) to dofork", action);
1103 		/*FALL THRU*/
1104 	case DOABORT:
1105 		exit(1);
1106 	}
1107 	/*NOTREACHED*/
1108 }
1109 
1110 /*
1111  * Kill child processes to abort current job.
1112  */
1113 static void
1114 abortpr(signo)
1115 	int signo;
1116 {
1117 	(void) unlink(tempfile);
1118 	kill(0, SIGINT);
1119 	if (ofilter > 0)
1120 		kill(ofilter, SIGCONT);
1121 	while (wait(NULL) > 0)
1122 		;
1123 	exit(0);
1124 }
1125 
1126 static void
1127 init()
1128 {
1129 	int status;
1130 	char *s;
1131 
1132 	if ((status = cgetent(&bp, printcapdb, printer)) == -2) {
1133 		syslog(LOG_ERR, "can't open printer description file");
1134 		exit(1);
1135 	} else if (status == -1) {
1136 		syslog(LOG_ERR, "unknown printer: %s", printer);
1137 		exit(1);
1138 	} else if (status == -3)
1139 		fatal("potential reference loop detected in printcap file");
1140 
1141 	if (cgetstr(bp, "lp", &LP) == -1)
1142 		LP = _PATH_DEFDEVLP;
1143 	if (cgetstr(bp, "rp", &RP) == -1)
1144 		RP = DEFLP;
1145 	if (cgetstr(bp, "lo", &LO) == -1)
1146 		LO = DEFLOCK;
1147 	if (cgetstr(bp, "st", &ST) == -1)
1148 		ST = DEFSTAT;
1149 	if (cgetstr(bp, "lf", &LF) == -1)
1150 		LF = _PATH_CONSOLE;
1151 	if (cgetstr(bp, "sd", &SD) == -1)
1152 		SD = _PATH_DEFSPOOL;
1153 	if (cgetnum(bp, "du", &DU) < 0)
1154 		DU = DEFUID;
1155 	if (cgetstr(bp,"ff", &FF) == -1)
1156 		FF = DEFFF;
1157 	if (cgetnum(bp, "pw", &PW) < 0)
1158 		PW = DEFWIDTH;
1159 	sprintf(&width[2], "%d", PW);
1160 	if (cgetnum(bp, "pl", &PL) < 0)
1161 		PL = DEFLENGTH;
1162 	sprintf(&length[2], "%d", PL);
1163 	if (cgetnum(bp,"px", &PX) < 0)
1164 		PX = 0;
1165 	sprintf(&pxwidth[2], "%d", PX);
1166 	if (cgetnum(bp, "py", &PY) < 0)
1167 		PY = 0;
1168 	sprintf(&pxlength[2], "%d", PY);
1169 	cgetstr(bp, "rm", &RM);
1170 	if (s = checkremote())
1171 		syslog(LOG_WARNING, s);
1172 
1173 	cgetstr(bp, "af", &AF);
1174 	cgetstr(bp, "of", &OF);
1175 	cgetstr(bp, "if", &IF);
1176 	cgetstr(bp, "rf", &RF);
1177 	cgetstr(bp, "tf", &TF);
1178 	cgetstr(bp, "nf", &NF);
1179 	cgetstr(bp, "df", &DF);
1180 	cgetstr(bp, "gf", &GF);
1181 	cgetstr(bp, "vf", &VF);
1182 	cgetstr(bp, "cf", &CF);
1183 	cgetstr(bp, "tr", &TR);
1184 
1185 	RS = (cgetcap(bp, "rs", ':') != NULL);
1186 	SF = (cgetcap(bp, "sf", ':') != NULL);
1187 	SH = (cgetcap(bp, "sh", ':') != NULL);
1188 	SB = (cgetcap(bp, "sb", ':') != NULL);
1189 	HL = (cgetcap(bp, "hl", ':') != NULL);
1190 	RW = (cgetcap(bp, "rw", ':') != NULL);
1191 
1192 	cgetnum(bp, "br", &BR);
1193 	if (cgetnum(bp, "fc", &FC) < 0)
1194 		FC = 0;
1195 	if (cgetnum(bp, "fs", &FS) < 0)
1196 		FS = 0;
1197 	if (cgetnum(bp, "xc", &XC) < 0)
1198 		XC = 0;
1199 	if (cgetnum(bp, "xs", &XS) < 0)
1200 		XS = 0;
1201 
1202 	tof = (cgetcap(bp, "fo", ':') == NULL);
1203 }
1204 
1205 /*
1206  * Acquire line printer or remote connection.
1207  */
1208 static void
1209 openpr()
1210 {
1211 	register int i, n;
1212 	int resp;
1213 
1214 	if (!sendtorem && *LP) {
1215 		for (i = 1; ; i = i < 32 ? i << 1 : i) {
1216 			pfd = open(LP, RW ? O_RDWR : O_WRONLY);
1217 			if (pfd >= 0)
1218 				break;
1219 			if (errno == ENOENT) {
1220 				syslog(LOG_ERR, "%s: %m", LP);
1221 				exit(1);
1222 			}
1223 			if (i == 1)
1224 				pstatus("waiting for %s to become ready (offline ?)", printer);
1225 			sleep(i);
1226 		}
1227 		if (isatty(pfd))
1228 			setty();
1229 		pstatus("%s is ready and printing", printer);
1230 	} else if (RM != NULL) {
1231 		for (i = 1; ; i = i < 256 ? i << 1 : i) {
1232 			resp = -1;
1233 			pfd = getport(RM);
1234 			if (pfd >= 0) {
1235 				(void) sprintf(line, "\2%s\n", RP);
1236 				n = strlen(line);
1237 				if (write(pfd, line, n) == n &&
1238 				    (resp = response()) == '\0')
1239 					break;
1240 				(void) close(pfd);
1241 			}
1242 			if (i == 1) {
1243 				if (resp < 0)
1244 					pstatus("waiting for %s to come up", RM);
1245 				else {
1246 					pstatus("waiting for queue to be enabled on %s", RM);
1247 					i = 256;
1248 				}
1249 			}
1250 			sleep(i);
1251 		}
1252 		pstatus("sending to %s", RM);
1253 		remote = 1;
1254 	} else {
1255 		syslog(LOG_ERR, "%s: no line printer device or host name",
1256 			printer);
1257 		exit(1);
1258 	}
1259 	/*
1260 	 * Start up an output filter, if needed.
1261 	 */
1262 	if (!remote && OF) {
1263 		int p[2];
1264 		char *cp;
1265 
1266 		pipe(p);
1267 		if ((ofilter = dofork(DOABORT)) == 0) {	/* child */
1268 			dup2(p[0], 0);		/* pipe is std in */
1269 			dup2(pfd, 1);		/* printer is std out */
1270 			closelog();
1271 			for (i = 3; i < NOFILE; i++)
1272 				(void) close(i);
1273 			if ((cp = rindex(OF, '/')) == NULL)
1274 				cp = OF;
1275 			else
1276 				cp++;
1277 			execl(OF, cp, width, length, 0);
1278 			openlog("lpd", LOG_PID, LOG_LPR);
1279 			syslog(LOG_ERR, "%s: %s: %m", printer, OF);
1280 			exit(1);
1281 		}
1282 		(void) close(p[0]);		/* close input side */
1283 		ofd = p[1];			/* use pipe for output */
1284 	} else {
1285 		ofd = pfd;
1286 		ofilter = 0;
1287 	}
1288 }
1289 
1290 struct bauds {
1291 	int	baud;
1292 	int	speed;
1293 } bauds[] = {
1294 	50,	B50,
1295 	75,	B75,
1296 	110,	B110,
1297 	134,	B134,
1298 	150,	B150,
1299 	200,	B200,
1300 	300,	B300,
1301 	600,	B600,
1302 	1200,	B1200,
1303 	1800,	B1800,
1304 	2400,	B2400,
1305 	4800,	B4800,
1306 	9600,	B9600,
1307 	19200,	EXTA,
1308 	38400,	EXTB,
1309 	57600,	B57600,
1310 	115200,	B115200,
1311 	0,	0
1312 };
1313 
1314 /*
1315  * setup tty lines.
1316  */
1317 static void
1318 setty()
1319 {
1320 	struct sgttyb ttybuf;
1321 	register struct bauds *bp;
1322 
1323 	if (ioctl(pfd, TIOCEXCL, (char *)0) < 0) {
1324 		syslog(LOG_ERR, "%s: ioctl(TIOCEXCL): %m", printer);
1325 		exit(1);
1326 	}
1327 	if (ioctl(pfd, TIOCGETP, (char *)&ttybuf) < 0) {
1328 		syslog(LOG_ERR, "%s: ioctl(TIOCGETP): %m", printer);
1329 		exit(1);
1330 	}
1331 	if (BR > 0) {
1332 		for (bp = bauds; bp->baud; bp++)
1333 			if (BR == bp->baud)
1334 				break;
1335 		if (!bp->baud) {
1336 			syslog(LOG_ERR, "%s: illegal baud rate %d", printer, BR);
1337 			exit(1);
1338 		}
1339 		ttybuf.sg_ispeed = ttybuf.sg_ospeed = bp->speed;
1340 	}
1341 	ttybuf.sg_flags &= ~FC;
1342 	ttybuf.sg_flags |= FS;
1343 	if (ioctl(pfd, TIOCSETP, (char *)&ttybuf) < 0) {
1344 		syslog(LOG_ERR, "%s: ioctl(TIOCSETP): %m", printer);
1345 		exit(1);
1346 	}
1347 	if (XC) {
1348 		if (ioctl(pfd, TIOCLBIC, &XC) < 0) {
1349 			syslog(LOG_ERR, "%s: ioctl(TIOCLBIC): %m", printer);
1350 			exit(1);
1351 		}
1352 	}
1353 	if (XS) {
1354 		if (ioctl(pfd, TIOCLBIS, &XS) < 0) {
1355 			syslog(LOG_ERR, "%s: ioctl(TIOCLBIS): %m", printer);
1356 			exit(1);
1357 		}
1358 	}
1359 }
1360 
1361 #if __STDC__
1362 #include <stdarg.h>
1363 #else
1364 #include <varargs.h>
1365 #endif
1366 
1367 void
1368 #if __STDC__
1369 pstatus(const char *msg, ...)
1370 #else
1371 pstatus(msg, va_alist)
1372 	char *msg;
1373         va_dcl
1374 #endif
1375 {
1376 	register int fd;
1377 	char buf[BUFSIZ];
1378 	va_list ap;
1379 #if __STDC__
1380 	va_start(ap, msg);
1381 #else
1382 	va_start(ap);
1383 #endif
1384 
1385 	umask(0);
1386 	fd = open(ST, O_WRONLY|O_CREAT, 0664);
1387 	if (fd < 0 || flock(fd, LOCK_EX) < 0) {
1388 		syslog(LOG_ERR, "%s: %s: %m", printer, ST);
1389 		exit(1);
1390 	}
1391 	ftruncate(fd, 0);
1392 	(void)vsnprintf(buf, sizeof(buf), msg, ap);
1393 	va_end(ap);
1394 	strcat(buf, "\n");
1395 	(void) write(fd, buf, strlen(buf));
1396 	(void) close(fd);
1397 }
1398