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