xref: /freebsd/usr.sbin/lpr/lpd/printjob.c (revision 243e928310d073338c5ec089f0dce238a80b9866)
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  * 4. Neither the name of the University nor the names of its contributors
15  *    may be used to endorse or promote products derived from this software
16  *    without specific prior written permission.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
19  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
22  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28  * SUCH DAMAGE.
29  */
30 
31 #ifndef lint
32 static const char copyright[] =
33 "@(#) Copyright (c) 1983, 1993\n\
34 	The Regents of the University of California.  All rights reserved.\n";
35 #endif /* not lint */
36 
37 #if 0
38 #ifndef lint
39 static char sccsid[] = "@(#)printjob.c	8.7 (Berkeley) 5/10/95";
40 #endif /* not lint */
41 #endif
42 
43 #include "lp.cdefs.h"		/* A cross-platform version of <sys/cdefs.h> */
44 __FBSDID("$FreeBSD$");
45 
46 /*
47  * printjob -- print jobs in the queue.
48  *
49  *	NOTE: the lock file is used to pass information to lpq and lprm.
50  *	it does not need to be removed because file locks are dynamic.
51  */
52 
53 #include <sys/param.h>
54 #include <sys/wait.h>
55 #include <sys/stat.h>
56 #include <sys/types.h>
57 
58 #include <pwd.h>
59 #include <unistd.h>
60 #include <signal.h>
61 #include <syslog.h>
62 #include <fcntl.h>
63 #include <dirent.h>
64 #include <err.h>
65 #include <errno.h>
66 #include <inttypes.h>
67 #include <stdio.h>
68 #include <string.h>
69 #include <stdlib.h>
70 #include <sys/ioctl.h>
71 #include <termios.h>
72 #include <time.h>
73 #include "lp.h"
74 #include "lp.local.h"
75 #include "pathnames.h"
76 #include "extern.h"
77 
78 #define DORETURN	0	/* dofork should return "can't fork" error */
79 #define DOABORT		1	/* dofork should just die if fork() fails */
80 
81 /*
82  * The buffer size to use when reading/writing spool files.
83  */
84 #define	SPL_BUFSIZ	BUFSIZ
85 
86 /*
87  * Error tokens
88  */
89 #define REPRINT		-2
90 #define ERROR		-1
91 #define	OK		0
92 #define	FATALERR	1
93 #define	NOACCT		2
94 #define	FILTERERR	3
95 #define	ACCESS		4
96 
97 static dev_t	 fdev;		/* device of file pointed to by symlink */
98 static ino_t	 fino;		/* inode of file pointed to by symlink */
99 static FILE	*cfp;		/* control file */
100 static pid_t	 of_pid;	/* process id of output filter, if any */
101 static int	 child;		/* id of any filters */
102 static int	 job_dfcnt;	/* count of datafiles in current user job */
103 static int	 lfd;		/* lock file descriptor */
104 static int	 ofd;		/* output filter file descriptor */
105 static int	 tfd = -1;	/* output filter temp file output */
106 static int	 pfd;		/* prstatic inter file descriptor */
107 static int	 prchild;	/* id of pr process */
108 static char	 title[80];	/* ``pr'' title */
109 static char      locale[80];    /* ``pr'' locale */
110 
111 /* these two are set from pp->daemon_user, but only if they are needed */
112 static char	*daemon_uname;	/* set from pwd->pw_name */
113 static int	 daemon_defgid;
114 
115 static char	class[32];		/* classification field */
116 static char	origin_host[MAXHOSTNAMELEN];	/* user's host machine */
117 				/* indentation size in static characters */
118 static char	indent[10] = "-i0";
119 static char	jobname[100];		/* job or file name */
120 static char	length[10] = "-l";	/* page length in lines */
121 static char	logname[32];		/* user's login name */
122 static char	pxlength[10] = "-y";	/* page length in pixels */
123 static char	pxwidth[10] = "-x";	/* page width in pixels */
124 /* tempstderr is the filename used to catch stderr from exec-ing filters */
125 static char	tempstderr[] = "errs.XXXXXXX";
126 static char	width[10] = "-w";	/* page width in static characters */
127 #define TFILENAME "fltXXXXXX"
128 static char	tfile[] = TFILENAME;	/* file name for filter output */
129 
130 static void	 abortpr(int _signo);
131 static void	 alarmhandler(int _signo);
132 static void	 banner(struct printer *_pp, char *_name1, char *_name2);
133 static int	 dofork(const struct printer *_pp, int _action);
134 static int	 dropit(int _c);
135 static int	 execfilter(struct printer *_pp, char *_f_cmd, char **_f_av,
136 		    int _infd, int _outfd);
137 static void	 init(struct printer *_pp);
138 static void	 openpr(const struct printer *_pp);
139 static void	 opennet(const struct printer *_pp);
140 static void	 opentty(const struct printer *_pp);
141 static void	 openrem(const struct printer *pp);
142 static int	 print(struct printer *_pp, int _format, char *_file);
143 static int	 printit(struct printer *_pp, char *_file);
144 static void	 pstatus(const struct printer *_pp, const char *_msg, ...)
145 		    __printflike(2, 3);
146 static char	 response(const struct printer *_pp);
147 static void	 scan_out(struct printer *_pp, int _scfd, char *_scsp,
148 		    int _dlm);
149 static char	*scnline(int _key, char *_p, int _c);
150 static int	 sendfile(struct printer *_pp, int _type, char *_file,
151 		    char _format, int _copyreq);
152 static int	 sendit(struct printer *_pp, char *_file);
153 static void	 sendmail(struct printer *_pp, char *_userid, int _bombed);
154 static void	 setty(const struct printer *_pp);
155 static void	 wait4data(struct printer *_pp, const char *_dfile);
156 
157 void
158 printjob(struct printer *pp)
159 {
160 	struct stat stb;
161 	register struct jobqueue *q, **qp;
162 	struct jobqueue **queue;
163 	register int i, nitems;
164 	off_t pidoff;
165 	pid_t printpid;
166 	int errcnt, jobcount, statok, tempfd;
167 
168 	jobcount = 0;
169 	init(pp); /* set up capabilities */
170 	(void) write(STDOUT_FILENO, "", 1);	/* ack that daemon is started */
171 	(void) close(STDERR_FILENO);			/* set up log file */
172 	if (open(pp->log_file, O_WRONLY|O_APPEND, LOG_FILE_MODE) < 0) {
173 		syslog(LOG_ERR, "%s: open(%s): %m", pp->printer,
174 		    pp->log_file);
175 		(void) open(_PATH_DEVNULL, O_WRONLY);
176 	}
177 	if(setgid(getegid()) != 0) err(1, "setgid() failed");
178 	printpid = getpid();			/* for use with lprm */
179 	setpgid((pid_t)0, printpid);
180 
181 	/*
182 	 * At initial lpd startup, printjob may be called with various
183 	 * signal handlers in effect.  After that initial startup, any
184 	 * calls to printjob will have a *different* set of signal-handlers
185 	 * in effect.  Make sure all handlers are the ones we want.
186 	 */
187 	signal(SIGCHLD, SIG_DFL);
188 	signal(SIGHUP, abortpr);
189 	signal(SIGINT, abortpr);
190 	signal(SIGQUIT, abortpr);
191 	signal(SIGTERM, abortpr);
192 
193 	/*
194 	 * uses short form file names
195 	 */
196 	if (chdir(pp->spool_dir) < 0) {
197 		syslog(LOG_ERR, "%s: chdir(%s): %m", pp->printer,
198 		    pp->spool_dir);
199 		exit(1);
200 	}
201 	statok = stat(pp->lock_file, &stb);
202 	if (statok == 0 && (stb.st_mode & LFM_PRINT_DIS))
203 		exit(0);		/* printing disabled */
204 	umask(S_IWOTH);
205 	lfd = open(pp->lock_file, O_WRONLY|O_CREAT|O_EXLOCK|O_NONBLOCK,
206 		   LOCK_FILE_MODE);
207 	if (lfd < 0) {
208 		if (errno == EWOULDBLOCK)	/* active daemon present */
209 			exit(0);
210 		syslog(LOG_ERR, "%s: open(%s): %m", pp->printer,
211 		    pp->lock_file);
212 		exit(1);
213 	}
214 	/*
215 	 * If the initial call to stat() failed, then lock_file will have
216 	 * been created by open().  Update &stb to match that new file.
217 	 */
218 	if (statok != 0)
219 		statok = stat(pp->lock_file, &stb);
220 	/* turn off non-blocking mode (was turned on for lock effects only) */
221 	if (fcntl(lfd, F_SETFL, 0) < 0) {
222 		syslog(LOG_ERR, "%s: fcntl(%s): %m", pp->printer,
223 		    pp->lock_file);
224 		exit(1);
225 	}
226 	ftruncate(lfd, 0);
227 	/*
228 	 * write process id for others to know
229 	 */
230 	sprintf(line, "%u\n", printpid);
231 	pidoff = i = strlen(line);
232 	if (write(lfd, line, i) != i) {
233 		syslog(LOG_ERR, "%s: write(%s): %m", pp->printer,
234 		    pp->lock_file);
235 		exit(1);
236 	}
237 	/*
238 	 * search the spool directory for work and sort by queue order.
239 	 */
240 	if ((nitems = getq(pp, &queue)) < 0) {
241 		syslog(LOG_ERR, "%s: can't scan %s", pp->printer,
242 		    pp->spool_dir);
243 		exit(1);
244 	}
245 	if (nitems == 0)		/* no work to do */
246 		exit(0);
247 	if (stb.st_mode & LFM_RESET_QUE) { /* reset queue flag */
248 		if (fchmod(lfd, stb.st_mode & ~LFM_RESET_QUE) < 0)
249 			syslog(LOG_ERR, "%s: fchmod(%s): %m", pp->printer,
250 			    pp->lock_file);
251 	}
252 
253 	/* create a file which will be used to hold stderr from filters */
254 	if ((tempfd = mkstemp(tempstderr)) == -1) {
255 		syslog(LOG_ERR, "%s: mkstemp(%s): %m", pp->printer,
256 		    tempstderr);
257 		exit(1);
258 	}
259 	if ((i = fchmod(tempfd, 0664)) == -1) {
260 		syslog(LOG_ERR, "%s: fchmod(%s): %m", pp->printer,
261 		    tempstderr);
262 		exit(1);
263 	}
264 	/* lpd doesn't need it to be open, it just needs it to exist */
265 	close(tempfd);
266 
267 	openpr(pp);			/* open printer or remote */
268 again:
269 	/*
270 	 * we found something to do now do it --
271 	 *    write the name of the current control file into the lock file
272 	 *    so the spool queue program can tell what we're working on
273 	 */
274 	for (qp = queue; nitems--; free((char *) q)) {
275 		q = *qp++;
276 		if (stat(q->job_cfname, &stb) < 0)
277 			continue;
278 		errcnt = 0;
279 	restart:
280 		(void) lseek(lfd, pidoff, 0);
281 		(void) snprintf(line, sizeof(line), "%s\n", q->job_cfname);
282 		i = strlen(line);
283 		if (write(lfd, line, i) != i)
284 			syslog(LOG_ERR, "%s: write(%s): %m", pp->printer,
285 			    pp->lock_file);
286 		if (!pp->remote)
287 			i = printit(pp, q->job_cfname);
288 		else
289 			i = sendit(pp, q->job_cfname);
290 		/*
291 		 * Check to see if we are supposed to stop printing or
292 		 * if we are to rebuild the queue.
293 		 */
294 		if (fstat(lfd, &stb) == 0) {
295 			/* stop printing before starting next job? */
296 			if (stb.st_mode & LFM_PRINT_DIS)
297 				goto done;
298 			/* rebuild queue (after lpc topq) */
299 			if (stb.st_mode & LFM_RESET_QUE) {
300 				for (free(q); nitems--; free(q))
301 					q = *qp++;
302 				if (fchmod(lfd, stb.st_mode & ~LFM_RESET_QUE)
303 				    < 0)
304 					syslog(LOG_WARNING,
305 					    "%s: fchmod(%s): %m",
306 					    pp->printer, pp->lock_file);
307 				break;
308 			}
309 		}
310 		if (i == OK)		/* all files of this job printed */
311 			jobcount++;
312 		else if (i == REPRINT && ++errcnt < 5) {
313 			/* try reprinting the job */
314 			syslog(LOG_INFO, "restarting %s", pp->printer);
315 			if (of_pid > 0) {
316 				kill(of_pid, SIGCONT); /* to be sure */
317 				(void) close(ofd);
318 				while ((i = wait(NULL)) > 0 && i != of_pid)
319 					;
320 				if (i < 0)
321 					syslog(LOG_WARNING, "%s: after kill(of=%d), wait() returned: %m",
322 					    pp->printer, of_pid);
323 				of_pid = 0;
324 			}
325 			(void) close(pfd);	/* close printer */
326 			if (ftruncate(lfd, pidoff) < 0)
327 				syslog(LOG_WARNING, "%s: ftruncate(%s): %m",
328 				    pp->printer, pp->lock_file);
329 			openpr(pp);		/* try to reopen printer */
330 			goto restart;
331 		} else {
332 			syslog(LOG_WARNING, "%s: job could not be %s (%s)",
333 			    pp->printer,
334 			    pp->remote ? "sent to remote host" : "printed",
335 			    q->job_cfname);
336 			if (i == REPRINT) {
337 				/* ensure we don't attempt this job again */
338 				(void) unlink(q->job_cfname);
339 				q->job_cfname[0] = 'd';
340 				(void) unlink(q->job_cfname);
341 				if (logname[0])
342 					sendmail(pp, logname, FATALERR);
343 			}
344 		}
345 	}
346 	free(queue);
347 	/*
348 	 * search the spool directory for more work.
349 	 */
350 	if ((nitems = getq(pp, &queue)) < 0) {
351 		syslog(LOG_ERR, "%s: can't scan %s", pp->printer,
352 		    pp->spool_dir);
353 		exit(1);
354 	}
355 	if (nitems == 0) {		/* no more work to do */
356 	done:
357 		if (jobcount > 0) {	/* jobs actually printed */
358 			if (!pp->no_formfeed && !pp->tof)
359 				(void) write(ofd, pp->form_feed,
360 					     strlen(pp->form_feed));
361 			if (pp->trailer != NULL) /* output trailer */
362 				(void) write(ofd, pp->trailer,
363 					     strlen(pp->trailer));
364 		}
365 		(void) close(ofd);
366 		(void) wait(NULL);
367 		(void) unlink(tempstderr);
368 		exit(0);
369 	}
370 	goto again;
371 }
372 
373 char	fonts[4][50];	/* fonts for troff */
374 
375 char ifonts[4][40] = {
376 	_PATH_VFONTR,
377 	_PATH_VFONTI,
378 	_PATH_VFONTB,
379 	_PATH_VFONTS,
380 };
381 
382 /*
383  * The remaining part is the reading of the control file (cf)
384  * and performing the various actions.
385  */
386 static int
387 printit(struct printer *pp, char *file)
388 {
389 	register int i;
390 	char *cp;
391 	int bombed, didignorehdr;
392 
393 	bombed = OK;
394 	didignorehdr = 0;
395 	/*
396 	 * open control file; ignore if no longer there.
397 	 */
398 	if ((cfp = fopen(file, "r")) == NULL) {
399 		syslog(LOG_INFO, "%s: fopen(%s): %m", pp->printer, file);
400 		return (OK);
401 	}
402 	/*
403 	 * Reset troff fonts.
404 	 */
405 	for (i = 0; i < 4; i++)
406 		strcpy(fonts[i], ifonts[i]);
407 	sprintf(&width[2], "%ld", pp->page_width);
408 	strcpy(indent+2, "0");
409 
410 	/* initialize job-specific count of datafiles processed */
411 	job_dfcnt = 0;
412 
413 	/*
414 	 *      read the control file for work to do
415 	 *
416 	 *      file format -- first character in the line is a command
417 	 *      rest of the line is the argument.
418 	 *      valid commands are:
419 	 *
420 	 *		S -- "stat info" for symbolic link protection
421 	 *		J -- "job name" on banner page
422 	 *		C -- "class name" on banner page
423 	 *              L -- "literal" user's name to print on banner
424 	 *		T -- "title" for pr
425 	 *		H -- "host name" of machine where lpr was done
426 	 *              P -- "person" user's login name
427 	 *              I -- "indent" amount to indent output
428 	 *		R -- laser dpi "resolution"
429 	 *              f -- "file name" name of text file to print
430 	 *		l -- "file name" text file with control chars
431 	 *		o -- "file name" postscript file, according to
432 	 *		     the RFC.  Here it is treated like an 'f'.
433 	 *		p -- "file name" text file to print with pr(1)
434 	 *		t -- "file name" troff(1) file to print
435 	 *		n -- "file name" ditroff(1) file to print
436 	 *		d -- "file name" dvi file to print
437 	 *		g -- "file name" plot(1G) file to print
438 	 *		v -- "file name" plain raster file to print
439 	 *		c -- "file name" cifplot file to print
440 	 *		1 -- "R font file" for troff
441 	 *		2 -- "I font file" for troff
442 	 *		3 -- "B font file" for troff
443 	 *		4 -- "S font file" for troff
444 	 *		N -- "name" of file (used by lpq)
445 	 *              U -- "unlink" name of file to remove
446 	 *                    (after we print it. (Pass 2 only)).
447 	 *		M -- "mail" to user when done printing
448 	 *              Z -- "locale" for pr
449 	 *
450 	 *      get_line reads a line and expands tabs to blanks
451 	 */
452 
453 	/* pass 1 */
454 
455 	while (get_line(cfp))
456 		switch (line[0]) {
457 		case 'H':
458 			strlcpy(origin_host, line + 1, sizeof(origin_host));
459 			if (class[0] == '\0') {
460 				strlcpy(class, line+1, sizeof(class));
461 			}
462 			continue;
463 
464 		case 'P':
465 			strlcpy(logname, line + 1, sizeof(logname));
466 			if (pp->restricted) { /* restricted */
467 				if (getpwnam(logname) == NULL) {
468 					bombed = NOACCT;
469 					sendmail(pp, line+1, bombed);
470 					goto pass2;
471 				}
472 			}
473 			continue;
474 
475 		case 'S':
476 			cp = line+1;
477 			i = 0;
478 			while (*cp >= '0' && *cp <= '9')
479 				i = i * 10 + (*cp++ - '0');
480 			fdev = i;
481 			cp++;
482 			i = 0;
483 			while (*cp >= '0' && *cp <= '9')
484 				i = i * 10 + (*cp++ - '0');
485 			fino = i;
486 			continue;
487 
488 		case 'J':
489 			if (line[1] != '\0') {
490 				strlcpy(jobname, line + 1, sizeof(jobname));
491 			} else
492 				strcpy(jobname, " ");
493 			continue;
494 
495 		case 'C':
496 			if (line[1] != '\0')
497 				strlcpy(class, line + 1, sizeof(class));
498 			else if (class[0] == '\0') {
499 				/* XXX - why call gethostname instead of
500 				 *       just strlcpy'ing local_host? */
501 				gethostname(class, sizeof(class));
502 				class[sizeof(class) - 1] = '\0';
503 			}
504 			continue;
505 
506 		case 'T':	/* header title for pr */
507 			strlcpy(title, line + 1, sizeof(title));
508 			continue;
509 
510 		case 'L':	/* identification line */
511 			if (!pp->no_header && !pp->header_last)
512 				banner(pp, line+1, jobname);
513 			continue;
514 
515 		case '1':	/* troff fonts */
516 		case '2':
517 		case '3':
518 		case '4':
519 			if (line[1] != '\0') {
520 				strlcpy(fonts[line[0]-'1'], line + 1,
521 				    (size_t)50);
522 			}
523 			continue;
524 
525 		case 'W':	/* page width */
526 			strlcpy(width+2, line + 1, sizeof(width) - 2);
527 			continue;
528 
529 		case 'I':	/* indent amount */
530 			strlcpy(indent+2, line + 1, sizeof(indent) - 2);
531 			continue;
532 
533 		case 'Z':       /* locale for pr */
534 			strlcpy(locale, line + 1, sizeof(locale));
535 			continue;
536 
537 		default:	/* some file to print */
538 			/* only lowercase cmd-codes include a file-to-print */
539 			if ((line[0] < 'a') || (line[0] > 'z')) {
540 				/* ignore any other lines */
541 				if (lflag <= 1)
542 					continue;
543 				if (!didignorehdr) {
544 					syslog(LOG_INFO, "%s: in %s :",
545 					    pp->printer, file);
546 					didignorehdr = 1;
547 				}
548 				syslog(LOG_INFO, "%s: ignoring line: '%c' %s",
549 				    pp->printer, line[0], &line[1]);
550 				continue;
551 			}
552 			i = print(pp, line[0], line+1);
553 			switch (i) {
554 			case ERROR:
555 				if (bombed == OK)
556 					bombed = FATALERR;
557 				break;
558 			case REPRINT:
559 				(void) fclose(cfp);
560 				return (REPRINT);
561 			case FILTERERR:
562 			case ACCESS:
563 				bombed = i;
564 				sendmail(pp, logname, bombed);
565 			}
566 			title[0] = '\0';
567 			continue;
568 
569 		case 'N':
570 		case 'U':
571 		case 'M':
572 		case 'R':
573 			continue;
574 		}
575 
576 	/* pass 2 */
577 
578 pass2:
579 	fseek(cfp, 0L, 0);
580 	while (get_line(cfp))
581 		switch (line[0]) {
582 		case 'L':	/* identification line */
583 			if (!pp->no_header && pp->header_last)
584 				banner(pp, line+1, jobname);
585 			continue;
586 
587 		case 'M':
588 			if (bombed < NOACCT)	/* already sent if >= NOACCT */
589 				sendmail(pp, line+1, bombed);
590 			continue;
591 
592 		case 'U':
593 			if (strchr(line+1, '/'))
594 				continue;
595 			(void) unlink(line+1);
596 		}
597 	/*
598 	 * clean-up in case another control file exists
599 	 */
600 	(void) fclose(cfp);
601 	(void) unlink(file);
602 	return (bombed == OK ? OK : ERROR);
603 }
604 
605 /*
606  * Print a file.
607  * Set up the chain [ PR [ | {IF, OF} ] ] or {IF, RF, TF, NF, DF, CF, VF}.
608  * Return -1 if a non-recoverable error occurred,
609  * 2 if the filter detected some errors (but printed the job anyway),
610  * 1 if we should try to reprint this job and
611  * 0 if all is well.
612  * Note: all filters take stdin as the file, stdout as the printer,
613  * stderr as the log file, and must not ignore SIGINT.
614  */
615 static int
616 print(struct printer *pp, int format, char *file)
617 {
618 	register int n, i;
619 	register char *prog;
620 	int fi, fo;
621 	FILE *fp;
622 	char *av[15], buf[SPL_BUFSIZ];
623 	pid_t wpid;
624 	int p[2], retcode, stopped, wstatus, wstatus_set;
625 	struct stat stb;
626 
627 	/* Make sure the entire data file has arrived. */
628 	wait4data(pp, file);
629 
630 	if (lstat(file, &stb) < 0 || (fi = open(file, O_RDONLY)) < 0) {
631 		syslog(LOG_INFO, "%s: unable to open %s ('%c' line)",
632 		    pp->printer, file, format);
633 		return (ERROR);
634 	}
635 	/*
636 	 * Check to see if data file is a symbolic link. If so, it should
637 	 * still point to the same file or someone is trying to print
638 	 * something he shouldn't.
639 	 */
640 	if ((stb.st_mode & S_IFMT) == S_IFLNK && fstat(fi, &stb) == 0 &&
641 	    (stb.st_dev != fdev || stb.st_ino != fino))
642 		return (ACCESS);
643 
644 	job_dfcnt++;		/* increment datafile counter for this job */
645 	stopped = 0;		/* output filter is not stopped */
646 
647 	/* everything seems OK, start it up */
648 	if (!pp->no_formfeed && !pp->tof) { /* start on a fresh page */
649 		(void) write(ofd, pp->form_feed, strlen(pp->form_feed));
650 		pp->tof = 1;
651 	}
652 	if (pp->filters[LPF_INPUT] == NULL
653 	    && (format == 'f' || format == 'l' || format == 'o')) {
654 		pp->tof = 0;
655 		while ((n = read(fi, buf, SPL_BUFSIZ)) > 0)
656 			if (write(ofd, buf, n) != n) {
657 				(void) close(fi);
658 				return (REPRINT);
659 			}
660 		(void) close(fi);
661 		return (OK);
662 	}
663 	switch (format) {
664 	case 'p':	/* print file using 'pr' */
665 		if (pp->filters[LPF_INPUT] == NULL) {	/* use output filter */
666 			prog = _PATH_PR;
667 			i = 0;
668 			av[i++] = "pr";
669 			av[i++] = width;
670 			av[i++] = length;
671 			av[i++] = "-h";
672 			av[i++] = *title ? title : " ";
673 			av[i++] = "-L";
674 			av[i++] = *locale ? locale : "C";
675 			av[i++] = "-F";
676 			av[i] = NULL;
677 			fo = ofd;
678 			goto start;
679 		}
680 		pipe(p);
681 		if ((prchild = dofork(pp, DORETURN)) == 0) {	/* child */
682 			dup2(fi, STDIN_FILENO);		/* file is stdin */
683 			dup2(p[1], STDOUT_FILENO);	/* pipe is stdout */
684 			closelog();
685 			closeallfds(3);
686 			execl(_PATH_PR, "pr", width, length,
687 			    "-h", *title ? title : " ",
688 			    "-L", *locale ? locale : "C",
689 			    "-F", (char *)0);
690 			syslog(LOG_ERR, "cannot execl %s", _PATH_PR);
691 			exit(2);
692 		}
693 		(void) close(p[1]);		/* close output side */
694 		(void) close(fi);
695 		if (prchild < 0) {
696 			prchild = 0;
697 			(void) close(p[0]);
698 			return (ERROR);
699 		}
700 		fi = p[0];			/* use pipe for input */
701 	case 'f':	/* print plain text file */
702 		prog = pp->filters[LPF_INPUT];
703 		av[1] = width;
704 		av[2] = length;
705 		av[3] = indent;
706 		n = 4;
707 		break;
708 	case 'o':	/* print postscript file */
709 		/*
710 		 * Treat this as a "plain file with control characters", and
711 		 * assume the standard LPF_INPUT filter will recognize that
712 		 * the data is postscript and know what to do with it.  These
713 		 * 'o'-file requests could come from MacOS 10.1 systems.
714 		 * (later versions of MacOS 10 will explicitly use 'l')
715 		 * A postscript file can contain binary data, which is why 'l'
716 		 * is somewhat more appropriate than 'f'.
717 		 */
718 		/* FALLTHROUGH */
719 	case 'l':	/* like 'f' but pass control characters */
720 		prog = pp->filters[LPF_INPUT];
721 		av[1] = "-c";
722 		av[2] = width;
723 		av[3] = length;
724 		av[4] = indent;
725 		n = 5;
726 		break;
727 	case 'r':	/* print a fortran text file */
728 		prog = pp->filters[LPF_FORTRAN];
729 		av[1] = width;
730 		av[2] = length;
731 		n = 3;
732 		break;
733 	case 't':	/* print troff output */
734 	case 'n':	/* print ditroff output */
735 	case 'd':	/* print tex output */
736 		(void) unlink(".railmag");
737 		if ((fo = creat(".railmag", FILMOD)) < 0) {
738 			syslog(LOG_ERR, "%s: cannot create .railmag",
739 			    pp->printer);
740 			(void) unlink(".railmag");
741 		} else {
742 			for (n = 0; n < 4; n++) {
743 				if (fonts[n][0] != '/')
744 					(void) write(fo, _PATH_VFONT,
745 					    sizeof(_PATH_VFONT) - 1);
746 				(void) write(fo, fonts[n], strlen(fonts[n]));
747 				(void) write(fo, "\n", 1);
748 			}
749 			(void) close(fo);
750 		}
751 		prog = (format == 't') ? pp->filters[LPF_TROFF]
752 			: ((format == 'n') ? pp->filters[LPF_DITROFF]
753 			   : pp->filters[LPF_DVI]);
754 		av[1] = pxwidth;
755 		av[2] = pxlength;
756 		n = 3;
757 		break;
758 	case 'c':	/* print cifplot output */
759 		prog = pp->filters[LPF_CIFPLOT];
760 		av[1] = pxwidth;
761 		av[2] = pxlength;
762 		n = 3;
763 		break;
764 	case 'g':	/* print plot(1G) output */
765 		prog = pp->filters[LPF_GRAPH];
766 		av[1] = pxwidth;
767 		av[2] = pxlength;
768 		n = 3;
769 		break;
770 	case 'v':	/* print raster output */
771 		prog = pp->filters[LPF_RASTER];
772 		av[1] = pxwidth;
773 		av[2] = pxlength;
774 		n = 3;
775 		break;
776 	default:
777 		(void) close(fi);
778 		syslog(LOG_ERR, "%s: illegal format character '%c'",
779 		    pp->printer, format);
780 		return (ERROR);
781 	}
782 	if (prog == NULL) {
783 		(void) close(fi);
784 		syslog(LOG_ERR,
785 		   "%s: no filter found in printcap for format character '%c'",
786 		   pp->printer, format);
787 		return (ERROR);
788 	}
789 	if ((av[0] = strrchr(prog, '/')) != NULL)
790 		av[0]++;
791 	else
792 		av[0] = prog;
793 	av[n++] = "-n";
794 	av[n++] = logname;
795 	av[n++] = "-h";
796 	av[n++] = origin_host;
797 	av[n++] = pp->acct_file;
798 	av[n] = NULL;
799 	fo = pfd;
800 	if (of_pid > 0) {		/* stop output filter */
801 		write(ofd, "\031\1", 2);
802 		while ((wpid =
803 		    wait3(&wstatus, WUNTRACED, 0)) > 0 && wpid != of_pid)
804 			;
805 		if (wpid < 0)
806 			syslog(LOG_WARNING,
807 			    "%s: after stopping 'of', wait3() returned: %m",
808 			    pp->printer);
809 		else if (!WIFSTOPPED(wstatus)) {
810 			(void) close(fi);
811 			syslog(LOG_WARNING, "%s: output filter died "
812 			    "(pid=%d retcode=%d termsig=%d)",
813 			    pp->printer, of_pid, WEXITSTATUS(wstatus),
814 			    WTERMSIG(wstatus));
815 			return (REPRINT);
816 		}
817 		stopped++;
818 	}
819 start:
820 	if ((child = dofork(pp, DORETURN)) == 0) { /* child */
821 		dup2(fi, STDIN_FILENO);
822 		dup2(fo, STDOUT_FILENO);
823 		/* setup stderr for the filter (child process)
824 		 * so it goes to our temporary errors file */
825 		n = open(tempstderr, O_WRONLY|O_TRUNC, 0664);
826 		if (n >= 0)
827 			dup2(n, STDERR_FILENO);
828 		closelog();
829 		closeallfds(3);
830 		execv(prog, av);
831 		syslog(LOG_ERR, "%s: cannot execv(%s): %m", pp->printer,
832 		    prog);
833 		exit(2);
834 	}
835 	(void) close(fi);
836 	wstatus_set = 0;
837 	if (child < 0)
838 		retcode = 100;
839 	else {
840 		while ((wpid = wait(&wstatus)) > 0 && wpid != child)
841 			;
842 		if (wpid < 0) {
843 			retcode = 100;
844 			syslog(LOG_WARNING,
845 			    "%s: after execv(%s), wait() returned: %m",
846 			    pp->printer, prog);
847 		} else {
848 			wstatus_set = 1;
849 			retcode = WEXITSTATUS(wstatus);
850 		}
851 	}
852 	child = 0;
853 	prchild = 0;
854 	if (stopped) {		/* restart output filter */
855 		if (kill(of_pid, SIGCONT) < 0) {
856 			syslog(LOG_ERR, "cannot restart output filter");
857 			exit(1);
858 		}
859 	}
860 	pp->tof = 0;
861 
862 	/* Copy the filter's output to "lf" logfile */
863 	if ((fp = fopen(tempstderr, "r"))) {
864 		while (fgets(buf, sizeof(buf), fp))
865 			fputs(buf, stderr);
866 		fclose(fp);
867 	}
868 
869 	if (wstatus_set && !WIFEXITED(wstatus)) {
870 		syslog(LOG_WARNING, "%s: filter '%c' terminated (termsig=%d)",
871 		    pp->printer, format, WTERMSIG(wstatus));
872 		return (ERROR);
873 	}
874 	switch (retcode) {
875 	case 0:
876 		pp->tof = 1;
877 		return (OK);
878 	case 1:
879 		return (REPRINT);
880 	case 2:
881 		return (ERROR);
882 	default:
883 		syslog(LOG_WARNING, "%s: filter '%c' exited (retcode=%d)",
884 		    pp->printer, format, retcode);
885 		return (FILTERERR);
886 	}
887 }
888 
889 /*
890  * Send the daemon control file (cf) and any data files.
891  * Return -1 if a non-recoverable error occurred, 1 if a recoverable error and
892  * 0 if all is well.
893  */
894 static int
895 sendit(struct printer *pp, char *file)
896 {
897 	int dfcopies, err, i;
898 	char *cp, last[sizeof(line)];
899 
900 	/*
901 	 * open control file
902 	 */
903 	if ((cfp = fopen(file, "r")) == NULL)
904 		return (OK);
905 
906 	/* initialize job-specific count of datafiles processed */
907 	job_dfcnt = 0;
908 
909 	/*
910 	 *      read the control file for work to do
911 	 *
912 	 *      file format -- first character in the line is a command
913 	 *      rest of the line is the argument.
914 	 *      commands of interest are:
915 	 *
916 	 *            a-z -- "file name" name of file to print
917 	 *              U -- "unlink" name of file to remove
918 	 *                    (after we print it. (Pass 2 only)).
919 	 */
920 
921 	/*
922 	 * pass 1
923 	 */
924 	err = OK;
925 	while (get_line(cfp)) {
926 	again:
927 		if (line[0] == 'S') {
928 			cp = line+1;
929 			i = 0;
930 			while (*cp >= '0' && *cp <= '9')
931 				i = i * 10 + (*cp++ - '0');
932 			fdev = i;
933 			cp++;
934 			i = 0;
935 			while (*cp >= '0' && *cp <= '9')
936 				i = i * 10 + (*cp++ - '0');
937 			fino = i;
938 		} else if (line[0] == 'H') {
939 			strlcpy(origin_host, line + 1, sizeof(origin_host));
940 			if (class[0] == '\0') {
941 				strlcpy(class, line + 1, sizeof(class));
942 			}
943 		} else if (line[0] == 'P') {
944 			strlcpy(logname, line + 1, sizeof(logname));
945 			if (pp->restricted) { /* restricted */
946 				if (getpwnam(logname) == NULL) {
947 					sendmail(pp, line+1, NOACCT);
948 					err = ERROR;
949 					break;
950 				}
951 			}
952 		} else if (line[0] == 'I') {
953 			strlcpy(indent+2, line + 1, sizeof(indent) - 2);
954 		} else if (line[0] >= 'a' && line[0] <= 'z') {
955 			dfcopies = 1;
956 			strcpy(last, line);
957 			while ((i = get_line(cfp)) != 0) {
958 				if (strcmp(last, line) != 0)
959 					break;
960 				dfcopies++;
961 			}
962 			switch (sendfile(pp, '\3', last+1, *last, dfcopies)) {
963 			case OK:
964 				if (i)
965 					goto again;
966 				break;
967 			case REPRINT:
968 				(void) fclose(cfp);
969 				return (REPRINT);
970 			case ACCESS:
971 				sendmail(pp, logname, ACCESS);
972 			case ERROR:
973 				err = ERROR;
974 			}
975 			break;
976 		}
977 	}
978 	if (err == OK && sendfile(pp, '\2', file, '\0', 1) > 0) {
979 		(void) fclose(cfp);
980 		return (REPRINT);
981 	}
982 	/*
983 	 * pass 2
984 	 */
985 	fseek(cfp, 0L, 0);
986 	while (get_line(cfp))
987 		if (line[0] == 'U' && !strchr(line+1, '/'))
988 			(void) unlink(line+1);
989 	/*
990 	 * clean-up in case another control file exists
991 	 */
992 	(void) fclose(cfp);
993 	(void) unlink(file);
994 	return (err);
995 }
996 
997 /*
998  * Send a data file to the remote machine and spool it.
999  * Return positive if we should try resending.
1000  */
1001 static int
1002 sendfile(struct printer *pp, int type, char *file, char format, int copyreq)
1003 {
1004 	int i, amt;
1005 	struct stat stb;
1006 	char *av[15], *filtcmd;
1007 	char buf[SPL_BUFSIZ], opt_c[4], opt_h[4], opt_n[4];
1008 	int copycnt, filtstat, narg, resp, sfd, sfres, sizerr, statrc;
1009 
1010 	/* Make sure the entire data file has arrived. */
1011 	wait4data(pp, file);
1012 
1013 	statrc = lstat(file, &stb);
1014 	if (statrc < 0) {
1015 		syslog(LOG_ERR, "%s: error from lstat(%s): %m",
1016 		    pp->printer, file);
1017 		return (ERROR);
1018 	}
1019 	sfd = open(file, O_RDONLY);
1020 	if (sfd < 0) {
1021 		syslog(LOG_ERR, "%s: error from open(%s,O_RDONLY): %m",
1022 		    pp->printer, file);
1023 		return (ERROR);
1024 	}
1025 	/*
1026 	 * Check to see if data file is a symbolic link. If so, it should
1027 	 * still point to the same file or someone is trying to print something
1028 	 * he shouldn't.
1029 	 */
1030 	if ((stb.st_mode & S_IFMT) == S_IFLNK && fstat(sfd, &stb) == 0 &&
1031 	    (stb.st_dev != fdev || stb.st_ino != fino)) {
1032 		close(sfd);
1033 		return (ACCESS);
1034 	}
1035 
1036 	/* Everything seems OK for reading the file, now to send it */
1037 	filtcmd = NULL;
1038 	sizerr = 0;
1039 	tfd = -1;
1040 	if (type == '\3') {
1041 		/*
1042 		 * Type == 3 means this is a datafile, not a control file.
1043 		 * Increment the counter of data-files in this job, and
1044 		 * then check for input or output filters (which are only
1045 		 * applied to datafiles, not control files).
1046 		 */
1047 		job_dfcnt++;
1048 
1049 		/*
1050 		 * Note that here we are filtering datafiles, one at a time,
1051 		 * as they are sent to the remote machine.  Here, the *only*
1052 		 * difference between an input filter (`if=') and an output
1053 		 * filter (`of=') is the argument list that the filter is
1054 		 * started up with.  Here, the output filter is executed
1055 		 * for each individual file as it is sent.  This is not the
1056 		 * same as local print queues, where the output filter is
1057 		 * started up once, and then all jobs are passed thru that
1058 		 * single invocation of the output filter.
1059 		 *
1060 		 * Also note that a queue for a remote-machine can have an
1061 		 * input filter or an output filter, but not both.
1062 		 */
1063 		if (pp->filters[LPF_INPUT]) {
1064 			filtcmd = pp->filters[LPF_INPUT];
1065 			av[0] = filtcmd;
1066 			narg = 0;
1067 			strcpy(opt_c, "-c");
1068 			strcpy(opt_h, "-h");
1069 			strcpy(opt_n, "-n");
1070 			if (format == 'l')
1071 				av[++narg] = opt_c;
1072 			av[++narg] = width;
1073 			av[++narg] = length;
1074 			av[++narg] = indent;
1075 			av[++narg] = opt_n;
1076 			av[++narg] = logname;
1077 			av[++narg] = opt_h;
1078 			av[++narg] = origin_host;
1079 			av[++narg] = pp->acct_file;
1080 			av[++narg] = NULL;
1081 		} else if (pp->filters[LPF_OUTPUT]) {
1082 			filtcmd = pp->filters[LPF_OUTPUT];
1083 			av[0] = filtcmd;
1084 			narg = 0;
1085 			av[++narg] = width;
1086 			av[++narg] = length;
1087 			av[++narg] = NULL;
1088 		}
1089 	}
1090 	if (filtcmd) {
1091 		/*
1092 		 * If there is an input or output filter, we have to run
1093 		 * the datafile thru that filter and store the result as
1094 		 * a temporary spool file, because the protocol requires
1095 		 * that we send the remote host the file-size before we
1096 		 * start to send any of the data.
1097 		 */
1098 		strcpy(tfile, TFILENAME);
1099 		tfd = mkstemp(tfile);
1100 		if (tfd == -1) {
1101 			syslog(LOG_ERR, "%s: mkstemp(%s): %m", pp->printer,
1102 			    TFILENAME);
1103 			sfres = ERROR;
1104 			goto return_sfres;
1105 		}
1106 		filtstat = execfilter(pp, filtcmd, av, sfd, tfd);
1107 
1108 		/* process the return-code from the filter */
1109 		switch (filtstat) {
1110 		case 0:
1111 			break;
1112 		case 1:
1113 			sfres = REPRINT;
1114 			goto return_sfres;
1115 		case 2:
1116 			sfres = ERROR;
1117 			goto return_sfres;
1118 		default:
1119 			syslog(LOG_WARNING,
1120 			    "%s: filter '%c' exited (retcode=%d)",
1121 			    pp->printer, format, filtstat);
1122 			sfres = FILTERERR;
1123 			goto return_sfres;
1124 		}
1125 		statrc = fstat(tfd, &stb);   /* to find size of tfile */
1126 		if (statrc < 0)	{
1127 			syslog(LOG_ERR,
1128 			    "%s: error processing 'if', fstat(%s): %m",
1129 			    pp->printer, tfile);
1130 			sfres = ERROR;
1131 			goto return_sfres;
1132 		}
1133 		close(sfd);
1134 		sfd = tfd;
1135 		lseek(sfd, 0, SEEK_SET);
1136 	}
1137 
1138 	copycnt = 0;
1139 sendagain:
1140 	copycnt++;
1141 
1142 	if (copycnt < 2)
1143 		(void) sprintf(buf, "%c%" PRId64 " %s\n", type, stb.st_size,
1144 		    file);
1145 	else
1146 		(void) sprintf(buf, "%c%" PRId64 " %s_c%d\n", type, stb.st_size,
1147 		    file, copycnt);
1148 	amt = strlen(buf);
1149 	for (i = 0;  ; i++) {
1150 		if (write(pfd, buf, amt) != amt ||
1151 		    (resp = response(pp)) < 0 || resp == '\1') {
1152 			sfres = REPRINT;
1153 			goto return_sfres;
1154 		} else if (resp == '\0')
1155 			break;
1156 		if (i == 0)
1157 			pstatus(pp,
1158 				"no space on remote; waiting for queue to drain");
1159 		if (i == 10)
1160 			syslog(LOG_ALERT, "%s: can't send to %s; queue full",
1161 			    pp->printer, pp->remote_host);
1162 		sleep(5 * 60);
1163 	}
1164 	if (i)
1165 		pstatus(pp, "sending to %s", pp->remote_host);
1166 	/*
1167 	 * XXX - we should change trstat_init()/trstat_write() to include
1168 	 *	 the copycnt in the statistics record it may write.
1169 	 */
1170 	if (type == '\3')
1171 		trstat_init(pp, file, job_dfcnt);
1172 	for (i = 0; i < stb.st_size; i += SPL_BUFSIZ) {
1173 		amt = SPL_BUFSIZ;
1174 		if (i + amt > stb.st_size)
1175 			amt = stb.st_size - i;
1176 		if (sizerr == 0 && read(sfd, buf, amt) != amt)
1177 			sizerr = 1;
1178 		if (write(pfd, buf, amt) != amt) {
1179 			sfres = REPRINT;
1180 			goto return_sfres;
1181 		}
1182 	}
1183 
1184 	if (sizerr) {
1185 		syslog(LOG_INFO, "%s: %s: changed size", pp->printer, file);
1186 		/* tell recvjob to ignore this file */
1187 		(void) write(pfd, "\1", 1);
1188 		sfres = ERROR;
1189 		goto return_sfres;
1190 	}
1191 	if (write(pfd, "", 1) != 1 || response(pp)) {
1192 		sfres = REPRINT;
1193 		goto return_sfres;
1194 	}
1195 	if (type == '\3') {
1196 		trstat_write(pp, TR_SENDING, stb.st_size, logname,
1197 		    pp->remote_host, origin_host);
1198 		/*
1199 		 * Usually we only need to send one copy of a datafile,
1200 		 * because the control-file will simply print the same
1201 		 * file multiple times.  However, some printers ignore
1202 		 * the control file, and simply print each data file as
1203 		 * it arrives.  For such "remote hosts", we need to
1204 		 * transfer the same data file multiple times.  Such a
1205 		 * a host is indicated by adding 'rc' to the printcap
1206 		 * entry.
1207 		 * XXX - Right now this ONLY works for remote hosts which
1208 		 *	do ignore the name of the data file, because
1209 		 *	this sends the file multiple times with slight
1210 		 *	changes to the filename.  To do this right would
1211 		 *	require that we also rewrite the control file
1212 		 *	to match those filenames.
1213 		 */
1214 		if (pp->resend_copies && (copycnt < copyreq)) {
1215 			lseek(sfd, 0, SEEK_SET);
1216 			goto sendagain;
1217 		}
1218 	}
1219 	sfres = OK;
1220 
1221 return_sfres:
1222 	(void)close(sfd);
1223 	if (tfd != -1) {
1224 		/*
1225 		 * If tfd is set, then it is the same value as sfd, and
1226 		 * therefore it is already closed at this point.  All
1227 		 * we need to do is remove the temporary file.
1228 		 */
1229 		tfd = -1;
1230 		unlink(tfile);
1231 	}
1232 	return (sfres);
1233 }
1234 
1235 /*
1236  * Some print servers send the control-file first, and then start sending the
1237  * matching data file(s).  That is not the correct order.  If some queue is
1238  * already printing an active job, then when that job is finished the queue
1239  * may proceed to the control file of any incoming print job.  This turns
1240  * into a race between the process which is receiving the data file, and the
1241  * process which is actively printing the very same file.  When the remote
1242  * server sends files in the wrong order, it is even possible that a queue
1243  * will start to print a data file before the file has been created!
1244  *
1245  * So before we start to print() or send() a data file, we call this routine
1246  * to make sure the data file is not still changing in size.  Note that this
1247  * problem will only happen for jobs arriving from a remote host, and that
1248  * the process which has decided to print this job (and is thus making this
1249  * check) is *not* the process which is receiving the job.
1250  *
1251  * A second benefit of this is that any incoming job is guaranteed to appear
1252  * in a queue listing for at least a few seconds after it has arrived.  Some
1253  * lpr implementations get confused if they send a job and it disappears
1254  * from the queue before they can check on it.
1255  */
1256 #define	MAXWAIT_ARRIVE	16	    /* max to wait for the file to *exist* */
1257 #define	MAXWAIT_4DATA	(20*60)	    /* max to wait for it to stop changing */
1258 #define	MINWAIT_4DATA	4	    /* This value must be >= 1 */
1259 #define	DEBUG_MINWAIT	1
1260 static void
1261 wait4data(struct printer *pp, const char *dfile)
1262 {
1263 	const char *cp;
1264 	int statres;
1265 	u_int sleepreq;
1266 	size_t dlen, hlen;
1267 	time_t amtslept, cur_time, prev_mtime;
1268 	struct stat statdf;
1269 
1270 	/* Skip these checks if the print job is from the local host. */
1271 	dlen = strlen(dfile);
1272 	hlen = strlen(local_host);
1273 	if (dlen > hlen) {
1274 		cp = dfile + dlen - hlen;
1275 		if (strcmp(cp, local_host) == 0)
1276 			return;
1277 	}
1278 
1279 	/*
1280 	 * If this data file does not exist, then wait up to MAXWAIT_ARRIVE
1281 	 * seconds for it to arrive.
1282 	 */
1283 	amtslept = 0;
1284 	statres = stat(dfile, &statdf);
1285 	while (statres < 0 && amtslept < MAXWAIT_ARRIVE) {
1286 		if (amtslept == 0)
1287 			pstatus(pp, "Waiting for data file from remote host");
1288 		amtslept += MINWAIT_4DATA - sleep(MINWAIT_4DATA);
1289 		statres = stat(dfile, &statdf);
1290 	}
1291 	if (statres < 0) {
1292 		/* The file still does not exist, so just give up on it. */
1293 		syslog(LOG_WARNING, "%s: wait4data() abandoned wait for %s",
1294 		    pp->printer, dfile);
1295 		return;
1296 	}
1297 
1298 	/*
1299 	 * The file exists, so keep waiting until the data file has not
1300 	 * changed for some reasonable amount of time.  Extra care is
1301 	 * taken when computing wait-times, just in case there are data
1302 	 * files with a last-modify time in the future.  While that is
1303 	 * very unlikely to happen, it can happen when the system has
1304 	 * a flakey time-of-day clock.
1305 	 */
1306 	prev_mtime = statdf.st_mtime;
1307 	cur_time = time(NULL);
1308 	if (statdf.st_mtime >= cur_time - MINWAIT_4DATA) {
1309 		if (statdf.st_mtime >= cur_time)	/* some TOD oddity */
1310 			sleepreq = MINWAIT_4DATA;
1311 		else
1312 			sleepreq = cur_time - statdf.st_mtime;
1313 		if (amtslept == 0)
1314 			pstatus(pp, "Waiting for data file from remote host");
1315 		amtslept += sleepreq - sleep(sleepreq);
1316 		statres = stat(dfile, &statdf);
1317 	}
1318 	sleepreq = MINWAIT_4DATA;
1319 	while (statres == 0 && amtslept < MAXWAIT_4DATA) {
1320 		if (statdf.st_mtime == prev_mtime)
1321 			break;
1322 		prev_mtime = statdf.st_mtime;
1323 		amtslept += sleepreq - sleep(sleepreq);
1324 		statres = stat(dfile, &statdf);
1325 	}
1326 
1327 	if (statres != 0)
1328 		syslog(LOG_WARNING, "%s: %s disappeared during wait4data()",
1329 		    pp->printer, dfile);
1330 	else if (amtslept > MAXWAIT_4DATA)
1331 		syslog(LOG_WARNING,
1332 		    "%s: %s still changing after %lu secs in wait4data()",
1333 		    pp->printer, dfile, (unsigned long)amtslept);
1334 #if DEBUG_MINWAIT
1335 	else if (amtslept > MINWAIT_4DATA)
1336 		syslog(LOG_INFO, "%s: slept %lu secs in wait4data(%s)",
1337 		    pp->printer, (unsigned long)amtslept, dfile);
1338 #endif
1339 }
1340 #undef	MAXWAIT_ARRIVE
1341 #undef	MAXWAIT_4DATA
1342 #undef	MINWAIT_4DATA
1343 
1344 /*
1345  *  This routine is called to execute one of the filters as was
1346  *  specified in a printcap entry.  While the child-process will read
1347  *  all of 'infd', it is up to the caller to close that file descriptor
1348  *  in the parent process.
1349  */
1350 static int
1351 execfilter(struct printer *pp, char *f_cmd, char *f_av[], int infd, int outfd)
1352 {
1353 	pid_t fpid, wpid;
1354 	int errfd, retcode, wstatus;
1355 	FILE *errfp;
1356 	char buf[BUFSIZ], *slash;
1357 
1358 	fpid = dofork(pp, DORETURN);
1359 	if (fpid != 0) {
1360 		/*
1361 		 * This is the parent process, which just waits for the child
1362 		 * to complete and then returns the result.  Note that it is
1363 		 * the child process which reads the input stream.
1364 		 */
1365 		if (fpid < 0)
1366 			retcode = 100;
1367 		else {
1368 			while ((wpid = wait(&wstatus)) > 0 &&
1369 			    wpid != fpid)
1370 				;
1371 			if (wpid < 0) {
1372 				retcode = 100;
1373 				syslog(LOG_WARNING,
1374 				    "%s: after execv(%s), wait() returned: %m",
1375 				    pp->printer, f_cmd);
1376 			} else
1377 				retcode = WEXITSTATUS(wstatus);
1378 		}
1379 
1380 		/*
1381 		 * Copy everything the filter wrote to stderr from our
1382 		 * temporary errors file to the "lf=" logfile.
1383 		 */
1384 		errfp = fopen(tempstderr, "r");
1385 		if (errfp) {
1386 			while (fgets(buf, sizeof(buf), errfp))
1387 				fputs(buf, stderr);
1388 			fclose(errfp);
1389 		}
1390 
1391 		return (retcode);
1392 	}
1393 
1394 	/*
1395 	 * This is the child process, which is the one that executes the
1396 	 * given filter.
1397 	 */
1398 	/*
1399 	 * If the first parameter has any slashes in it, then change it
1400 	 * to point to the first character after the last slash.
1401 	 */
1402 	slash = strrchr(f_av[0], '/');
1403 	if (slash != NULL)
1404 		f_av[0] = slash + 1;
1405 	/*
1406 	 * XXX - in the future, this should setup an explicit list of
1407 	 *       environment variables and use execve()!
1408 	 */
1409 
1410 	/*
1411 	 * Setup stdin, stdout, and stderr as we want them when the filter
1412 	 * is running.  Stderr is setup so it points to a temporary errors
1413 	 * file, and the parent process will copy that temporary file to
1414 	 * the real logfile after the filter completes.
1415 	 */
1416 	dup2(infd, STDIN_FILENO);
1417 	dup2(outfd, STDOUT_FILENO);
1418 	errfd = open(tempstderr, O_WRONLY|O_TRUNC, 0664);
1419 	if (errfd >= 0)
1420 		dup2(errfd, STDERR_FILENO);
1421 	closelog();
1422 	closeallfds(3);
1423 	execv(f_cmd, f_av);
1424 	syslog(LOG_ERR, "%s: cannot execv(%s): %m", pp->printer, f_cmd);
1425 	exit(2);
1426 	/* NOTREACHED */
1427 }
1428 
1429 /*
1430  * Check to make sure there have been no errors and that both programs
1431  * are in sync with eachother.
1432  * Return non-zero if the connection was lost.
1433  */
1434 static char
1435 response(const struct printer *pp)
1436 {
1437 	char resp;
1438 
1439 	if (read(pfd, &resp, 1) != 1) {
1440 		syslog(LOG_INFO, "%s: lost connection", pp->printer);
1441 		return (-1);
1442 	}
1443 	return (resp);
1444 }
1445 
1446 /*
1447  * Banner printing stuff
1448  */
1449 static void
1450 banner(struct printer *pp, char *name1, char *name2)
1451 {
1452 	time_t tvec;
1453 
1454 	time(&tvec);
1455 	if (!pp->no_formfeed && !pp->tof)
1456 		(void) write(ofd, pp->form_feed, strlen(pp->form_feed));
1457 	if (pp->short_banner) {	/* short banner only */
1458 		if (class[0]) {
1459 			(void) write(ofd, class, strlen(class));
1460 			(void) write(ofd, ":", 1);
1461 		}
1462 		(void) write(ofd, name1, strlen(name1));
1463 		(void) write(ofd, "  Job: ", 7);
1464 		(void) write(ofd, name2, strlen(name2));
1465 		(void) write(ofd, "  Date: ", 8);
1466 		(void) write(ofd, ctime(&tvec), 24);
1467 		(void) write(ofd, "\n", 1);
1468 	} else {	/* normal banner */
1469 		(void) write(ofd, "\n\n\n", 3);
1470 		scan_out(pp, ofd, name1, '\0');
1471 		(void) write(ofd, "\n\n", 2);
1472 		scan_out(pp, ofd, name2, '\0');
1473 		if (class[0]) {
1474 			(void) write(ofd,"\n\n\n",3);
1475 			scan_out(pp, ofd, class, '\0');
1476 		}
1477 		(void) write(ofd, "\n\n\n\n\t\t\t\t\tJob:  ", 15);
1478 		(void) write(ofd, name2, strlen(name2));
1479 		(void) write(ofd, "\n\t\t\t\t\tDate: ", 12);
1480 		(void) write(ofd, ctime(&tvec), 24);
1481 		(void) write(ofd, "\n", 1);
1482 	}
1483 	if (!pp->no_formfeed)
1484 		(void) write(ofd, pp->form_feed, strlen(pp->form_feed));
1485 	pp->tof = 1;
1486 }
1487 
1488 static char *
1489 scnline(int key, char *p, int c)
1490 {
1491 	register int scnwidth;
1492 
1493 	for (scnwidth = WIDTH; --scnwidth;) {
1494 		key <<= 1;
1495 		*p++ = key & 0200 ? c : BACKGND;
1496 	}
1497 	return (p);
1498 }
1499 
1500 #define TRC(q)	(((q)-' ')&0177)
1501 
1502 static void
1503 scan_out(struct printer *pp, int scfd, char *scsp, int dlm)
1504 {
1505 	register char *strp;
1506 	register int nchrs, j;
1507 	char outbuf[LINELEN+1], *sp, c, cc;
1508 	int d, scnhgt;
1509 
1510 	for (scnhgt = 0; scnhgt++ < HEIGHT+DROP; ) {
1511 		strp = &outbuf[0];
1512 		sp = scsp;
1513 		for (nchrs = 0; ; ) {
1514 			d = dropit(c = TRC(cc = *sp++));
1515 			if ((!d && scnhgt > HEIGHT) || (scnhgt <= DROP && d))
1516 				for (j = WIDTH; --j;)
1517 					*strp++ = BACKGND;
1518 			else
1519 				strp = scnline(scnkey[(int)c][scnhgt-1-d], strp, cc);
1520 			if (*sp == dlm || *sp == '\0' ||
1521 			    nchrs++ >= pp->page_width/(WIDTH+1)-1)
1522 				break;
1523 			*strp++ = BACKGND;
1524 			*strp++ = BACKGND;
1525 		}
1526 		while (*--strp == BACKGND && strp >= outbuf)
1527 			;
1528 		strp++;
1529 		*strp++ = '\n';
1530 		(void) write(scfd, outbuf, strp-outbuf);
1531 	}
1532 }
1533 
1534 static int
1535 dropit(int c)
1536 {
1537 	switch(c) {
1538 
1539 	case TRC('_'):
1540 	case TRC(';'):
1541 	case TRC(','):
1542 	case TRC('g'):
1543 	case TRC('j'):
1544 	case TRC('p'):
1545 	case TRC('q'):
1546 	case TRC('y'):
1547 		return (DROP);
1548 
1549 	default:
1550 		return (0);
1551 	}
1552 }
1553 
1554 /*
1555  * sendmail ---
1556  *   tell people about job completion
1557  */
1558 static void
1559 sendmail(struct printer *pp, char *userid, int bombed)
1560 {
1561 	register int i;
1562 	int p[2], s;
1563 	register const char *cp;
1564 	struct stat stb;
1565 	FILE *fp;
1566 
1567 	pipe(p);
1568 	if ((s = dofork(pp, DORETURN)) == 0) {		/* child */
1569 		dup2(p[0], STDIN_FILENO);
1570 		closelog();
1571 		closeallfds(3);
1572 		if ((cp = strrchr(_PATH_SENDMAIL, '/')) != NULL)
1573 			cp++;
1574 		else
1575 			cp = _PATH_SENDMAIL;
1576 		execl(_PATH_SENDMAIL, cp, "-t", (char *)0);
1577 		_exit(0);
1578 	} else if (s > 0) {				/* parent */
1579 		dup2(p[1], STDOUT_FILENO);
1580 		printf("To: %s@%s\n", userid, origin_host);
1581 		printf("Subject: %s printer job \"%s\"\n", pp->printer,
1582 			*jobname ? jobname : "<unknown>");
1583 		printf("Reply-To: root@%s\n\n", local_host);
1584 		printf("Your printer job ");
1585 		if (*jobname)
1586 			printf("(%s) ", jobname);
1587 
1588 		switch (bombed) {
1589 		case OK:
1590 			cp = "OK";
1591 			printf("\ncompleted successfully\n");
1592 			break;
1593 		default:
1594 		case FATALERR:
1595 			cp = "FATALERR";
1596 			printf("\ncould not be printed\n");
1597 			break;
1598 		case NOACCT:
1599 			cp = "NOACCT";
1600 			printf("\ncould not be printed without an account on %s\n",
1601 			    local_host);
1602 			break;
1603 		case FILTERERR:
1604 			cp = "FILTERERR";
1605 			if (stat(tempstderr, &stb) < 0 || stb.st_size == 0
1606 			    || (fp = fopen(tempstderr, "r")) == NULL) {
1607 				printf("\nhad some errors and may not have printed\n");
1608 				break;
1609 			}
1610 			printf("\nhad the following errors and may not have printed:\n");
1611 			while ((i = getc(fp)) != EOF)
1612 				putchar(i);
1613 			(void) fclose(fp);
1614 			break;
1615 		case ACCESS:
1616 			cp = "ACCESS";
1617 			printf("\nwas not printed because it was not linked to the original file\n");
1618 		}
1619 		fflush(stdout);
1620 		(void) close(STDOUT_FILENO);
1621 	} else {
1622 		syslog(LOG_WARNING, "unable to send mail to %s: %m", userid);
1623 		return;
1624 	}
1625 	(void) close(p[0]);
1626 	(void) close(p[1]);
1627 	wait(NULL);
1628 	syslog(LOG_INFO, "mail sent to user %s about job %s on printer %s (%s)",
1629 	    userid, *jobname ? jobname : "<unknown>", pp->printer, cp);
1630 }
1631 
1632 /*
1633  * dofork - fork with retries on failure
1634  */
1635 static int
1636 dofork(const struct printer *pp, int action)
1637 {
1638 	pid_t forkpid;
1639 	int i, fail;
1640 	struct passwd *pwd;
1641 
1642 	forkpid = -1;
1643 	if (daemon_uname == NULL) {
1644 		pwd = getpwuid(pp->daemon_user);
1645 		if (pwd == NULL) {
1646 			syslog(LOG_ERR, "%s: Can't lookup default daemon uid (%ld) in password file",
1647 			    pp->printer, pp->daemon_user);
1648 			goto error_ret;
1649 		}
1650 		daemon_uname = strdup(pwd->pw_name);
1651 		daemon_defgid = pwd->pw_gid;
1652 	}
1653 
1654 	for (i = 0; i < 20; i++) {
1655 		forkpid = fork();
1656 		if (forkpid < 0) {
1657 			sleep((unsigned)(i*i));
1658 			continue;
1659 		}
1660 		/*
1661 		 * Child should run as daemon instead of root
1662 		 */
1663 		if (forkpid == 0) {
1664 			errno = 0;
1665 			fail = initgroups(daemon_uname, daemon_defgid);
1666 			if (fail) {
1667 				syslog(LOG_ERR, "%s: initgroups(%s,%u): %m",
1668 				    pp->printer, daemon_uname, daemon_defgid);
1669 				break;
1670 			}
1671 			fail = setgid(daemon_defgid);
1672 			if (fail) {
1673 				syslog(LOG_ERR, "%s: setgid(%u): %m",
1674 				    pp->printer, daemon_defgid);
1675 				break;
1676 			}
1677 			fail = setuid(pp->daemon_user);
1678 			if (fail) {
1679 				syslog(LOG_ERR, "%s: setuid(%ld): %m",
1680 				    pp->printer, pp->daemon_user);
1681 				break;
1682 			}
1683 		}
1684 		return (forkpid);
1685 	}
1686 
1687 	/*
1688 	 * An error occurred.  If the error is in the child process, then
1689 	 * this routine MUST always exit().  DORETURN only effects how
1690 	 * errors should be handled in the parent process.
1691 	 */
1692 error_ret:
1693 	if (forkpid == 0) {
1694 		syslog(LOG_ERR, "%s: dofork(): aborting child process...",
1695 		    pp->printer);
1696 		exit(1);
1697 	}
1698 	syslog(LOG_ERR, "%s: dofork(): failure in fork", pp->printer);
1699 
1700 	sleep(1);		/* throttle errors, as a safety measure */
1701 	switch (action) {
1702 	case DORETURN:
1703 		return (-1);
1704 	default:
1705 		syslog(LOG_ERR, "bad action (%d) to dofork", action);
1706 		/* FALLTHROUGH */
1707 	case DOABORT:
1708 		exit(1);
1709 	}
1710 	/*NOTREACHED*/
1711 }
1712 
1713 /*
1714  * Kill child processes to abort current job.
1715  */
1716 static void
1717 abortpr(int signo __unused)
1718 {
1719 
1720 	(void) unlink(tempstderr);
1721 	kill(0, SIGINT);
1722 	if (of_pid > 0)
1723 		kill(of_pid, SIGCONT);
1724 	while (wait(NULL) > 0)
1725 		;
1726 	if (of_pid > 0 && tfd != -1)
1727 		unlink(tfile);
1728 	exit(0);
1729 }
1730 
1731 static void
1732 init(struct printer *pp)
1733 {
1734 	char *s;
1735 
1736 	sprintf(&width[2], "%ld", pp->page_width);
1737 	sprintf(&length[2], "%ld", pp->page_length);
1738 	sprintf(&pxwidth[2], "%ld", pp->page_pwidth);
1739 	sprintf(&pxlength[2], "%ld", pp->page_plength);
1740 	if ((s = checkremote(pp)) != NULL) {
1741 		syslog(LOG_WARNING, "%s", s);
1742 		free(s);
1743 	}
1744 }
1745 
1746 void
1747 startprinting(const char *printer)
1748 {
1749 	struct printer myprinter, *pp = &myprinter;
1750 	int status;
1751 
1752 	init_printer(pp);
1753 	status = getprintcap(printer, pp);
1754 	switch(status) {
1755 	case PCAPERR_OSERR:
1756 		syslog(LOG_ERR, "can't open printer description file: %m");
1757 		exit(1);
1758 	case PCAPERR_NOTFOUND:
1759 		syslog(LOG_ERR, "unknown printer: %s", printer);
1760 		exit(1);
1761 	case PCAPERR_TCLOOP:
1762 		fatal(pp, "potential reference loop detected in printcap file");
1763 	default:
1764 		break;
1765 	}
1766 	printjob(pp);
1767 }
1768 
1769 /*
1770  * Acquire line printer or remote connection.
1771  */
1772 static void
1773 openpr(const struct printer *pp)
1774 {
1775 	int p[2];
1776 	char *cp;
1777 
1778 	if (pp->remote) {
1779 		openrem(pp);
1780 		/*
1781 		 * Lpd does support the setting of 'of=' filters for
1782 		 * jobs going to remote machines, but that does not
1783 		 * have the same meaning as 'of=' does when handling
1784 		 * local print queues.  For remote machines, all 'of='
1785 		 * filter processing is handled in sendfile(), and that
1786 		 * does not use these global "output filter" variables.
1787 		 */
1788 		ofd = -1;
1789 		of_pid = 0;
1790 		return;
1791 	} else if (*pp->lp) {
1792 		if (strchr(pp->lp, '@') != NULL)
1793 			opennet(pp);
1794 		else
1795 			opentty(pp);
1796 	} else {
1797 		syslog(LOG_ERR, "%s: no line printer device or host name",
1798 		    pp->printer);
1799 		exit(1);
1800 	}
1801 
1802 	/*
1803 	 * Start up an output filter, if needed.
1804 	 */
1805 	if (pp->filters[LPF_OUTPUT] && !pp->filters[LPF_INPUT] && !of_pid) {
1806 		pipe(p);
1807 		if (pp->remote) {
1808 			strcpy(tfile, TFILENAME);
1809 			tfd = mkstemp(tfile);
1810 		}
1811 		if ((of_pid = dofork(pp, DOABORT)) == 0) {	/* child */
1812 			dup2(p[0], STDIN_FILENO);	/* pipe is std in */
1813 			/* tfile/printer is stdout */
1814 			dup2(pp->remote ? tfd : pfd, STDOUT_FILENO);
1815 			closelog();
1816 			closeallfds(3);
1817 			if ((cp = strrchr(pp->filters[LPF_OUTPUT], '/')) == NULL)
1818 				cp = pp->filters[LPF_OUTPUT];
1819 			else
1820 				cp++;
1821 			execl(pp->filters[LPF_OUTPUT], cp, width, length,
1822 			      (char *)0);
1823 			syslog(LOG_ERR, "%s: execl(%s): %m", pp->printer,
1824 			    pp->filters[LPF_OUTPUT]);
1825 			exit(1);
1826 		}
1827 		(void) close(p[0]);		/* close input side */
1828 		ofd = p[1];			/* use pipe for output */
1829 	} else {
1830 		ofd = pfd;
1831 		of_pid = 0;
1832 	}
1833 }
1834 
1835 /*
1836  * Printer connected directly to the network
1837  * or to a terminal server on the net
1838  */
1839 static void
1840 opennet(const struct printer *pp)
1841 {
1842 	register int i;
1843 	int resp;
1844 	u_long port;
1845 	char *ep;
1846 	void (*savealrm)(int);
1847 
1848 	port = strtoul(pp->lp, &ep, 0);
1849 	if (*ep != '@' || port > 65535) {
1850 		syslog(LOG_ERR, "%s: bad port number: %s", pp->printer,
1851 		    pp->lp);
1852 		exit(1);
1853 	}
1854 	ep++;
1855 
1856 	for (i = 1; ; i = i < 256 ? i << 1 : i) {
1857 		resp = -1;
1858 		savealrm = signal(SIGALRM, alarmhandler);
1859 		alarm(pp->conn_timeout);
1860 		pfd = getport(pp, ep, port);
1861 		alarm(0);
1862 		(void)signal(SIGALRM, savealrm);
1863 		if (pfd < 0 && errno == ECONNREFUSED)
1864 			resp = 1;
1865 		else if (pfd >= 0) {
1866 			/*
1867 			 * need to delay a bit for rs232 lines
1868 			 * to stabilize in case printer is
1869 			 * connected via a terminal server
1870 			 */
1871 			delay(500);
1872 			break;
1873 		}
1874 		if (i == 1) {
1875 			if (resp < 0)
1876 				pstatus(pp, "waiting for %s to come up",
1877 					pp->lp);
1878 			else
1879 				pstatus(pp,
1880 					"waiting for access to printer on %s",
1881 					pp->lp);
1882 		}
1883 		sleep(i);
1884 	}
1885 	pstatus(pp, "sending to %s port %lu", ep, port);
1886 }
1887 
1888 /*
1889  * Printer is connected to an RS232 port on this host
1890  */
1891 static void
1892 opentty(const struct printer *pp)
1893 {
1894 	register int i;
1895 
1896 	for (i = 1; ; i = i < 32 ? i << 1 : i) {
1897 		pfd = open(pp->lp, pp->rw ? O_RDWR : O_WRONLY);
1898 		if (pfd >= 0) {
1899 			delay(500);
1900 			break;
1901 		}
1902 		if (errno == ENOENT) {
1903 			syslog(LOG_ERR, "%s: %m", pp->lp);
1904 			exit(1);
1905 		}
1906 		if (i == 1)
1907 			pstatus(pp,
1908 				"waiting for %s to become ready (offline?)",
1909 				pp->printer);
1910 		sleep(i);
1911 	}
1912 	if (isatty(pfd))
1913 		setty(pp);
1914 	pstatus(pp, "%s is ready and printing", pp->printer);
1915 }
1916 
1917 /*
1918  * Printer is on a remote host
1919  */
1920 static void
1921 openrem(const struct printer *pp)
1922 {
1923 	register int i;
1924 	int resp;
1925 	void (*savealrm)(int);
1926 
1927 	for (i = 1; ; i = i < 256 ? i << 1 : i) {
1928 		resp = -1;
1929 		savealrm = signal(SIGALRM, alarmhandler);
1930 		alarm(pp->conn_timeout);
1931 		pfd = getport(pp, pp->remote_host, 0);
1932 		alarm(0);
1933 		(void)signal(SIGALRM, savealrm);
1934 		if (pfd >= 0) {
1935 			if ((writel(pfd, "\2", pp->remote_queue, "\n",
1936 				    (char *)0)
1937 			     == 2 + strlen(pp->remote_queue))
1938 			    && (resp = response(pp)) == 0)
1939 				break;
1940 			(void) close(pfd);
1941 		}
1942 		if (i == 1) {
1943 			if (resp < 0)
1944 				pstatus(pp, "waiting for %s to come up",
1945 					pp->remote_host);
1946 			else {
1947 				pstatus(pp,
1948 					"waiting for queue to be enabled on %s",
1949 					pp->remote_host);
1950 				i = 256;
1951 			}
1952 		}
1953 		sleep(i);
1954 	}
1955 	pstatus(pp, "sending to %s", pp->remote_host);
1956 }
1957 
1958 /*
1959  * setup tty lines.
1960  */
1961 static void
1962 setty(const struct printer *pp)
1963 {
1964 	struct termios ttybuf;
1965 
1966 	if (ioctl(pfd, TIOCEXCL, (char *)0) < 0) {
1967 		syslog(LOG_ERR, "%s: ioctl(TIOCEXCL): %m", pp->printer);
1968 		exit(1);
1969 	}
1970 	if (tcgetattr(pfd, &ttybuf) < 0) {
1971 		syslog(LOG_ERR, "%s: tcgetattr: %m", pp->printer);
1972 		exit(1);
1973 	}
1974 	if (pp->baud_rate > 0)
1975 		cfsetspeed(&ttybuf, pp->baud_rate);
1976 	if (pp->mode_set) {
1977 		char *s = strdup(pp->mode_set), *tmp;
1978 
1979 		while ((tmp = strsep(&s, ",")) != NULL) {
1980 			(void) msearch(tmp, &ttybuf);
1981 		}
1982 	}
1983 	if (pp->mode_set != 0 || pp->baud_rate > 0) {
1984 		if (tcsetattr(pfd, TCSAFLUSH, &ttybuf) == -1) {
1985 			syslog(LOG_ERR, "%s: tcsetattr: %m", pp->printer);
1986 		}
1987 	}
1988 }
1989 
1990 #include <stdarg.h>
1991 
1992 static void
1993 pstatus(const struct printer *pp, const char *msg, ...)
1994 {
1995 	int fd;
1996 	char *buf;
1997 	va_list ap;
1998 	va_start(ap, msg);
1999 
2000 	umask(S_IWOTH);
2001 	fd = open(pp->status_file, O_WRONLY|O_CREAT|O_EXLOCK, STAT_FILE_MODE);
2002 	if (fd < 0) {
2003 		syslog(LOG_ERR, "%s: open(%s): %m", pp->printer,
2004 		    pp->status_file);
2005 		exit(1);
2006 	}
2007 	ftruncate(fd, 0);
2008 	vasprintf(&buf, msg, ap);
2009 	va_end(ap);
2010 	writel(fd, buf, "\n", (char *)0);
2011 	close(fd);
2012 	free(buf);
2013 }
2014 
2015 void
2016 alarmhandler(int signo __unused)
2017 {
2018 	/* the signal is ignored */
2019 	/* (the '__unused' is just to avoid a compile-time warning) */
2020 }
2021