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