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