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