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