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