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