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