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