xref: /freebsd/usr.sbin/lpr/lpd/printjob.c (revision daf1cffce2e07931f27c6c6998652e90df6ba87e)
1 /*
2  * Copyright (c) 1983, 1993
3  *	The Regents of the University of California.  All rights reserved.
4  *
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  * 3. All advertising materials mentioning features or use of this software
15  *    must display the following acknowledgement:
16  *	This product includes software developed by the University of
17  *	California, Berkeley and its contributors.
18  * 4. Neither the name of the University nor the names of its contributors
19  *    may be used to endorse or promote products derived from this software
20  *    without specific prior written permission.
21  *
22  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32  * SUCH DAMAGE.
33  */
34 
35 #ifndef lint
36 static const char copyright[] =
37 "@(#) Copyright (c) 1983, 1993\n\
38 	The Regents of the University of California.  All rights reserved.\n";
39 #endif /* not lint */
40 
41 #ifndef lint
42 /*
43 static char sccsid[] = "@(#)printjob.c	8.7 (Berkeley) 5/10/95";
44 */
45 static const char rcsid[] =
46   "$FreeBSD$";
47 #endif /* not lint */
48 
49 
50 /*
51  * printjob -- print jobs in the queue.
52  *
53  *	NOTE: the lock file is used to pass information to lpq and lprm.
54  *	it does not need to be removed because file locks are dynamic.
55  */
56 
57 #include <sys/param.h>
58 #include <sys/wait.h>
59 #include <sys/stat.h>
60 #include <sys/types.h>
61 
62 #include <pwd.h>
63 #include <unistd.h>
64 #include <signal.h>
65 #include <syslog.h>
66 #include <fcntl.h>
67 #include <dirent.h>
68 #include <errno.h>
69 #include <stdio.h>
70 #include <string.h>
71 #include <stdlib.h>
72 #include <sys/ioctl.h>
73 #include <termios.h>
74 #include <time.h>
75 #include "lp.h"
76 #include "lp.local.h"
77 #include "pathnames.h"
78 #include "extern.h"
79 
80 #define DORETURN	0	/* absorb fork error */
81 #define DOABORT		1	/* abort if dofork fails */
82 
83 /*
84  * Error tokens
85  */
86 #define REPRINT		-2
87 #define ERROR		-1
88 #define	OK		0
89 #define	FATALERR	1
90 #define	NOACCT		2
91 #define	FILTERERR	3
92 #define	ACCESS		4
93 
94 static dev_t	 fdev;		/* device of file pointed to by symlink */
95 static ino_t	 fino;		/* inode of file pointed to by symlink */
96 static FILE	*cfp;		/* control file */
97 static int	 child;		/* id of any filters */
98 static int	 lfd;		/* lock file descriptor */
99 static int	 ofd;		/* output filter file descriptor */
100 static int	 ofilter;	/* id of output filter, if any */
101 static int	 tfd = -1;	/* output filter temp file output */
102 static int	 pfd;		/* prstatic inter file descriptor */
103 static int	 pid;		/* pid of lpd process */
104 static int	 prchild;	/* id of pr process */
105 static char	 title[80];	/* ``pr'' title */
106 static char      locale[80];    /* ``pr'' locale */
107 
108 static char	class[32];		/* classification field */
109 static char	fromhost[32];		/* user's host machine */
110 				/* indentation size in static characters */
111 static char	indent[10] = "-i0";
112 static char	jobname[100];		/* job or file name */
113 static char	length[10] = "-l";	/* page length in lines */
114 static char	logname[32];		/* user's login name */
115 static char	pxlength[10] = "-y";	/* page length in pixels */
116 static char	pxwidth[10] = "-x";	/* page width in pixels */
117 static char	tempfile[] = "errsXXXXXX"; /* file name for filter errors */
118 static char	width[10] = "-w";	/* page width in static characters */
119 #define TFILENAME "fltXXXXXX"
120 static char	tfile[] = TFILENAME;	/* file name for filter output */
121 
122 static void       abortpr __P((int));
123 static void	  alarmhandler __P((int));
124 static void       banner __P((struct printer *pp, char *name1, char *name2));
125 static int        dofork __P((const struct printer *pp, int action));
126 static int        dropit __P((int));
127 static void       init __P((struct printer *pp));
128 static void       openpr __P((const struct printer *pp));
129 static void       opennet __P((const struct printer *pp));
130 static void       opentty __P((const struct printer *pp));
131 static void       openrem __P((const struct printer *pp));
132 static int        print __P((struct printer *pp, int format, char *file));
133 static int        printit __P((struct printer *pp, char *file));
134 static void       pstatus __P((const struct printer *, const char *, ...));
135 static char       response __P((const struct printer *pp));
136 static void       scan_out __P((struct printer *pp, int scfd, char *scsp,
137 				int dlm));
138 static char      *scnline __P((int, char *, int));
139 static int        sendfile __P((struct printer *pp, int type, char *file,
140 				int format));
141 static int        sendit __P((struct printer *pp, char *file));
142 static void       sendmail __P((struct printer *pp, char *user, int bombed));
143 static void       setty __P((const struct printer *pp));
144 
145 void
146 printjob(pp)
147 	struct printer *pp;
148 {
149 	struct stat stb;
150 	register struct queue *q, **qp;
151 	struct queue **queue;
152 	register int i, nitems;
153 	off_t pidoff;
154 	int errcnt, count = 0;
155 
156 	init(pp); /* set up capabilities */
157 	(void) write(1, "", 1);	/* ack that daemon is started */
158 	(void) close(2);			/* set up log file */
159 	if (open(pp->log_file, O_WRONLY|O_APPEND, LOG_FILE_MODE) < 0) {
160 		syslog(LOG_ERR, "%s: %m", pp->log_file);
161 		(void) open(_PATH_DEVNULL, O_WRONLY);
162 	}
163 	setgid(getegid());
164 	pid = getpid();				/* for use with lprm */
165 	setpgrp(0, pid);
166 	signal(SIGHUP, abortpr);
167 	signal(SIGINT, abortpr);
168 	signal(SIGQUIT, abortpr);
169 	signal(SIGTERM, abortpr);
170 
171 	(void) mktemp(tempfile);
172 
173 	/*
174 	 * uses short form file names
175 	 */
176 	if (chdir(pp->spool_dir) < 0) {
177 		syslog(LOG_ERR, "%s: %m", pp->spool_dir);
178 		exit(1);
179 	}
180 	if (stat(pp->lock_file, &stb) == 0 && (stb.st_mode & LFM_PRINT_DIS))
181 		exit(0);		/* printing disabled */
182 	lfd = open(pp->lock_file, O_WRONLY|O_CREAT|O_EXLOCK|O_NONBLOCK,
183 		   LOCK_FILE_MODE);
184 	if (lfd < 0) {
185 		if (errno == EWOULDBLOCK)	/* active daemon present */
186 			exit(0);
187 		syslog(LOG_ERR, "%s: %s: %m", pp->printer, pp->lock_file);
188 		exit(1);
189 	}
190 	/* turn off non-blocking mode (was turned on for lock effects only) */
191 	if (fcntl(lfd, F_SETFL, 0) < 0) {
192 		syslog(LOG_ERR, "%s: %s: %m", pp->printer, pp->lock_file);
193 		exit(1);
194 	}
195 	ftruncate(lfd, 0);
196 	/*
197 	 * write process id for others to know
198 	 */
199 	sprintf(line, "%u\n", pid);
200 	pidoff = i = strlen(line);
201 	if (write(lfd, line, i) != i) {
202 		syslog(LOG_ERR, "%s: %s: %m", pp->printer, pp->lock_file);
203 		exit(1);
204 	}
205 	/*
206 	 * search the spool directory for work and sort by queue order.
207 	 */
208 	if ((nitems = getq(pp, &queue)) < 0) {
209 		syslog(LOG_ERR, "%s: can't scan %s", pp->printer,
210 		       pp->spool_dir);
211 		exit(1);
212 	}
213 	if (nitems == 0)		/* no work to do */
214 		exit(0);
215 	if (stb.st_mode & LFM_RESET_QUE) { /* reset queue flag */
216 		if (fchmod(lfd, stb.st_mode & ~LFM_RESET_QUE) < 0)
217 			syslog(LOG_ERR, "%s: %s: %m", pp->printer,
218 			       pp->lock_file);
219 	}
220 	openpr(pp);			/* open printer or remote */
221 again:
222 	/*
223 	 * we found something to do now do it --
224 	 *    write the name of the current control file into the lock file
225 	 *    so the spool queue program can tell what we're working on
226 	 */
227 	for (qp = queue; nitems--; free((char *) q)) {
228 		q = *qp++;
229 		if (stat(q->q_name, &stb) < 0)
230 			continue;
231 		errcnt = 0;
232 	restart:
233 		(void) lseek(lfd, pidoff, 0);
234 		(void) snprintf(line, sizeof(line), "%s\n", q->q_name);
235 		i = strlen(line);
236 		if (write(lfd, line, i) != i)
237 			syslog(LOG_ERR, "%s: %s: %m", pp->printer,
238 			       pp->lock_file);
239 		if (!pp->remote)
240 			i = printit(pp, q->q_name);
241 		else
242 			i = sendit(pp, q->q_name);
243 		/*
244 		 * Check to see if we are supposed to stop printing or
245 		 * if we are to rebuild the queue.
246 		 */
247 		if (fstat(lfd, &stb) == 0) {
248 			/* stop printing before starting next job? */
249 			if (stb.st_mode & LFM_PRINT_DIS)
250 				goto done;
251 			/* rebuild queue (after lpc topq) */
252 			if (stb.st_mode & LFM_RESET_QUE) {
253 				for (free(q); nitems--; free(q))
254 					q = *qp++;
255 				if (fchmod(lfd, stb.st_mode & ~LFM_RESET_QUE)
256 				    < 0)
257 					syslog(LOG_WARNING, "%s: %s: %m",
258 					       pp->printer, pp->lock_file);
259 				break;
260 			}
261 		}
262 		if (i == OK)		/* file ok and printed */
263 			count++;
264 		else if (i == REPRINT && ++errcnt < 5) {
265 			/* try reprinting the job */
266 			syslog(LOG_INFO, "restarting %s", pp->printer);
267 			if (ofilter > 0) {
268 				kill(ofilter, SIGCONT);	/* to be sure */
269 				(void) close(ofd);
270 				while ((i = wait(NULL)) > 0 && i != ofilter)
271 					;
272 				ofilter = 0;
273 			}
274 			(void) close(pfd);	/* close printer */
275 			if (ftruncate(lfd, pidoff) < 0)
276 				syslog(LOG_WARNING, "%s: %s: %m",
277 				       pp->printer, pp->lock_file);
278 			openpr(pp);		/* try to reopen printer */
279 			goto restart;
280 		} else {
281 			syslog(LOG_WARNING, "%s: job could not be %s (%s)",
282 			       pp->printer,
283 			       pp->remote ? "sent to remote host" : "printed",
284 			       q->q_name);
285 			if (i == REPRINT) {
286 				/* ensure we don't attempt this job again */
287 				(void) unlink(q->q_name);
288 				q->q_name[0] = 'd';
289 				(void) unlink(q->q_name);
290 				if (logname[0])
291 					sendmail(pp, logname, FATALERR);
292 			}
293 		}
294 	}
295 	free(queue);
296 	/*
297 	 * search the spool directory for more work.
298 	 */
299 	if ((nitems = getq(pp, &queue)) < 0) {
300 		syslog(LOG_ERR, "%s: can't scan %s", pp->printer,
301 		       pp->spool_dir);
302 		exit(1);
303 	}
304 	if (nitems == 0) {		/* no more work to do */
305 	done:
306 		if (count > 0) {	/* Files actually printed */
307 			if (!pp->no_formfeed && !pp->tof)
308 				(void) write(ofd, pp->form_feed,
309 					     strlen(pp->form_feed));
310 			if (pp->trailer != NULL) /* output trailer */
311 				(void) write(ofd, pp->trailer,
312 					     strlen(pp->trailer));
313 		}
314 		(void) close(ofd);
315 		(void) wait(NULL);
316 		(void) unlink(tempfile);
317 		exit(0);
318 	}
319 	goto again;
320 }
321 
322 char	fonts[4][50];	/* fonts for troff */
323 
324 char ifonts[4][40] = {
325 	_PATH_VFONTR,
326 	_PATH_VFONTI,
327 	_PATH_VFONTB,
328 	_PATH_VFONTS,
329 };
330 
331 /*
332  * The remaining part is the reading of the control file (cf)
333  * and performing the various actions.
334  */
335 static int
336 printit(pp, file)
337 	struct printer *pp;
338 	char *file;
339 {
340 	register int i;
341 	char *cp;
342 	int bombed = OK;
343 
344 	/*
345 	 * open control file; ignore if no longer there.
346 	 */
347 	if ((cfp = fopen(file, "r")) == NULL) {
348 		syslog(LOG_INFO, "%s: %s: %m", pp->printer, file);
349 		return(OK);
350 	}
351 	/*
352 	 * Reset troff fonts.
353 	 */
354 	for (i = 0; i < 4; i++)
355 		strcpy(fonts[i], ifonts[i]);
356 	sprintf(&width[2], "%ld", pp->page_width);
357 	strcpy(indent+2, "0");
358 
359 	/*
360 	 *      read the control file for work to do
361 	 *
362 	 *      file format -- first character in the line is a command
363 	 *      rest of the line is the argument.
364 	 *      valid commands are:
365 	 *
366 	 *		S -- "stat info" for symbolic link protection
367 	 *		J -- "job name" on banner page
368 	 *		C -- "class name" on banner page
369 	 *              L -- "literal" user's name to print on banner
370 	 *		T -- "title" for pr
371 	 *		H -- "host name" of machine where lpr was done
372 	 *              P -- "person" user's login name
373 	 *              I -- "indent" amount to indent output
374 	 *		R -- laser dpi "resolution"
375 	 *              f -- "file name" name of text file to print
376 	 *		l -- "file name" text file with control chars
377 	 *		p -- "file name" text file to print with pr(1)
378 	 *		t -- "file name" troff(1) file to print
379 	 *		n -- "file name" ditroff(1) file to print
380 	 *		d -- "file name" dvi file to print
381 	 *		g -- "file name" plot(1G) file to print
382 	 *		v -- "file name" plain raster file to print
383 	 *		c -- "file name" cifplot file to print
384 	 *		1 -- "R font file" for troff
385 	 *		2 -- "I font file" for troff
386 	 *		3 -- "B font file" for troff
387 	 *		4 -- "S font file" for troff
388 	 *		N -- "name" of file (used by lpq)
389 	 *              U -- "unlink" name of file to remove
390 	 *                    (after we print it. (Pass 2 only)).
391 	 *		M -- "mail" to user when done printing
392 	 *              Z -- "locale" for pr
393 	 *
394 	 *      getline reads a line and expands tabs to blanks
395 	 */
396 
397 	/* pass 1 */
398 
399 	while (getline(cfp))
400 		switch (line[0]) {
401 		case 'H':
402 			strncpy(fromhost, line+1, sizeof(fromhost) - 1);
403 			fromhost[sizeof(fromhost) - 1] = '\0';
404 			if (class[0] == '\0') {
405 				strncpy(class, line+1, sizeof(class) - 1);
406 				class[sizeof(class) - 1] = '\0';
407 			}
408 			continue;
409 
410 		case 'P':
411 			strncpy(logname, line+1, sizeof(logname) - 1);
412 			logname[sizeof(logname) - 1] = '\0';
413 			if (pp->restricted) { /* restricted */
414 				if (getpwnam(logname) == NULL) {
415 					bombed = NOACCT;
416 					sendmail(pp, line+1, bombed);
417 					goto pass2;
418 				}
419 			}
420 			continue;
421 
422 		case 'S':
423 			cp = line+1;
424 			i = 0;
425 			while (*cp >= '0' && *cp <= '9')
426 				i = i * 10 + (*cp++ - '0');
427 			fdev = i;
428 			cp++;
429 			i = 0;
430 			while (*cp >= '0' && *cp <= '9')
431 				i = i * 10 + (*cp++ - '0');
432 			fino = i;
433 			continue;
434 
435 		case 'J':
436 			if (line[1] != '\0') {
437 				strncpy(jobname, line+1, sizeof(jobname) - 1);
438 				jobname[sizeof(jobname) - 1] = '\0';
439 			} else
440 				strcpy(jobname, " ");
441 			continue;
442 
443 		case 'C':
444 			if (line[1] != '\0')
445 				strncpy(class, line+1, sizeof(class) - 1);
446 			else if (class[0] == '\0')
447 				gethostname(class, sizeof(class));
448 			class[sizeof(class) - 1] = '\0';
449 			continue;
450 
451 		case 'T':	/* header title for pr */
452 			strncpy(title, line+1, sizeof(title) - 1);
453 			title[sizeof(title) - 1] = '\0';
454 			continue;
455 
456 		case 'L':	/* identification line */
457 			if (!pp->no_header && !pp->header_last)
458 				banner(pp, line+1, jobname);
459 			continue;
460 
461 		case '1':	/* troff fonts */
462 		case '2':
463 		case '3':
464 		case '4':
465 			if (line[1] != '\0') {
466 				strncpy(fonts[line[0]-'1'], line+1,
467 				    50-1);
468 				fonts[line[0]-'1'][50-1] = '\0';
469 			}
470 			continue;
471 
472 		case 'W':	/* page width */
473 			strncpy(width+2, line+1, sizeof(width) - 3);
474 			width[2+sizeof(width) - 3] = '\0';
475 			continue;
476 
477 		case 'I':	/* indent amount */
478 			strncpy(indent+2, line+1, sizeof(indent) - 3);
479 			indent[2+sizeof(indent) - 3] = '\0';
480 			continue;
481 
482 		case 'Z':       /* locale for pr */
483 			strncpy(locale, line+1, sizeof(locale) - 1);
484 			locale[sizeof(locale) - 1] = '\0';
485 			continue;
486 
487 		default:	/* some file to print */
488 			switch (i = print(pp, line[0], line+1)) {
489 			case ERROR:
490 				if (bombed == OK)
491 					bombed = FATALERR;
492 				break;
493 			case REPRINT:
494 				(void) fclose(cfp);
495 				return(REPRINT);
496 			case FILTERERR:
497 			case ACCESS:
498 				bombed = i;
499 				sendmail(pp, logname, bombed);
500 			}
501 			title[0] = '\0';
502 			continue;
503 
504 		case 'N':
505 		case 'U':
506 		case 'M':
507 		case 'R':
508 			continue;
509 		}
510 
511 	/* pass 2 */
512 
513 pass2:
514 	fseek(cfp, 0L, 0);
515 	while (getline(cfp))
516 		switch (line[0]) {
517 		case 'L':	/* identification line */
518 			if (!pp->no_header && pp->header_last)
519 				banner(pp, line+1, jobname);
520 			continue;
521 
522 		case 'M':
523 			if (bombed < NOACCT)	/* already sent if >= NOACCT */
524 				sendmail(pp, line+1, bombed);
525 			continue;
526 
527 		case 'U':
528 			if (strchr(line+1, '/'))
529 				continue;
530 			(void) unlink(line+1);
531 		}
532 	/*
533 	 * clean-up in case another control file exists
534 	 */
535 	(void) fclose(cfp);
536 	(void) unlink(file);
537 	return(bombed == OK ? OK : ERROR);
538 }
539 
540 /*
541  * Print a file.
542  * Set up the chain [ PR [ | {IF, OF} ] ] or {IF, RF, TF, NF, DF, CF, VF}.
543  * Return -1 if a non-recoverable error occured,
544  * 2 if the filter detected some errors (but printed the job anyway),
545  * 1 if we should try to reprint this job and
546  * 0 if all is well.
547  * Note: all filters take stdin as the file, stdout as the printer,
548  * stderr as the log file, and must not ignore SIGINT.
549  */
550 static int
551 print(pp, format, file)
552 	struct printer *pp;
553 	int format;
554 	char *file;
555 {
556 	register int n, i;
557 	register char *prog;
558 	int fi, fo;
559 	FILE *fp;
560 	char *av[15], buf[BUFSIZ];
561 	int pid, p[2], stopped = 0;
562 	union wait status;
563 	struct stat stb;
564 
565 	if (lstat(file, &stb) < 0 || (fi = open(file, O_RDONLY)) < 0)
566 		return(ERROR);
567 	/*
568 	 * Check to see if data file is a symbolic link. If so, it should
569 	 * still point to the same file or someone is trying to print
570 	 * something he shouldn't.
571 	 */
572 	if ((stb.st_mode & S_IFMT) == S_IFLNK && fstat(fi, &stb) == 0 &&
573 	    (stb.st_dev != fdev || stb.st_ino != fino))
574 		return(ACCESS);
575 	if (!pp->no_formfeed && !pp->tof) { /* start on a fresh page */
576 		(void) write(ofd, pp->form_feed, strlen(pp->form_feed));
577 		pp->tof = 1;
578 	}
579 	if (pp->filters[LPF_INPUT] == NULL
580 	    && (format == 'f' || format == 'l')) {
581 		pp->tof = 0;
582 		while ((n = read(fi, buf, BUFSIZ)) > 0)
583 			if (write(ofd, buf, n) != n) {
584 				(void) close(fi);
585 				return(REPRINT);
586 			}
587 		(void) close(fi);
588 		return(OK);
589 	}
590 	switch (format) {
591 	case 'p':	/* print file using 'pr' */
592 		if (pp->filters[LPF_INPUT] == NULL) {	/* use output filter */
593 			prog = _PATH_PR;
594 			i = 0;
595 			av[i++] = "pr";
596 			av[i++] = width;
597 			av[i++] = length;
598 			av[i++] = "-h";
599 			av[i++] = *title ? title : " ";
600 			av[i++] = "-L";
601 			av[i++] = *locale ? locale : "C";
602 			av[i++] = "-F";
603 			av[i] = 0;
604 			fo = ofd;
605 			goto start;
606 		}
607 		pipe(p);
608 		if ((prchild = dofork(pp, DORETURN)) == 0) {	/* child */
609 			dup2(fi, 0);		/* file is stdin */
610 			dup2(p[1], 1);		/* pipe is stdout */
611 			closelog();
612 			closeallfds(3);
613 			execl(_PATH_PR, "pr", width, length,
614 			    "-h", *title ? title : " ",
615 			    "-L", *locale ? locale : "C",
616 			    "-F", 0);
617 			syslog(LOG_ERR, "cannot execl %s", _PATH_PR);
618 			exit(2);
619 		}
620 		(void) close(p[1]);		/* close output side */
621 		(void) close(fi);
622 		if (prchild < 0) {
623 			prchild = 0;
624 			(void) close(p[0]);
625 			return(ERROR);
626 		}
627 		fi = p[0];			/* use pipe for input */
628 	case 'f':	/* print plain text file */
629 		prog = pp->filters[LPF_INPUT];
630 		av[1] = width;
631 		av[2] = length;
632 		av[3] = indent;
633 		n = 4;
634 		break;
635 	case 'l':	/* like 'f' but pass control characters */
636 		prog = pp->filters[LPF_INPUT];
637 		av[1] = "-c";
638 		av[2] = width;
639 		av[3] = length;
640 		av[4] = indent;
641 		n = 5;
642 		break;
643 	case 'r':	/* print a fortran text file */
644 		prog = pp->filters[LPF_FORTRAN];
645 		av[1] = width;
646 		av[2] = length;
647 		n = 3;
648 		break;
649 	case 't':	/* print troff output */
650 	case 'n':	/* print ditroff output */
651 	case 'd':	/* print tex output */
652 		(void) unlink(".railmag");
653 		if ((fo = creat(".railmag", FILMOD)) < 0) {
654 			syslog(LOG_ERR, "%s: cannot create .railmag",
655 			       pp->printer);
656 			(void) unlink(".railmag");
657 		} else {
658 			for (n = 0; n < 4; n++) {
659 				if (fonts[n][0] != '/')
660 					(void) write(fo, _PATH_VFONT,
661 					    sizeof(_PATH_VFONT) - 1);
662 				(void) write(fo, fonts[n], strlen(fonts[n]));
663 				(void) write(fo, "\n", 1);
664 			}
665 			(void) close(fo);
666 		}
667 		prog = (format == 't') ? pp->filters[LPF_TROFF]
668 			: ((format == 'n') ? pp->filters[LPF_DITROFF]
669 			   : pp->filters[LPF_DVI]);
670 		av[1] = pxwidth;
671 		av[2] = pxlength;
672 		n = 3;
673 		break;
674 	case 'c':	/* print cifplot output */
675 		prog = pp->filters[LPF_CIFPLOT];
676 		av[1] = pxwidth;
677 		av[2] = pxlength;
678 		n = 3;
679 		break;
680 	case 'g':	/* print plot(1G) output */
681 		prog = pp->filters[LPF_GRAPH];
682 		av[1] = pxwidth;
683 		av[2] = pxlength;
684 		n = 3;
685 		break;
686 	case 'v':	/* print raster output */
687 		prog = pp->filters[LPF_RASTER];
688 		av[1] = pxwidth;
689 		av[2] = pxlength;
690 		n = 3;
691 		break;
692 	default:
693 		(void) close(fi);
694 		syslog(LOG_ERR, "%s: illegal format character '%c'",
695 			pp->printer, format);
696 		return(ERROR);
697 	}
698 	if (prog == NULL) {
699 		(void) close(fi);
700 		syslog(LOG_ERR,
701 		   "%s: no filter found in printcap for format character '%c'",
702 		   pp->printer, format);
703 		return(ERROR);
704 	}
705 	if ((av[0] = strrchr(prog, '/')) != NULL)
706 		av[0]++;
707 	else
708 		av[0] = prog;
709 	av[n++] = "-n";
710 	av[n++] = logname;
711 	av[n++] = "-h";
712 	av[n++] = fromhost;
713 	av[n++] = pp->acct_file;
714 	av[n] = 0;
715 	fo = pfd;
716 	if (ofilter > 0) {		/* stop output filter */
717 		write(ofd, "\031\1", 2);
718 		while ((pid =
719 		    wait3((int *)&status, WUNTRACED, 0)) > 0 && pid != ofilter)
720 			;
721 		if (status.w_stopval != WSTOPPED) {
722 			(void) close(fi);
723 			syslog(LOG_WARNING,
724 			       "%s: output filter died "
725 			       "(retcode=%d termsig=%d)",
726 				pp->printer, status.w_retcode,
727 			       status.w_termsig);
728 			return(REPRINT);
729 		}
730 		stopped++;
731 	}
732 start:
733 	if ((child = dofork(pp, DORETURN)) == 0) { /* child */
734 		dup2(fi, 0);
735 		dup2(fo, 1);
736 		n = open(tempfile, O_WRONLY|O_CREAT|O_TRUNC, 0664);
737 		if (n >= 0)
738 			dup2(n, 2);
739 		closelog();
740 		closeallfds(3);
741 		execv(prog, av);
742 		syslog(LOG_ERR, "cannot execv %s", prog);
743 		exit(2);
744 	}
745 	(void) close(fi);
746 	if (child < 0)
747 		status.w_retcode = 100;
748 	else
749 		while ((pid = wait((int *)&status)) > 0 && pid != child)
750 			;
751 	child = 0;
752 	prchild = 0;
753 	if (stopped) {		/* restart output filter */
754 		if (kill(ofilter, SIGCONT) < 0) {
755 			syslog(LOG_ERR, "cannot restart output filter");
756 			exit(1);
757 		}
758 	}
759 	pp->tof = 0;
760 
761 	/* Copy filter output to "lf" logfile */
762 	if ((fp = fopen(tempfile, "r"))) {
763 		while (fgets(buf, sizeof(buf), fp))
764 			fputs(buf, stderr);
765 		fclose(fp);
766 	}
767 
768 	if (!WIFEXITED(status)) {
769 		syslog(LOG_WARNING, "%s: filter '%c' terminated (termsig=%d)",
770 			pp->printer, format, status.w_termsig);
771 		return(ERROR);
772 	}
773 	switch (status.w_retcode) {
774 	case 0:
775 		pp->tof = 1;
776 		return(OK);
777 	case 1:
778 		return(REPRINT);
779 	case 2:
780 		return(ERROR);
781 	default:
782 		syslog(LOG_WARNING, "%s: filter '%c' exited (retcode=%d)",
783 			pp->printer, format, status.w_retcode);
784 		return(FILTERERR);
785 	}
786 }
787 
788 /*
789  * Send the daemon control file (cf) and any data files.
790  * Return -1 if a non-recoverable error occured, 1 if a recoverable error and
791  * 0 if all is well.
792  */
793 static int
794 sendit(pp, file)
795 	struct printer *pp;
796 	char *file;
797 {
798 	register int i, err = OK;
799 	char *cp, last[BUFSIZ];
800 
801 	/*
802 	 * open control file
803 	 */
804 	if ((cfp = fopen(file, "r")) == NULL)
805 		return(OK);
806 	/*
807 	 *      read the control file for work to do
808 	 *
809 	 *      file format -- first character in the line is a command
810 	 *      rest of the line is the argument.
811 	 *      commands of interest are:
812 	 *
813 	 *            a-z -- "file name" name of file to print
814 	 *              U -- "unlink" name of file to remove
815 	 *                    (after we print it. (Pass 2 only)).
816 	 */
817 
818 	/*
819 	 * pass 1
820 	 */
821 	while (getline(cfp)) {
822 	again:
823 		if (line[0] == 'S') {
824 			cp = line+1;
825 			i = 0;
826 			while (*cp >= '0' && *cp <= '9')
827 				i = i * 10 + (*cp++ - '0');
828 			fdev = i;
829 			cp++;
830 			i = 0;
831 			while (*cp >= '0' && *cp <= '9')
832 				i = i * 10 + (*cp++ - '0');
833 			fino = i;
834 		} else if (line[0] == 'H') {
835 			strcpy(fromhost, line+1);
836 			if (class[0] == '\0')
837 				strncpy(class, line+1, sizeof(class) - 1);
838 		} else if (line[0] == 'P') {
839 			strncpy(logname, line+1, sizeof(logname) - 1);
840 			if (pp->restricted) { /* restricted */
841 				if (getpwnam(logname) == NULL) {
842 					sendmail(pp, line+1, NOACCT);
843 					err = ERROR;
844 					break;
845 				}
846 			}
847 		} else if (line[0] == 'I') {
848 			strncpy(indent+2, line+1, sizeof(indent) - 3);
849 		} else if (line[0] >= 'a' && line[0] <= 'z') {
850 			strcpy(last, line);
851 			while ((i = getline(cfp)) != 0)
852 				if (strcmp(last, line))
853 					break;
854 			switch (sendfile(pp, '\3', last+1, *last)) {
855 			case OK:
856 				if (i)
857 					goto again;
858 				break;
859 			case REPRINT:
860 				(void) fclose(cfp);
861 				return(REPRINT);
862 			case ACCESS:
863 				sendmail(pp, logname, ACCESS);
864 			case ERROR:
865 				err = ERROR;
866 			}
867 			break;
868 		}
869 	}
870 	if (err == OK && sendfile(pp, '\2', file, '\0') > 0) {
871 		(void) fclose(cfp);
872 		return(REPRINT);
873 	}
874 	/*
875 	 * pass 2
876 	 */
877 	fseek(cfp, 0L, 0);
878 	while (getline(cfp))
879 		if (line[0] == 'U' && !strchr(line+1, '/'))
880 			(void) unlink(line+1);
881 	/*
882 	 * clean-up in case another control file exists
883 	 */
884 	(void) fclose(cfp);
885 	(void) unlink(file);
886 	return(err);
887 }
888 
889 /*
890  * Send a data file to the remote machine and spool it.
891  * Return positive if we should try resending.
892  */
893 static int
894 sendfile(pp, type, file, format)
895 	struct printer *pp;
896 	int type;
897 	char *file;
898 	char format;
899 {
900 	register int f, i, amt;
901 	struct stat stb;
902 	char buf[BUFSIZ];
903 	int sizerr, resp, closedpr;
904 
905 	if (lstat(file, &stb) < 0 || (f = open(file, O_RDONLY)) < 0)
906 		return(ERROR);
907 	/*
908 	 * Check to see if data file is a symbolic link. If so, it should
909 	 * still point to the same file or someone is trying to print something
910 	 * he shouldn't.
911 	 */
912 	if ((stb.st_mode & S_IFMT) == S_IFLNK && fstat(f, &stb) == 0 &&
913 	    (stb.st_dev != fdev || stb.st_ino != fino))
914 		return(ACCESS);
915 
916 	sizerr = 0;
917 	closedpr = 0;
918 	if (type == '\3') {
919 		if (pp->filters[LPF_INPUT]) {
920 			/*
921 			 * We're sending something with an ifilter, we have to
922 			 * run the ifilter and store the output as a
923 			 * temporary file (tfile)... the protocol requires us
924 			 * to send the file size
925 			 */
926 			char *av[15];
927 			int n;
928 			int ifilter;
929 			union wait status; /* XXX */
930 
931 			strcpy(tfile,TFILENAME);
932 			if ((tfd = mkstemp(tfile)) == -1) {
933 				syslog(LOG_ERR, "mkstemp: %m");
934 				return(ERROR);
935 			}
936 			if ((av[0] = strrchr(pp->filters[LPF_INPUT], '/')) == NULL)
937 				av[0] = pp->filters[LPF_INPUT];
938 			else
939 				av[0]++;
940 			if (format == 'l')
941 				av[n=1] = "-c";
942 			else
943 				n = 0;
944 			av[++n] = width;
945 			av[++n] = length;
946 			av[++n] = indent;
947 			av[++n] = "-n";
948 			av[++n] = logname;
949 			av[++n] = "-h";
950 			av[++n] = fromhost;
951 			av[++n] = pp->acct_file;
952 			av[++n] = 0;
953 			if ((ifilter = dofork(pp, DORETURN)) == 0) { /* child */
954 				dup2(f, 0);
955 				dup2(tfd, 1);
956 				n = open(tempfile, O_WRONLY|O_CREAT|O_TRUNC,
957 					 TEMP_FILE_MODE);
958 				if (n >= 0)
959 					dup2(n, 2);
960 				closelog();
961 				closeallfds(3);
962 				execv(pp->filters[LPF_INPUT], av);
963 				syslog(LOG_ERR, "cannot execv %s",
964 				       pp->filters[LPF_INPUT]);
965 				exit(2);
966 			}
967 			(void) close(f);
968 			if (ifilter < 0)
969 				status.w_retcode = 100;
970 			else
971 				while ((pid = wait((int *)&status)) > 0 &&
972 					pid != ifilter)
973 					;
974 			switch (status.w_retcode) {
975 			case 0:
976 				break;
977 			case 1:
978 				unlink(tfile);
979 				return(REPRINT);
980 			case 2:
981 				unlink(tfile);
982 				return(ERROR);
983 			default:
984 				syslog(LOG_WARNING, "%s: filter '%c' exited"
985 					" (retcode=%d)",
986 					pp->printer, format, status.w_retcode);
987 				unlink(tfile);
988 				return(FILTERERR);
989 			}
990 			if (fstat(tfd, &stb) < 0)	/* the size of tfile */
991 				return(ERROR);
992 			f = tfd;
993 			lseek(f,0,SEEK_SET);
994 		} else if (ofilter) {
995 			/*
996 			 * We're sending something with an ofilter, we have to
997 			 * store the output as a temporary file (tfile)... the
998 			 * protocol requires us to send the file size
999 			 */
1000 			int i;
1001 			for (i = 0; i < stb.st_size; i += BUFSIZ) {
1002 				amt = BUFSIZ;
1003 				if (i + amt > stb.st_size)
1004 					amt = stb.st_size - i;
1005 				if (sizerr == 0 && read(f, buf, amt) != amt) {
1006 					sizerr = 1;
1007 					break;
1008 				}
1009 				if (write(ofd, buf, amt) != amt) {
1010 					(void) close(f);
1011 					return(REPRINT);
1012 				}
1013 			}
1014 			close(ofd);
1015 			close(f);
1016 			while ((i = wait(NULL)) > 0 && i != ofilter)
1017 				;
1018 			ofilter = 0;
1019 			if (fstat(tfd, &stb) < 0) {	/* the size of tfile */
1020 				openpr(pp);
1021 				return(ERROR);
1022 			}
1023 			f = tfd;
1024 			lseek(f,0,SEEK_SET);
1025 			closedpr = 1;
1026 		}
1027 	}
1028 
1029 	(void) sprintf(buf, "%c%qd %s\n", type, stb.st_size, file);
1030 	amt = strlen(buf);
1031 	for (i = 0;  ; i++) {
1032 		if (write(pfd, buf, amt) != amt ||
1033 		    (resp = response(pp)) < 0 || resp == '\1') {
1034 			(void) close(f);
1035 			if (tfd != -1 && type == '\3') {
1036 				tfd = -1;
1037 				unlink(tfile);
1038 				if (closedpr)
1039 					openpr(pp);
1040 			}
1041 			return(REPRINT);
1042 		} else if (resp == '\0')
1043 			break;
1044 		if (i == 0)
1045 			pstatus(pp,
1046 				"no space on remote; waiting for queue to drain");
1047 		if (i == 10)
1048 			syslog(LOG_ALERT, "%s: can't send to %s; queue full",
1049 				pp->printer, pp->remote_host);
1050 		sleep(5 * 60);
1051 	}
1052 	if (i)
1053 		pstatus(pp, "sending to %s", pp->remote_host);
1054 	for (i = 0; i < stb.st_size; i += BUFSIZ) {
1055 		amt = BUFSIZ;
1056 		if (i + amt > stb.st_size)
1057 			amt = stb.st_size - i;
1058 		if (sizerr == 0 && read(f, buf, amt) != amt)
1059 			sizerr = 1;
1060 		if (write(pfd, buf, amt) != amt) {
1061 			(void) close(f);
1062 			if (tfd != -1 && type == '\3') {
1063 				tfd = -1;
1064 				unlink(tfile);
1065 				if (closedpr)
1066 					openpr(pp);
1067 			}
1068 			return(REPRINT);
1069 		}
1070 	}
1071 
1072 	(void) close(f);
1073 	if (tfd != -1 && type == '\3') {
1074 		tfd = -1;
1075 		unlink(tfile);
1076 	}
1077 	if (sizerr) {
1078 		syslog(LOG_INFO, "%s: %s: changed size", pp->printer, file);
1079 		/* tell recvjob to ignore this file */
1080 		(void) write(pfd, "\1", 1);
1081 		if (closedpr)
1082 			openpr(pp);
1083 		return(ERROR);
1084 	}
1085 	if (write(pfd, "", 1) != 1 || response(pp)) {
1086 		if (closedpr)
1087 			openpr(pp);
1088 		return(REPRINT);
1089 	}
1090 	if (closedpr)
1091 		openpr(pp);
1092 	return(OK);
1093 }
1094 
1095 /*
1096  * Check to make sure there have been no errors and that both programs
1097  * are in sync with eachother.
1098  * Return non-zero if the connection was lost.
1099  */
1100 static char
1101 response(pp)
1102 	const struct printer *pp;
1103 {
1104 	char resp;
1105 
1106 	if (read(pfd, &resp, 1) != 1) {
1107 		syslog(LOG_INFO, "%s: lost connection", pp->printer);
1108 		return(-1);
1109 	}
1110 	return(resp);
1111 }
1112 
1113 /*
1114  * Banner printing stuff
1115  */
1116 static void
1117 banner(pp, name1, name2)
1118 	struct printer *pp;
1119 	char *name1, *name2;
1120 {
1121 	time_t tvec;
1122 
1123 	time(&tvec);
1124 	if (!pp->no_formfeed && !pp->tof)
1125 		(void) write(ofd, pp->form_feed, strlen(pp->form_feed));
1126 	if (pp->short_banner) {	/* short banner only */
1127 		if (class[0]) {
1128 			(void) write(ofd, class, strlen(class));
1129 			(void) write(ofd, ":", 1);
1130 		}
1131 		(void) write(ofd, name1, strlen(name1));
1132 		(void) write(ofd, "  Job: ", 7);
1133 		(void) write(ofd, name2, strlen(name2));
1134 		(void) write(ofd, "  Date: ", 8);
1135 		(void) write(ofd, ctime(&tvec), 24);
1136 		(void) write(ofd, "\n", 1);
1137 	} else {	/* normal banner */
1138 		(void) write(ofd, "\n\n\n", 3);
1139 		scan_out(pp, ofd, name1, '\0');
1140 		(void) write(ofd, "\n\n", 2);
1141 		scan_out(pp, ofd, name2, '\0');
1142 		if (class[0]) {
1143 			(void) write(ofd,"\n\n\n",3);
1144 			scan_out(pp, ofd, class, '\0');
1145 		}
1146 		(void) write(ofd, "\n\n\n\n\t\t\t\t\tJob:  ", 15);
1147 		(void) write(ofd, name2, strlen(name2));
1148 		(void) write(ofd, "\n\t\t\t\t\tDate: ", 12);
1149 		(void) write(ofd, ctime(&tvec), 24);
1150 		(void) write(ofd, "\n", 1);
1151 	}
1152 	if (!pp->no_formfeed)
1153 		(void) write(ofd, pp->form_feed, strlen(pp->form_feed));
1154 	pp->tof = 1;
1155 }
1156 
1157 static char *
1158 scnline(key, p, c)
1159 	register int key;
1160 	register char *p;
1161 	int c;
1162 {
1163 	register int scnwidth;
1164 
1165 	for (scnwidth = WIDTH; --scnwidth;) {
1166 		key <<= 1;
1167 		*p++ = key & 0200 ? c : BACKGND;
1168 	}
1169 	return (p);
1170 }
1171 
1172 #define TRC(q)	(((q)-' ')&0177)
1173 
1174 static void
1175 scan_out(pp, scfd, scsp, dlm)
1176 	struct printer *pp;
1177 	int scfd, dlm;
1178 	char *scsp;
1179 {
1180 	register char *strp;
1181 	register int nchrs, j;
1182 	char outbuf[LINELEN+1], *sp, c, cc;
1183 	int d, scnhgt;
1184 
1185 	for (scnhgt = 0; scnhgt++ < HEIGHT+DROP; ) {
1186 		strp = &outbuf[0];
1187 		sp = scsp;
1188 		for (nchrs = 0; ; ) {
1189 			d = dropit(c = TRC(cc = *sp++));
1190 			if ((!d && scnhgt > HEIGHT) || (scnhgt <= DROP && d))
1191 				for (j = WIDTH; --j;)
1192 					*strp++ = BACKGND;
1193 			else
1194 				strp = scnline(scnkey[(int)c][scnhgt-1-d], strp, cc);
1195 			if (*sp == dlm || *sp == '\0' ||
1196 			    nchrs++ >= pp->page_width/(WIDTH+1)-1)
1197 				break;
1198 			*strp++ = BACKGND;
1199 			*strp++ = BACKGND;
1200 		}
1201 		while (*--strp == BACKGND && strp >= outbuf)
1202 			;
1203 		strp++;
1204 		*strp++ = '\n';
1205 		(void) write(scfd, outbuf, strp-outbuf);
1206 	}
1207 }
1208 
1209 static int
1210 dropit(c)
1211 	int c;
1212 {
1213 	switch(c) {
1214 
1215 	case TRC('_'):
1216 	case TRC(';'):
1217 	case TRC(','):
1218 	case TRC('g'):
1219 	case TRC('j'):
1220 	case TRC('p'):
1221 	case TRC('q'):
1222 	case TRC('y'):
1223 		return (DROP);
1224 
1225 	default:
1226 		return (0);
1227 	}
1228 }
1229 
1230 /*
1231  * sendmail ---
1232  *   tell people about job completion
1233  */
1234 static void
1235 sendmail(pp, user, bombed)
1236 	struct printer *pp;
1237 	char *user;
1238 	int bombed;
1239 {
1240 	register int i;
1241 	int p[2], s;
1242 	register char *cp;
1243 	struct stat stb;
1244 	FILE *fp;
1245 
1246 	pipe(p);
1247 	if ((s = dofork(pp, DORETURN)) == 0) {		/* child */
1248 		dup2(p[0], 0);
1249 		closelog();
1250 		closeallfds(3);
1251 		if ((cp = strrchr(_PATH_SENDMAIL, '/')) != NULL)
1252 			cp++;
1253 		else
1254 			cp = _PATH_SENDMAIL;
1255 		execl(_PATH_SENDMAIL, cp, "-t", 0);
1256 		_exit(0);
1257 	} else if (s > 0) {				/* parent */
1258 		dup2(p[1], 1);
1259 		printf("To: %s@%s\n", user, fromhost);
1260 		printf("Subject: %s printer job \"%s\"\n", pp->printer,
1261 			*jobname ? jobname : "<unknown>");
1262 		printf("Reply-To: root@%s\n\n", host);
1263 		printf("Your printer job ");
1264 		if (*jobname)
1265 			printf("(%s) ", jobname);
1266 
1267 		cp = "XXX compiler confusion"; /* XXX shut GCC up */
1268 		switch (bombed) {
1269 		case OK:
1270 			printf("\ncompleted successfully\n");
1271 			cp = "OK";
1272 			break;
1273 		default:
1274 		case FATALERR:
1275 			printf("\ncould not be printed\n");
1276 			cp = "FATALERR";
1277 			break;
1278 		case NOACCT:
1279 			printf("\ncould not be printed without an account on %s\n", host);
1280 			cp = "NOACCT";
1281 			break;
1282 		case FILTERERR:
1283 			if (stat(tempfile, &stb) < 0 || stb.st_size == 0 ||
1284 			    (fp = fopen(tempfile, "r")) == NULL) {
1285 				printf("\nhad some errors and may not have printed\n");
1286 				break;
1287 			}
1288 			printf("\nhad the following errors and may not have printed:\n");
1289 			while ((i = getc(fp)) != EOF)
1290 				putchar(i);
1291 			(void) fclose(fp);
1292 			cp = "FILTERERR";
1293 			break;
1294 		case ACCESS:
1295 			printf("\nwas not printed because it was not linked to the original file\n");
1296 			cp = "ACCESS";
1297 		}
1298 		fflush(stdout);
1299 		(void) close(1);
1300 	} else {
1301 		syslog(LOG_WARNING, "unable to send mail to %s: %m", user);
1302 		return;
1303 	}
1304 	(void) close(p[0]);
1305 	(void) close(p[1]);
1306 	wait(NULL);
1307 	syslog(LOG_INFO, "mail sent to user %s about job %s on printer %s (%s)",
1308 		user, *jobname ? jobname : "<unknown>", pp->printer, cp);
1309 }
1310 
1311 /*
1312  * dofork - fork with retries on failure
1313  */
1314 static int
1315 dofork(pp, action)
1316 	const struct printer *pp;
1317 	int action;
1318 {
1319 	register int i, pid;
1320 
1321 	for (i = 0; i < 20; i++) {
1322 		if ((pid = fork()) < 0) {
1323 			sleep((unsigned)(i*i));
1324 			continue;
1325 		}
1326 		/*
1327 		 * Child should run as daemon instead of root
1328 		 */
1329 		if (pid == 0)
1330 			setuid(pp->daemon_user);
1331 		return(pid);
1332 	}
1333 	syslog(LOG_ERR, "can't fork");
1334 
1335 	switch (action) {
1336 	case DORETURN:
1337 		return (-1);
1338 	default:
1339 		syslog(LOG_ERR, "bad action (%d) to dofork", action);
1340 		/*FALL THRU*/
1341 	case DOABORT:
1342 		exit(1);
1343 	}
1344 	/*NOTREACHED*/
1345 }
1346 
1347 /*
1348  * Kill child processes to abort current job.
1349  */
1350 static void
1351 abortpr(signo)
1352 	int signo;
1353 {
1354 	(void) unlink(tempfile);
1355 	kill(0, SIGINT);
1356 	if (ofilter > 0)
1357 		kill(ofilter, SIGCONT);
1358 	while (wait(NULL) > 0)
1359 		;
1360 	if (ofilter > 0 && tfd != -1)
1361 		unlink(tfile);
1362 	exit(0);
1363 }
1364 
1365 static void
1366 init(pp)
1367 	struct printer *pp;
1368 {
1369 	char *s;
1370 
1371 	sprintf(&width[2], "%ld", pp->page_width);
1372 	sprintf(&length[2], "%ld", pp->page_length);
1373 	sprintf(&pxwidth[2], "%ld", pp->page_pwidth);
1374 	sprintf(&pxlength[2], "%ld", pp->page_plength);
1375 	if ((s = checkremote(pp)) != 0) {
1376 		syslog(LOG_WARNING, "%s", s);
1377 		free(s);
1378 	}
1379 }
1380 
1381 void
1382 startprinting(printer)
1383 	const char *printer;
1384 {
1385 	struct printer myprinter, *pp = &myprinter;
1386 	int status;
1387 
1388 	init_printer(pp);
1389 	status = getprintcap(printer, pp);
1390 	switch(status) {
1391 	case PCAPERR_OSERR:
1392 		syslog(LOG_ERR, "can't open printer description file: %m");
1393 		exit(1);
1394 	case PCAPERR_NOTFOUND:
1395 		syslog(LOG_ERR, "unknown printer: %s", printer);
1396 		exit(1);
1397 	case PCAPERR_TCLOOP:
1398 		fatal(pp, "potential reference loop detected in printcap file");
1399 	default:
1400 		break;
1401 	}
1402 	printjob(pp);
1403 }
1404 
1405 /*
1406  * Acquire line printer or remote connection.
1407  */
1408 static void
1409 openpr(pp)
1410 	const struct printer *pp;
1411 {
1412 	int p[2];
1413 	char *cp;
1414 
1415 	if (pp->remote) {
1416 		openrem(pp);
1417 	} else if (*pp->lp) {
1418 		if ((cp = strchr(pp->lp, '@')) != NULL)
1419 			opennet(pp);
1420 		else
1421 			opentty(pp);
1422 	} else {
1423 		syslog(LOG_ERR, "%s: no line printer device or host name",
1424 			pp->printer);
1425 		exit(1);
1426 	}
1427 
1428 	/*
1429 	 * Start up an output filter, if needed.
1430 	 */
1431 	if (pp->filters[LPF_OUTPUT] && !pp->filters[LPF_INPUT] && !ofilter) {
1432 		pipe(p);
1433 		if (pp->remote) {
1434 			strcpy(tfile, TFILENAME);
1435 			tfd = mkstemp(tfile);
1436 		}
1437 		if ((ofilter = dofork(pp, DOABORT)) == 0) {	/* child */
1438 			dup2(p[0], 0);		/* pipe is std in */
1439 			/* tfile/printer is stdout */
1440 			dup2(pp->remote ? tfd : pfd, 1);
1441 			closelog();
1442 			closeallfds(3);
1443 			if ((cp = strrchr(pp->filters[LPF_OUTPUT], '/')) == NULL)
1444 				cp = pp->filters[LPF_OUTPUT];
1445 			else
1446 				cp++;
1447 			execl(pp->filters[LPF_OUTPUT], cp, width, length, 0);
1448 			syslog(LOG_ERR, "%s: %s: %m", pp->printer,
1449 			       pp->filters[LPF_OUTPUT]);
1450 			exit(1);
1451 		}
1452 		(void) close(p[0]);		/* close input side */
1453 		ofd = p[1];			/* use pipe for output */
1454 	} else {
1455 		ofd = pfd;
1456 		ofilter = 0;
1457 	}
1458 }
1459 
1460 /*
1461  * Printer connected directly to the network
1462  * or to a terminal server on the net
1463  */
1464 static void
1465 opennet(pp)
1466 	const struct printer *pp;
1467 {
1468 	register int i;
1469 	int resp;
1470 	u_long port;
1471 	char *ep;
1472 	void (*savealrm)(int);
1473 
1474 	port = strtoul(pp->lp, &ep, 0);
1475 	if (*ep != '@' || port > 65535) {
1476 		syslog(LOG_ERR, "%s: bad port number: %s", pp->printer,
1477 		       pp->lp);
1478 		exit(1);
1479 	}
1480 	ep++;
1481 
1482 	for (i = 1; ; i = i < 256 ? i << 1 : i) {
1483 		resp = -1;
1484 		savealrm = signal(SIGALRM, alarmhandler);
1485 		alarm(pp->conn_timeout);
1486 		pfd = getport(pp, ep, port);
1487 		alarm(0);
1488 		(void)signal(SIGALRM, savealrm);
1489 		if (pfd < 0 && errno == ECONNREFUSED)
1490 			resp = 1;
1491 		else if (pfd >= 0) {
1492 			/*
1493 			 * need to delay a bit for rs232 lines
1494 			 * to stabilize in case printer is
1495 			 * connected via a terminal server
1496 			 */
1497 			delay(500);
1498 			break;
1499 		}
1500 		if (i == 1) {
1501 			if (resp < 0)
1502 				pstatus(pp, "waiting for %s to come up",
1503 					pp->lp);
1504 			else
1505 				pstatus(pp,
1506 					"waiting for access to printer on %s",
1507 					pp->lp);
1508 		}
1509 		sleep(i);
1510 	}
1511 	pstatus(pp, "sending to %s port %d", ep, port);
1512 }
1513 
1514 /*
1515  * Printer is connected to an RS232 port on this host
1516  */
1517 static void
1518 opentty(pp)
1519 	const struct printer *pp;
1520 {
1521 	register int i;
1522 
1523 	for (i = 1; ; i = i < 32 ? i << 1 : i) {
1524 		pfd = open(pp->lp, pp->rw ? O_RDWR : O_WRONLY);
1525 		if (pfd >= 0) {
1526 			delay(500);
1527 			break;
1528 		}
1529 		if (errno == ENOENT) {
1530 			syslog(LOG_ERR, "%s: %m", pp->lp);
1531 			exit(1);
1532 		}
1533 		if (i == 1)
1534 			pstatus(pp,
1535 				"waiting for %s to become ready (offline?)",
1536 				pp->printer);
1537 		sleep(i);
1538 	}
1539 	if (isatty(pfd))
1540 		setty(pp);
1541 	pstatus(pp, "%s is ready and printing", pp->printer);
1542 }
1543 
1544 /*
1545  * Printer is on a remote host
1546  */
1547 static void
1548 openrem(pp)
1549 	const struct printer *pp;
1550 {
1551 	register int i;
1552 	int resp;
1553 	void (*savealrm)(int);
1554 
1555 	for (i = 1; ; i = i < 256 ? i << 1 : i) {
1556 		resp = -1;
1557 		savealrm = signal(SIGALRM, alarmhandler);
1558 		alarm(pp->conn_timeout);
1559 		pfd = getport(pp, pp->remote_host, 0);
1560 		alarm(0);
1561 		(void)signal(SIGALRM, savealrm);
1562 		if (pfd >= 0) {
1563 			if ((writel(pfd, "\2", pp->remote_queue, "\n",
1564 				    (char *)0)
1565 			     == 2 + strlen(pp->remote_queue))
1566 			    && (resp = response(pp)) == 0)
1567 				break;
1568 			(void) close(pfd);
1569 		}
1570 		if (i == 1) {
1571 			if (resp < 0)
1572 				pstatus(pp, "waiting for %s to come up",
1573 					pp->remote_host);
1574 			else {
1575 				pstatus(pp,
1576 					"waiting for queue to be enabled on %s",
1577 					pp->remote_host);
1578 				i = 256;
1579 			}
1580 		}
1581 		sleep(i);
1582 	}
1583 	pstatus(pp, "sending to %s", pp->remote_host);
1584 }
1585 
1586 /*
1587  * setup tty lines.
1588  */
1589 static void
1590 setty(pp)
1591 	const struct printer *pp;
1592 {
1593 	struct termios ttybuf;
1594 
1595 	if (ioctl(pfd, TIOCEXCL, (char *)0) < 0) {
1596 		syslog(LOG_ERR, "%s: ioctl(TIOCEXCL): %m", pp->printer);
1597 		exit(1);
1598 	}
1599 	if (tcgetattr(pfd, &ttybuf) < 0) {
1600 		syslog(LOG_ERR, "%s: tcgetattr: %m", pp->printer);
1601 		exit(1);
1602 	}
1603 	if (pp->baud_rate > 0)
1604 		cfsetspeed(&ttybuf, pp->baud_rate);
1605 	if (pp->mode_set) {
1606 		char *s = strdup(pp->mode_set), *tmp;
1607 
1608 		while ((tmp = strsep(&s, ",")) != NULL) {
1609 			(void) msearch(tmp, &ttybuf);
1610 		}
1611 	}
1612 	if (pp->mode_set != 0 || pp->baud_rate > 0) {
1613 		if (tcsetattr(pfd, TCSAFLUSH, &ttybuf) == -1) {
1614 			syslog(LOG_ERR, "%s: tcsetattr: %m", pp->printer);
1615 		}
1616 	}
1617 }
1618 
1619 #ifdef __STDC__
1620 #include <stdarg.h>
1621 #else
1622 #include <varargs.h>
1623 #endif
1624 
1625 static void
1626 #ifdef __STDC__
1627 pstatus(const struct printer *pp, const char *msg, ...)
1628 #else
1629 pstatus(pp, msg, va_alist)
1630 	const struct printer *pp;
1631 	char *msg;
1632         va_dcl
1633 #endif
1634 {
1635 	int fd;
1636 	char *buf;
1637 	va_list ap;
1638 #ifdef __STDC__
1639 	va_start(ap, msg);
1640 #else
1641 	va_start(ap);
1642 #endif
1643 
1644 	umask(0);
1645 	fd = open(pp->status_file, O_WRONLY|O_CREAT|O_EXLOCK, STAT_FILE_MODE);
1646 	if (fd < 0) {
1647 		syslog(LOG_ERR, "%s: %s: %m", pp->printer, pp->status_file);
1648 		exit(1);
1649 	}
1650 	ftruncate(fd, 0);
1651 	vasprintf(&buf, msg, ap);
1652 	va_end(ap);
1653 	writel(fd, buf, "\n", (char *)0);
1654 	close(fd);
1655 	free(buf);
1656 }
1657 
1658 void
1659 alarmhandler(signo)
1660 {
1661 	/* ignored */
1662 }
1663