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