xref: /netbsd-src/usr.sbin/lpr/lpd/printjob.c (revision ae9172d6cd9432a6a1a56760d86b32c57a66c39c)
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] = 0;
533 			fo = ofd;
534 			goto start;
535 		}
536 		pipe(p);
537 		if ((prchild = dofork(DORETURN)) == 0) {	/* child */
538 			dup2(fi, 0);		/* file is stdin */
539 			dup2(p[1], 1);		/* pipe is stdout */
540 			for (n = 3; n < NOFILE; n++)
541 				(void) close(n);
542 			execl(_PATH_PR, "pr", width, length,
543 			    "-h", *title ? title : " ", 0);
544 			syslog(LOG_ERR, "cannot execl %s", _PATH_PR);
545 			exit(2);
546 		}
547 		(void) close(p[1]);		/* close output side */
548 		(void) close(fi);
549 		if (prchild < 0) {
550 			prchild = 0;
551 			(void) close(p[0]);
552 			return(ERROR);
553 		}
554 		fi = p[0];			/* use pipe for input */
555 	case 'f':	/* print plain text file */
556 		prog = IF;
557 		av[1] = width;
558 		av[2] = length;
559 		av[3] = indent;
560 		n = 4;
561 		break;
562 	case 'l':	/* like 'f' but pass control characters */
563 		prog = IF;
564 		av[1] = "-c";
565 		av[2] = width;
566 		av[3] = length;
567 		av[4] = indent;
568 		n = 5;
569 		break;
570 	case 'r':	/* print a fortran text file */
571 		prog = RF;
572 		av[1] = width;
573 		av[2] = length;
574 		n = 3;
575 		break;
576 	case 't':	/* print troff output */
577 	case 'n':	/* print ditroff output */
578 	case 'd':	/* print tex output */
579 		(void) unlink(".railmag");
580 		if ((fo = creat(".railmag", FILMOD)) < 0) {
581 			syslog(LOG_ERR, "%s: cannot create .railmag", printer);
582 			(void) unlink(".railmag");
583 		} else {
584 			for (n = 0; n < 4; n++) {
585 				if (fonts[n][0] != '/')
586 					(void) write(fo, _PATH_VFONT,
587 					    sizeof(_PATH_VFONT) - 1);
588 				(void) write(fo, fonts[n], strlen(fonts[n]));
589 				(void) write(fo, "\n", 1);
590 			}
591 			(void) close(fo);
592 		}
593 		prog = (format == 't') ? TF : (format == 'n') ? NF : DF;
594 		av[1] = pxwidth;
595 		av[2] = pxlength;
596 		n = 3;
597 		break;
598 	case 'c':	/* print cifplot output */
599 		prog = CF;
600 		av[1] = pxwidth;
601 		av[2] = pxlength;
602 		n = 3;
603 		break;
604 	case 'g':	/* print plot(1G) output */
605 		prog = GF;
606 		av[1] = pxwidth;
607 		av[2] = pxlength;
608 		n = 3;
609 		break;
610 	case 'v':	/* print raster output */
611 		prog = VF;
612 		av[1] = pxwidth;
613 		av[2] = pxlength;
614 		n = 3;
615 		break;
616 	default:
617 		(void) close(fi);
618 		syslog(LOG_ERR, "%s: illegal format character '%c'",
619 			printer, format);
620 		return(ERROR);
621 	}
622 	if ((av[0] = rindex(prog, '/')) != NULL)
623 		av[0]++;
624 	else
625 		av[0] = prog;
626 	av[n++] = "-n";
627 	av[n++] = logname;
628 	av[n++] = "-h";
629 	av[n++] = fromhost;
630 	av[n++] = AF;
631 	av[n] = 0;
632 	fo = pfd;
633 	if (ofilter > 0) {		/* stop output filter */
634 		write(ofd, "\031\1", 2);
635 		while ((pid =
636 		    wait3((int *)&status, WUNTRACED, 0)) > 0 && pid != ofilter)
637 			;
638 		if (status.w_stopval != WSTOPPED) {
639 			(void) close(fi);
640 			syslog(LOG_WARNING, "%s: output filter died (%d)",
641 				printer, status.w_retcode);
642 			return(REPRINT);
643 		}
644 		stopped++;
645 	}
646 start:
647 	if ((child = dofork(DORETURN)) == 0) {	/* child */
648 		dup2(fi, 0);
649 		dup2(fo, 1);
650 		n = open(tempfile, O_WRONLY|O_CREAT|O_TRUNC, 0664);
651 		if (n >= 0)
652 			dup2(n, 2);
653 		for (n = 3; n < NOFILE; n++)
654 			(void) close(n);
655 		execv(prog, av);
656 		syslog(LOG_ERR, "cannot execv %s", prog);
657 		exit(2);
658 	}
659 	(void) close(fi);
660 	if (child < 0)
661 		status.w_retcode = 100;
662 	else
663 		while ((pid = wait((int *)&status)) > 0 && pid != child)
664 			;
665 	child = 0;
666 	prchild = 0;
667 	if (stopped) {		/* restart output filter */
668 		if (kill(ofilter, SIGCONT) < 0) {
669 			syslog(LOG_ERR, "cannot restart output filter");
670 			exit(1);
671 		}
672 	}
673 	tof = 0;
674 
675 	/* Copy filter output to "lf" logfile */
676 	if (fp = fopen(tempfile, "r")) {
677 		while (fgets(buf, sizeof(buf), fp))
678 			fputs(buf, stderr);
679 		fclose(fp);
680 	}
681 
682 	if (!WIFEXITED(status)) {
683 		syslog(LOG_WARNING, "%s: Daemon filter '%c' terminated (%d)",
684 			printer, format, status.w_termsig);
685 		return(ERROR);
686 	}
687 	switch (status.w_retcode) {
688 	case 0:
689 		tof = 1;
690 		return(OK);
691 	case 1:
692 		return(REPRINT);
693 	default:
694 		syslog(LOG_WARNING, "%s: Daemon filter '%c' exited (%d)",
695 			printer, format, status.w_retcode);
696 	case 2:
697 		return(ERROR);
698 	}
699 }
700 
701 /*
702  * Send the daemon control file (cf) and any data files.
703  * Return -1 if a non-recoverable error occured, 1 if a recoverable error and
704  * 0 if all is well.
705  */
706 static int
707 sendit(file)
708 	char *file;
709 {
710 	register int i, err = OK;
711 	char *cp, last[BUFSIZ];
712 
713 	/*
714 	 * open control file
715 	 */
716 	if ((cfp = fopen(file, "r")) == NULL)
717 		return(OK);
718 	/*
719 	 *      read the control file for work to do
720 	 *
721 	 *      file format -- first character in the line is a command
722 	 *      rest of the line is the argument.
723 	 *      commands of interest are:
724 	 *
725 	 *            a-z -- "file name" name of file to print
726 	 *              U -- "unlink" name of file to remove
727 	 *                    (after we print it. (Pass 2 only)).
728 	 */
729 
730 	/*
731 	 * pass 1
732 	 */
733 	while (getline(cfp)) {
734 	again:
735 		if (line[0] == 'S') {
736 			cp = line+1;
737 			i = 0;
738 			while (*cp >= '0' && *cp <= '9')
739 				i = i * 10 + (*cp++ - '0');
740 			fdev = i;
741 			cp++;
742 			i = 0;
743 			while (*cp >= '0' && *cp <= '9')
744 				i = i * 10 + (*cp++ - '0');
745 			fino = i;
746 			continue;
747 		}
748 		if (line[0] >= 'a' && line[0] <= 'z') {
749 			strcpy(last, line);
750 			while (i = getline(cfp))
751 				if (strcmp(last, line))
752 					break;
753 			switch (sendfile('\3', last+1)) {
754 			case OK:
755 				if (i)
756 					goto again;
757 				break;
758 			case REPRINT:
759 				(void) fclose(cfp);
760 				return(REPRINT);
761 			case ACCESS:
762 				sendmail(logname, ACCESS);
763 			case ERROR:
764 				err = ERROR;
765 			}
766 			break;
767 		}
768 	}
769 	if (err == OK && sendfile('\2', file) > 0) {
770 		(void) fclose(cfp);
771 		return(REPRINT);
772 	}
773 	/*
774 	 * pass 2
775 	 */
776 	fseek(cfp, 0L, 0);
777 	while (getline(cfp))
778 		if (line[0] == 'U')
779 			(void) unlink(line+1);
780 	/*
781 	 * clean-up in case another control file exists
782 	 */
783 	(void) fclose(cfp);
784 	(void) unlink(file);
785 	return(err);
786 }
787 
788 /*
789  * Send a data file to the remote machine and spool it.
790  * Return positive if we should try resending.
791  */
792 static int
793 sendfile(type, file)
794 	int type;
795 	char *file;
796 {
797 	register int f, i, amt;
798 	struct stat stb;
799 	char buf[BUFSIZ];
800 	int sizerr, resp;
801 
802 	if (lstat(file, &stb) < 0 || (f = open(file, O_RDONLY)) < 0)
803 		return(ERROR);
804 	/*
805 	 * Check to see if data file is a symbolic link. If so, it should
806 	 * still point to the same file or someone is trying to print something
807 	 * he shouldn't.
808 	 */
809 	if ((stb.st_mode & S_IFMT) == S_IFLNK && fstat(f, &stb) == 0 &&
810 	    (stb.st_dev != fdev || stb.st_ino != fino))
811 		return(ACCESS);
812 	(void) sprintf(buf, "%c%qd %s\n", type, stb.st_size, file);
813 	amt = strlen(buf);
814 	for (i = 0;  ; i++) {
815 		if (write(pfd, buf, amt) != amt ||
816 		    (resp = response()) < 0 || resp == '\1') {
817 			(void) close(f);
818 			return(REPRINT);
819 		} else if (resp == '\0')
820 			break;
821 		if (i == 0)
822 			pstatus("no space on remote; waiting for queue to drain");
823 		if (i == 10)
824 			syslog(LOG_ALERT, "%s: can't send to %s; queue full",
825 				printer, RM);
826 		sleep(5 * 60);
827 	}
828 	if (i)
829 		pstatus("sending to %s", RM);
830 	sizerr = 0;
831 	for (i = 0; i < stb.st_size; i += BUFSIZ) {
832 		amt = BUFSIZ;
833 		if (i + amt > stb.st_size)
834 			amt = stb.st_size - i;
835 		if (sizerr == 0 && read(f, buf, amt) != amt)
836 			sizerr = 1;
837 		if (write(pfd, buf, amt) != amt) {
838 			(void) close(f);
839 			return(REPRINT);
840 		}
841 	}
842 
843 
844 
845 
846 	(void) close(f);
847 	if (sizerr) {
848 		syslog(LOG_INFO, "%s: %s: changed size", printer, file);
849 		/* tell recvjob to ignore this file */
850 		(void) write(pfd, "\1", 1);
851 		return(ERROR);
852 	}
853 	if (write(pfd, "", 1) != 1 || response())
854 		return(REPRINT);
855 	return(OK);
856 }
857 
858 /*
859  * Check to make sure there have been no errors and that both programs
860  * are in sync with eachother.
861  * Return non-zero if the connection was lost.
862  */
863 static char
864 response()
865 {
866 	char resp;
867 
868 	if (read(pfd, &resp, 1) != 1) {
869 		syslog(LOG_INFO, "%s: lost connection", printer);
870 		return(-1);
871 	}
872 	return(resp);
873 }
874 
875 /*
876  * Banner printing stuff
877  */
878 static void
879 banner(name1, name2)
880 	char *name1, *name2;
881 {
882 	time_t tvec;
883 	extern char *ctime();
884 
885 	time(&tvec);
886 	if (!SF && !tof)
887 		(void) write(ofd, FF, strlen(FF));
888 	if (SB) {	/* short banner only */
889 		if (class[0]) {
890 			(void) write(ofd, class, strlen(class));
891 			(void) write(ofd, ":", 1);
892 		}
893 		(void) write(ofd, name1, strlen(name1));
894 		(void) write(ofd, "  Job: ", 7);
895 		(void) write(ofd, name2, strlen(name2));
896 		(void) write(ofd, "  Date: ", 8);
897 		(void) write(ofd, ctime(&tvec), 24);
898 		(void) write(ofd, "\n", 1);
899 	} else {	/* normal banner */
900 		(void) write(ofd, "\n\n\n", 3);
901 		scan_out(ofd, name1, '\0');
902 		(void) write(ofd, "\n\n", 2);
903 		scan_out(ofd, name2, '\0');
904 		if (class[0]) {
905 			(void) write(ofd,"\n\n\n",3);
906 			scan_out(ofd, class, '\0');
907 		}
908 		(void) write(ofd, "\n\n\n\n\t\t\t\t\tJob:  ", 15);
909 		(void) write(ofd, name2, strlen(name2));
910 		(void) write(ofd, "\n\t\t\t\t\tDate: ", 12);
911 		(void) write(ofd, ctime(&tvec), 24);
912 		(void) write(ofd, "\n", 1);
913 	}
914 	if (!SF)
915 		(void) write(ofd, FF, strlen(FF));
916 	tof = 1;
917 }
918 
919 static char *
920 scnline(key, p, c)
921 	register int key;
922 	register char *p;
923 	int c;
924 {
925 	register scnwidth;
926 
927 	for (scnwidth = WIDTH; --scnwidth;) {
928 		key <<= 1;
929 		*p++ = key & 0200 ? c : BACKGND;
930 	}
931 	return (p);
932 }
933 
934 #define TRC(q)	(((q)-' ')&0177)
935 
936 static void
937 scan_out(scfd, scsp, dlm)
938 	int scfd, dlm;
939 	char *scsp;
940 {
941 	register char *strp;
942 	register nchrs, j;
943 	char outbuf[LINELEN+1], *sp, c, cc;
944 	int d, scnhgt;
945 	extern char scnkey[][HEIGHT];	/* in lpdchar.c */
946 
947 	for (scnhgt = 0; scnhgt++ < HEIGHT+DROP; ) {
948 		strp = &outbuf[0];
949 		sp = scsp;
950 		for (nchrs = 0; ; ) {
951 			d = dropit(c = TRC(cc = *sp++));
952 			if ((!d && scnhgt > HEIGHT) || (scnhgt <= DROP && d))
953 				for (j = WIDTH; --j;)
954 					*strp++ = BACKGND;
955 			else
956 				strp = scnline(scnkey[c][scnhgt-1-d], strp, cc);
957 			if (*sp == dlm || *sp == '\0' || nchrs++ >= PW/(WIDTH+1)-1)
958 				break;
959 			*strp++ = BACKGND;
960 			*strp++ = BACKGND;
961 		}
962 		while (*--strp == BACKGND && strp >= outbuf)
963 			;
964 		strp++;
965 		*strp++ = '\n';
966 		(void) write(scfd, outbuf, strp-outbuf);
967 	}
968 }
969 
970 static int
971 dropit(c)
972 	int c;
973 {
974 	switch(c) {
975 
976 	case TRC('_'):
977 	case TRC(';'):
978 	case TRC(','):
979 	case TRC('g'):
980 	case TRC('j'):
981 	case TRC('p'):
982 	case TRC('q'):
983 	case TRC('y'):
984 		return (DROP);
985 
986 	default:
987 		return (0);
988 	}
989 }
990 
991 /*
992  * sendmail ---
993  *   tell people about job completion
994  */
995 static void
996 sendmail(user, bombed)
997 	char *user;
998 	int bombed;
999 {
1000 	register int i;
1001 	int p[2], s;
1002 	register char *cp;
1003 	char buf[100];
1004 	struct stat stb;
1005 	FILE *fp;
1006 
1007 	pipe(p);
1008 	if ((s = dofork(DORETURN)) == 0) {		/* child */
1009 		dup2(p[0], 0);
1010 		for (i = 3; i < NOFILE; i++)
1011 			(void) close(i);
1012 		if ((cp = rindex(_PATH_SENDMAIL, '/')) != NULL)
1013 			cp++;
1014 	else
1015 			cp = _PATH_SENDMAIL;
1016 		sprintf(buf, "%s@%s", user, fromhost);
1017 		execl(_PATH_SENDMAIL, cp, buf, 0);
1018 		exit(0);
1019 	} else if (s > 0) {				/* parent */
1020 		dup2(p[1], 1);
1021 		printf("To: %s@%s\n", user, fromhost);
1022 		printf("Subject: printer job\n\n");
1023 		printf("Your printer job ");
1024 		if (*jobname)
1025 			printf("(%s) ", jobname);
1026 		switch (bombed) {
1027 		case OK:
1028 			printf("\ncompleted successfully\n");
1029 			break;
1030 		default:
1031 		case FATALERR:
1032 			printf("\ncould not be printed\n");
1033 			break;
1034 		case NOACCT:
1035 			printf("\ncould not be printed without an account on %s\n", host);
1036 			break;
1037 		case FILTERERR:
1038 			if (stat(tempfile, &stb) < 0 || stb.st_size == 0 ||
1039 			    (fp = fopen(tempfile, "r")) == NULL) {
1040 				printf("\nwas printed but had some errors\n");
1041 				break;
1042 			}
1043 			printf("\nwas printed but had the following errors:\n");
1044 			while ((i = getc(fp)) != EOF)
1045 				putchar(i);
1046 			(void) fclose(fp);
1047 			break;
1048 		case ACCESS:
1049 			printf("\nwas not printed because it was not linked to the original file\n");
1050 		}
1051 		fflush(stdout);
1052 		(void) close(1);
1053 	}
1054 	(void) close(p[0]);
1055 	(void) close(p[1]);
1056 	wait(&s);
1057 }
1058 
1059 /*
1060  * dofork - fork with retries on failure
1061  */
1062 static int
1063 dofork(action)
1064 	int action;
1065 {
1066 	register int i, pid;
1067 
1068 	for (i = 0; i < 20; i++) {
1069 		if ((pid = fork()) < 0) {
1070 			sleep((unsigned)(i*i));
1071 			continue;
1072 		}
1073 		/*
1074 		 * Child should run as daemon instead of root
1075 		 */
1076 		if (pid == 0)
1077 			setuid(DU);
1078 		return(pid);
1079 	}
1080 	syslog(LOG_ERR, "can't fork");
1081 
1082 	switch (action) {
1083 	case DORETURN:
1084 		return (-1);
1085 	default:
1086 		syslog(LOG_ERR, "bad action (%d) to dofork", action);
1087 		/*FALL THRU*/
1088 	case DOABORT:
1089 		exit(1);
1090 	}
1091 	/*NOTREACHED*/
1092 }
1093 
1094 /*
1095  * Kill child processes to abort current job.
1096  */
1097 static void
1098 abortpr(signo)
1099 	int signo;
1100 {
1101 	(void) unlink(tempfile);
1102 	kill(0, SIGINT);
1103 	if (ofilter > 0)
1104 		kill(ofilter, SIGCONT);
1105 	while (wait(NULL) > 0)
1106 		;
1107 	exit(0);
1108 }
1109 
1110 static void
1111 init()
1112 {
1113 	int status;
1114 	char *s;
1115 
1116 	if ((status = cgetent(&bp, printcapdb, printer)) == -2) {
1117 		syslog(LOG_ERR, "can't open printer description file");
1118 		exit(1);
1119 	} else if (status == -1) {
1120 		syslog(LOG_ERR, "unknown printer: %s", printer);
1121 		exit(1);
1122 	} else if (status == -3)
1123 		fatal("potential reference loop detected in printcap file");
1124 
1125 	if (cgetstr(bp, "lp", &LP) == -1)
1126 		LP = _PATH_DEFDEVLP;
1127 	if (cgetstr(bp, "rp", &RP) == -1)
1128 		RP = DEFLP;
1129 	if (cgetstr(bp, "lo", &LO) == -1)
1130 		LO = DEFLOCK;
1131 	if (cgetstr(bp, "st", &ST) == -1)
1132 		ST = DEFSTAT;
1133 	if (cgetstr(bp, "lf", &LF) == -1)
1134 		LF = _PATH_CONSOLE;
1135 	if (cgetstr(bp, "sd", &SD) == -1)
1136 		SD = _PATH_DEFSPOOL;
1137 	if (cgetnum(bp, "du", &DU) < 0)
1138 		DU = DEFUID;
1139 	if (cgetstr(bp,"ff", &FF) == -1)
1140 		FF = DEFFF;
1141 	if (cgetnum(bp, "pw", &PW) < 0)
1142 		PW = DEFWIDTH;
1143 	sprintf(&width[2], "%d", PW);
1144 	if (cgetnum(bp, "pl", &PL) < 0)
1145 		PL = DEFLENGTH;
1146 	sprintf(&length[2], "%d", PL);
1147 	if (cgetnum(bp,"px", &PX) < 0)
1148 		PX = 0;
1149 	sprintf(&pxwidth[2], "%d", PX);
1150 	if (cgetnum(bp, "py", &PY) < 0)
1151 		PY = 0;
1152 	sprintf(&pxlength[2], "%d", PY);
1153 	cgetstr(bp, "rm", &RM);
1154 	if (s = checkremote())
1155 		syslog(LOG_WARNING, s);
1156 
1157 	cgetstr(bp, "af", &AF);
1158 	cgetstr(bp, "of", &OF);
1159 	cgetstr(bp, "if", &IF);
1160 	cgetstr(bp, "rf", &RF);
1161 	cgetstr(bp, "tf", &TF);
1162 	cgetstr(bp, "nf", &NF);
1163 	cgetstr(bp, "df", &DF);
1164 	cgetstr(bp, "gf", &GF);
1165 	cgetstr(bp, "vf", &VF);
1166 	cgetstr(bp, "cf", &CF);
1167 	cgetstr(bp, "tr", &TR);
1168 
1169 	RS = (cgetcap(bp, "rs", ':') != NULL);
1170 	SF = (cgetcap(bp, "sf", ':') != NULL);
1171 	SH = (cgetcap(bp, "sh", ':') != NULL);
1172 	SB = (cgetcap(bp, "sb", ':') != NULL);
1173 	HL = (cgetcap(bp, "hl", ':') != NULL);
1174 	RW = (cgetcap(bp, "rw", ':') != NULL);
1175 
1176 	cgetnum(bp, "br", &BR);
1177 	if (cgetnum(bp, "fc", &FC) < 0)
1178 		FC = 0;
1179 	if (cgetnum(bp, "fs", &FS) < 0)
1180 		FS = 0;
1181 	if (cgetnum(bp, "xc", &XC) < 0)
1182 		XC = 0;
1183 	if (cgetnum(bp, "xs", &XS) < 0)
1184 		XS = 0;
1185 
1186 	tof = (cgetcap(bp, "fo", ':') == NULL);
1187 }
1188 
1189 /*
1190  * Acquire line printer or remote connection.
1191  */
1192 static void
1193 openpr()
1194 {
1195 	register int i, n;
1196 	int resp;
1197 
1198 	if (!sendtorem && *LP) {
1199 		for (i = 1; ; i = i < 32 ? i << 1 : i) {
1200 			pfd = open(LP, RW ? O_RDWR : O_WRONLY);
1201 			if (pfd >= 0)
1202 				break;
1203 			if (errno == ENOENT) {
1204 				syslog(LOG_ERR, "%s: %m", LP);
1205 				exit(1);
1206 			}
1207 			if (i == 1)
1208 				pstatus("waiting for %s to become ready (offline ?)", printer);
1209 			sleep(i);
1210 		}
1211 		if (isatty(pfd))
1212 			setty();
1213 		pstatus("%s is ready and printing", printer);
1214 	} else if (RM != NULL) {
1215 		for (i = 1; ; i = i < 256 ? i << 1 : i) {
1216 			resp = -1;
1217 			pfd = getport(RM);
1218 			if (pfd >= 0) {
1219 				(void) sprintf(line, "\2%s\n", RP);
1220 				n = strlen(line);
1221 				if (write(pfd, line, n) == n &&
1222 				    (resp = response()) == '\0')
1223 					break;
1224 				(void) close(pfd);
1225 			}
1226 			if (i == 1) {
1227 				if (resp < 0)
1228 					pstatus("waiting for %s to come up", RM);
1229 				else {
1230 					pstatus("waiting for queue to be enabled on %s", RM);
1231 					i = 256;
1232 				}
1233 			}
1234 			sleep(i);
1235 		}
1236 		pstatus("sending to %s", RM);
1237 		remote = 1;
1238 	} else {
1239 		syslog(LOG_ERR, "%s: no line printer device or host name",
1240 			printer);
1241 		exit(1);
1242 	}
1243 	/*
1244 	 * Start up an output filter, if needed.
1245 	 */
1246 	if (!remote && OF) {
1247 		int p[2];
1248 		char *cp;
1249 
1250 		pipe(p);
1251 		if ((ofilter = dofork(DOABORT)) == 0) {	/* child */
1252 			dup2(p[0], 0);		/* pipe is std in */
1253 			dup2(pfd, 1);		/* printer is std out */
1254 			for (i = 3; i < NOFILE; i++)
1255 				(void) close(i);
1256 			if ((cp = rindex(OF, '/')) == NULL)
1257 				cp = OF;
1258 			else
1259 				cp++;
1260 			execl(OF, cp, width, length, 0);
1261 			syslog(LOG_ERR, "%s: %s: %m", printer, OF);
1262 			exit(1);
1263 		}
1264 		(void) close(p[0]);		/* close input side */
1265 		ofd = p[1];			/* use pipe for output */
1266 	} else {
1267 		ofd = pfd;
1268 		ofilter = 0;
1269 	}
1270 }
1271 
1272 struct bauds {
1273 	int	baud;
1274 	int	speed;
1275 } bauds[] = {
1276 	50,	B50,
1277 	75,	B75,
1278 	110,	B110,
1279 	134,	B134,
1280 	150,	B150,
1281 	200,	B200,
1282 	300,	B300,
1283 	600,	B600,
1284 	1200,	B1200,
1285 	1800,	B1800,
1286 	2400,	B2400,
1287 	4800,	B4800,
1288 	9600,	B9600,
1289 	19200,	EXTA,
1290 	38400,	EXTB,
1291 	0,	0
1292 };
1293 
1294 /*
1295  * setup tty lines.
1296  */
1297 static void
1298 setty()
1299 {
1300 	struct sgttyb ttybuf;
1301 	register struct bauds *bp;
1302 
1303 	if (ioctl(pfd, TIOCEXCL, (char *)0) < 0) {
1304 		syslog(LOG_ERR, "%s: ioctl(TIOCEXCL): %m", printer);
1305 		exit(1);
1306 	}
1307 	if (ioctl(pfd, TIOCGETP, (char *)&ttybuf) < 0) {
1308 		syslog(LOG_ERR, "%s: ioctl(TIOCGETP): %m", printer);
1309 		exit(1);
1310 	}
1311 	if (BR > 0) {
1312 		for (bp = bauds; bp->baud; bp++)
1313 			if (BR == bp->baud)
1314 				break;
1315 		if (!bp->baud) {
1316 			syslog(LOG_ERR, "%s: illegal baud rate %d", printer, BR);
1317 			exit(1);
1318 		}
1319 		ttybuf.sg_ispeed = ttybuf.sg_ospeed = bp->speed;
1320 	}
1321 	ttybuf.sg_flags &= ~FC;
1322 	ttybuf.sg_flags |= FS;
1323 	if (ioctl(pfd, TIOCSETP, (char *)&ttybuf) < 0) {
1324 		syslog(LOG_ERR, "%s: ioctl(TIOCSETP): %m", printer);
1325 		exit(1);
1326 	}
1327 	if (XC) {
1328 		if (ioctl(pfd, TIOCLBIC, &XC) < 0) {
1329 			syslog(LOG_ERR, "%s: ioctl(TIOCLBIC): %m", printer);
1330 			exit(1);
1331 		}
1332 	}
1333 	if (XS) {
1334 		if (ioctl(pfd, TIOCLBIS, &XS) < 0) {
1335 			syslog(LOG_ERR, "%s: ioctl(TIOCLBIS): %m", printer);
1336 			exit(1);
1337 		}
1338 	}
1339 }
1340 
1341 #if __STDC__
1342 #include <stdarg.h>
1343 #else
1344 #include <varargs.h>
1345 #endif
1346 
1347 void
1348 #if __STDC__
1349 pstatus(const char *msg, ...)
1350 #else
1351 pstatus(msg, va_alist)
1352 	char *msg;
1353         va_dcl
1354 #endif
1355 {
1356 	register int fd;
1357 	char buf[BUFSIZ];
1358 	va_list ap;
1359 #if __STDC__
1360 	va_start(ap, msg);
1361 #else
1362 	va_start(ap);
1363 #endif
1364 
1365 	umask(0);
1366 	fd = open(ST, O_WRONLY|O_CREAT, 0664);
1367 	if (fd < 0 || flock(fd, LOCK_EX) < 0) {
1368 		syslog(LOG_ERR, "%s: %s: %m", printer, ST);
1369 		exit(1);
1370 	}
1371 	ftruncate(fd, 0);
1372 	(void)vsnprintf(buf, sizeof(buf), msg, ap);
1373 	va_end(ap);
1374 	strcat(buf, "\n");
1375 	(void) write(fd, buf, strlen(buf));
1376 	(void) close(fd);
1377 }
1378