Home | History | Annotate | Line # | Download | only in lpd
printjob.c revision 1.11
      1 /*	$NetBSD: printjob.c,v 1.11 1996/12/09 09:57:46 mrg 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 	pidoff = i = snprintf(line, sizeof(line), "%u\n", pid);
    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 		i = snprintf(line, sizeof(line), "%s\n", q->q_name);
    216 		if (write(lfd, line, i) != i)
    217 			syslog(LOG_ERR, "%s: %s: %m", printer, LO);
    218 		if (!remote)
    219 			i = printit(q->q_name);
    220 		else
    221 			i = sendit(q->q_name);
    222 		/*
    223 		 * Check to see if we are supposed to stop printing or
    224 		 * if we are to rebuild the queue.
    225 		 */
    226 		if (fstat(lfd, &stb) == 0) {
    227 			/* stop printing before starting next job? */
    228 			if (stb.st_mode & 0100)
    229 				goto done;
    230 			/* rebuild queue (after lpc topq) */
    231 			if (stb.st_mode & 01) {
    232 				for (free((char *) q); nitems--; free((char *) q))
    233 					q = *qp++;
    234 				if (fchmod(lfd, stb.st_mode & 0776) < 0)
    235 					syslog(LOG_WARNING, "%s: %s: %m",
    236 						printer, LO);
    237 				break;
    238 			}
    239 		}
    240 		if (i == OK)		/* file ok and printed */
    241 			count++;
    242 		else if (i == REPRINT) { /* try reprinting the job */
    243 			syslog(LOG_INFO, "restarting %s", printer);
    244 			if (ofilter > 0) {
    245 				kill(ofilter, SIGCONT);	/* to be sure */
    246 				(void)close(ofd);
    247 				while ((i = wait(0)) > 0 && i != ofilter)
    248 					;
    249 				ofilter = 0;
    250 			}
    251 			(void)close(pfd);	/* close printer */
    252 			if (ftruncate(lfd, pidoff) < 0)
    253 				syslog(LOG_WARNING, "%s: %s: %m", printer, LO);
    254 			openpr();		/* try to reopen printer */
    255 			goto restart;
    256 		}
    257 	}
    258 	free((char *) queue);
    259 	/*
    260 	 * search the spool directory for more work.
    261 	 */
    262 	if ((nitems = getq(&queue)) < 0) {
    263 		syslog(LOG_ERR, "%s: can't scan %s", printer, SD);
    264 		exit(1);
    265 	}
    266 	if (nitems == 0) {		/* no more work to do */
    267 	done:
    268 		if (count > 0) {	/* Files actually printed */
    269 			if (!SF && !tof)
    270 				(void)write(ofd, FF, strlen(FF));
    271 			if (TR != NULL)		/* output trailer */
    272 				(void)write(ofd, TR, strlen(TR));
    273 		}
    274 		(void)unlink(tempfile);
    275 		exit(0);
    276 	}
    277 	goto again;
    278 }
    279 
    280 #define FONTLEN	50
    281 char	fonts[4][FONTLEN];	/* 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 		strncpy(fonts[i], ifonts[i], FONTLEN);
    314 	(void)snprintf(&width[2], sizeof(width) - 2, "%d", PW);
    315 	indent[2] = '0';
    316 	indent[3] = '\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 			strncpy(fromhost, line+1, sizeof(fromhost) - 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 				jobname[0] = ' ';
    393 				jobname[1] = '\0';
    394 			}
    395 			continue;
    396 
    397 		case 'C':
    398 			if (line[1] != '\0')
    399 				strncpy(class, line+1, sizeof(class) - 1);
    400 			else if (class[0] == '\0')
    401 				gethostname(class, sizeof(class));
    402 			continue;
    403 
    404 		case 'T':	/* header title for pr */
    405 			strncpy(title, line+1, sizeof(title) - 1);
    406 			continue;
    407 
    408 		case 'L':	/* identification line */
    409 			if (!SH && !HL)
    410 				banner(line+1, jobname);
    411 			continue;
    412 
    413 		case '1':	/* troff fonts */
    414 		case '2':
    415 		case '3':
    416 		case '4':
    417 			if (line[1] != '\0')
    418 				strncpy(fonts[line[0]-'1'], line+1, FONTLEN - 1);
    419 			continue;
    420 
    421 		case 'W':	/* page width */
    422 			strncpy(width+2, line+1, sizeof(width) - 3);
    423 			continue;
    424 
    425 		case 'I':	/* indent amount */
    426 			strncpy(indent+2, line+1, sizeof(indent) - 3);
    427 			continue;
    428 
    429 		default:	/* some file to print */
    430 			switch (i = print(line[0], line+1)) {
    431 			case ERROR:
    432 				if (bombed == OK)
    433 					bombed = FATALERR;
    434 				break;
    435 			case REPRINT:
    436 				(void)fclose(cfp);
    437 				return(REPRINT);
    438 			case FILTERERR:
    439 			case ACCESS:
    440 				bombed = i;
    441 				sendmail(logname, bombed);
    442 			}
    443 			title[0] = '\0';
    444 			continue;
    445 
    446 		case 'N':
    447 		case 'U':
    448 		case 'M':
    449 			continue;
    450 		}
    451 
    452 	/* pass 2 */
    453 
    454 pass2:
    455 	fseek(cfp, 0L, 0);
    456 	while (getline(cfp))
    457 		switch (line[0]) {
    458 		case 'L':	/* identification line */
    459 			if (!SH && HL)
    460 				banner(line+1, jobname);
    461 			continue;
    462 
    463 		case 'M':
    464 			if (bombed < NOACCT)	/* already sent if >= NOACCT */
    465 				sendmail(line+1, bombed);
    466 			continue;
    467 
    468 		case 'U':
    469 			(void)unlink(line+1);
    470 		}
    471 	/*
    472 	 * clean-up in case another control file exists
    473 	 */
    474 	(void)fclose(cfp);
    475 	(void)unlink(file);
    476 	return(bombed == OK ? OK : ERROR);
    477 }
    478 
    479 /*
    480  * Print a file.
    481  * Set up the chain [ PR [ | {IF, OF} ] ] or {IF, RF, TF, NF, DF, CF, VF}.
    482  * Return -1 if a non-recoverable error occured,
    483  * 2 if the filter detected some errors (but printed the job anyway),
    484  * 1 if we should try to reprint this job and
    485  * 0 if all is well.
    486  * Note: all filters take stdin as the file, stdout as the printer,
    487  * stderr as the log file, and must not ignore SIGINT.
    488  */
    489 static int
    490 print(format, file)
    491 	int format;
    492 	char *file;
    493 {
    494 	register int n;
    495 	register char *prog;
    496 	int fi, fo;
    497 	FILE *fp;
    498 	char *av[15], buf[BUFSIZ];
    499 	int pid, p[2], stopped = 0;
    500 	union wait status;
    501 	struct stat stb;
    502 
    503 	if (lstat(file, &stb) < 0 || (fi = open(file, O_RDONLY)) < 0)
    504 		return(ERROR);
    505 	/*
    506 	 * Check to see if data file is a symbolic link. If so, it should
    507 	 * still point to the same file or someone is trying to print
    508 	 * something he shouldn't.
    509 	 */
    510 	if ((stb.st_mode & S_IFMT) == S_IFLNK && fstat(fi, &stb) == 0 &&
    511 	    (stb.st_dev != fdev || stb.st_ino != fino))
    512 		return(ACCESS);
    513 	if (!SF && !tof) {		/* start on a fresh page */
    514 		(void)write(ofd, FF, strlen(FF));
    515 		tof = 1;
    516 	}
    517 	if (IF == NULL && (format == 'f' || format == 'l')) {
    518 		tof = 0;
    519 		while ((n = read(fi, buf, BUFSIZ)) > 0)
    520 			if (write(ofd, buf, n) != n) {
    521 				(void)close(fi);
    522 				return(REPRINT);
    523 			}
    524 		(void)close(fi);
    525 		return(OK);
    526 	}
    527 	switch (format) {
    528 	case 'p':	/* print file using 'pr' */
    529 		if (IF == NULL) {	/* use output filter */
    530 			prog = _PATH_PR;
    531 			av[0] = "pr";
    532 			av[1] = width;
    533 			av[2] = length;
    534 			av[3] = "-h";
    535 			av[4] = *title ? title : " ";
    536 			av[5] = 0;
    537 			fo = ofd;
    538 			goto start;
    539 		}
    540 		pipe(p);
    541 		if ((prchild = dofork(DORETURN)) == 0) {	/* child */
    542 			dup2(fi, 0);		/* file is stdin */
    543 			dup2(p[1], 1);		/* pipe is stdout */
    544 			for (n = 3; n < NOFILE; n++)
    545 				(void)close(n);
    546 			execl(_PATH_PR, "pr", width, length,
    547 			    "-h", *title ? title : " ", 0);
    548 			syslog(LOG_ERR, "cannot execl %s", _PATH_PR);
    549 			exit(2);
    550 		}
    551 		(void)close(p[1]);		/* close output side */
    552 		(void)close(fi);
    553 		if (prchild < 0) {
    554 			prchild = 0;
    555 			(void)close(p[0]);
    556 			return(ERROR);
    557 		}
    558 		fi = p[0];			/* use pipe for input */
    559 	case 'f':	/* print plain text file */
    560 		prog = IF;
    561 		av[1] = width;
    562 		av[2] = length;
    563 		av[3] = indent;
    564 		n = 4;
    565 		break;
    566 	case 'l':	/* like 'f' but pass control characters */
    567 		prog = IF;
    568 		av[1] = "-c";
    569 		av[2] = width;
    570 		av[3] = length;
    571 		av[4] = indent;
    572 		n = 5;
    573 		break;
    574 	case 'r':	/* print a fortran text file */
    575 		prog = RF;
    576 		av[1] = width;
    577 		av[2] = length;
    578 		n = 3;
    579 		break;
    580 	case 't':	/* print troff output */
    581 	case 'n':	/* print ditroff output */
    582 	case 'd':	/* print tex output */
    583 		(void)unlink(".railmag");
    584 		if ((fo = creat(".railmag", FILMOD)) < 0) {
    585 			syslog(LOG_ERR, "%s: cannot create .railmag", printer);
    586 			(void)unlink(".railmag");
    587 		} else {
    588 			for (n = 0; n < 4; n++) {
    589 				if (fonts[n][0] != '/')
    590 					(void)write(fo, _PATH_VFONT,
    591 					    sizeof(_PATH_VFONT) - 1);
    592 				(void)write(fo, fonts[n], strlen(fonts[n]));
    593 				(void)write(fo, "\n", 1);
    594 			}
    595 			(void)close(fo);
    596 		}
    597 		prog = (format == 't') ? TF : (format == 'n') ? NF : DF;
    598 		av[1] = pxwidth;
    599 		av[2] = pxlength;
    600 		n = 3;
    601 		break;
    602 	case 'c':	/* print cifplot output */
    603 		prog = CF;
    604 		av[1] = pxwidth;
    605 		av[2] = pxlength;
    606 		n = 3;
    607 		break;
    608 	case 'g':	/* print plot(1G) output */
    609 		prog = GF;
    610 		av[1] = pxwidth;
    611 		av[2] = pxlength;
    612 		n = 3;
    613 		break;
    614 	case 'v':	/* print raster output */
    615 		prog = VF;
    616 		av[1] = pxwidth;
    617 		av[2] = pxlength;
    618 		n = 3;
    619 		break;
    620 	default:
    621 		(void)close(fi);
    622 		syslog(LOG_ERR, "%s: illegal format character '%c'",
    623 			printer, format);
    624 		return(ERROR);
    625 	}
    626 	if ((av[0] = rindex(prog, '/')) != NULL)
    627 		av[0]++;
    628 	else
    629 		av[0] = prog;
    630 	av[n++] = "-n";
    631 	av[n++] = logname;
    632 	av[n++] = "-h";
    633 	av[n++] = fromhost;
    634 	av[n++] = AF;
    635 	av[n] = 0;
    636 	fo = pfd;
    637 	if (ofilter > 0) {		/* stop output filter */
    638 		write(ofd, "\031\1", 2);
    639 		while ((pid =
    640 		    wait3((int *)&status, WUNTRACED, 0)) > 0 && pid != ofilter)
    641 			;
    642 		if (status.w_stopval != WSTOPPED) {
    643 			(void)close(fi);
    644 			syslog(LOG_WARNING, "%s: output filter died (%d)",
    645 				printer, status.w_retcode);
    646 			return(REPRINT);
    647 		}
    648 		stopped++;
    649 	}
    650 start:
    651 	if ((child = dofork(DORETURN)) == 0) {	/* child */
    652 		dup2(fi, 0);
    653 		dup2(fo, 1);
    654 		n = open(tempfile, O_WRONLY|O_CREAT|O_TRUNC, 0664);
    655 		if (n >= 0)
    656 			dup2(n, 2);
    657 		for (n = 3; n < NOFILE; n++)
    658 			(void)close(n);
    659 		execv(prog, av);
    660 		syslog(LOG_ERR, "cannot execv %s", prog);
    661 		exit(2);
    662 	}
    663 	(void)close(fi);
    664 	if (child < 0)
    665 		status.w_retcode = 100;
    666 	else
    667 		while ((pid = wait((int *)&status)) > 0 && pid != child)
    668 			;
    669 	child = 0;
    670 	prchild = 0;
    671 	if (stopped) {		/* restart output filter */
    672 		if (kill(ofilter, SIGCONT) < 0) {
    673 			syslog(LOG_ERR, "cannot restart output filter");
    674 			exit(1);
    675 		}
    676 	}
    677 	tof = 0;
    678 
    679 	/* Copy filter output to "lf" logfile */
    680 	if (fp = fopen(tempfile, "r")) {
    681 		while (fgets(buf, sizeof(buf), fp))
    682 			fputs(buf, stderr);
    683 		fclose(fp);
    684 	}
    685 
    686 	if (!WIFEXITED(status)) {
    687 		syslog(LOG_WARNING, "%s: Daemon filter '%c' terminated (%d)",
    688 			printer, format, status.w_termsig);
    689 		return(ERROR);
    690 	}
    691 	switch (status.w_retcode) {
    692 	case 0:
    693 		tof = 1;
    694 		return(OK);
    695 	case 1:
    696 		return(REPRINT);
    697 	default:
    698 		syslog(LOG_WARNING, "%s: Daemon filter '%c' exited (%d)",
    699 			printer, format, status.w_retcode);
    700 	case 2:
    701 		return(ERROR);
    702 	}
    703 }
    704 
    705 /*
    706  * Send the daemon control file (cf) and any data files.
    707  * Return -1 if a non-recoverable error occured, 1 if a recoverable error and
    708  * 0 if all is well.
    709  */
    710 static int
    711 sendit(file)
    712 	char *file;
    713 {
    714 	register int i, err = OK;
    715 	char *cp, last[BUFSIZ];
    716 
    717 	/*
    718 	 * open control file
    719 	 */
    720 	if ((cfp = fopen(file, "r")) == NULL)
    721 		return(OK);
    722 	/*
    723 	 *      read the control file for work to do
    724 	 *
    725 	 *      file format -- first character in the line is a command
    726 	 *      rest of the line is the argument.
    727 	 *      commands of interest are:
    728 	 *
    729 	 *            a-z -- "file name" name of file to print
    730 	 *              U -- "unlink" name of file to remove
    731 	 *                    (after we print it. (Pass 2 only)).
    732 	 */
    733 
    734 	/*
    735 	 * pass 1
    736 	 */
    737 	while (getline(cfp)) {
    738 	again:
    739 		if (line[0] == 'S') {
    740 			cp = line+1;
    741 			i = 0;
    742 			while (*cp >= '0' && *cp <= '9')
    743 				i = i * 10 + (*cp++ - '0');
    744 			fdev = i;
    745 			cp++;
    746 			i = 0;
    747 			while (*cp >= '0' && *cp <= '9')
    748 				i = i * 10 + (*cp++ - '0');
    749 			fino = i;
    750 			continue;
    751 		}
    752 		if (line[0] >= 'a' && line[0] <= 'z') {
    753 			strncpy(last, line, sizeof(last) - 1);
    754 			while (i = getline(cfp))
    755 				if (strcmp(last, line))
    756 					break;
    757 			switch (sendfile('\3', last+1)) {
    758 			case OK:
    759 				if (i)
    760 					goto again;
    761 				break;
    762 			case REPRINT:
    763 				(void)fclose(cfp);
    764 				return(REPRINT);
    765 			case ACCESS:
    766 				sendmail(logname, ACCESS);
    767 			case ERROR:
    768 				err = ERROR;
    769 			}
    770 			break;
    771 		}
    772 	}
    773 	if (err == OK && sendfile('\2', file) > 0) {
    774 		(void)fclose(cfp);
    775 		return(REPRINT);
    776 	}
    777 	/*
    778 	 * pass 2
    779 	 */
    780 	fseek(cfp, 0L, 0);
    781 	while (getline(cfp))
    782 		if (line[0] == 'U')
    783 			(void)unlink(line+1);
    784 	/*
    785 	 * clean-up in case another control file exists
    786 	 */
    787 	(void)fclose(cfp);
    788 	(void)unlink(file);
    789 	return(err);
    790 }
    791 
    792 /*
    793  * Send a data file to the remote machine and spool it.
    794  * Return positive if we should try resending.
    795  */
    796 static int
    797 sendfile(type, file)
    798 	int type;
    799 	char *file;
    800 {
    801 	register int f, i, amt;
    802 	struct stat stb;
    803 	char buf[BUFSIZ];
    804 	int sizerr, resp;
    805 
    806 	if (lstat(file, &stb) < 0 || (f = open(file, O_RDONLY)) < 0)
    807 		return(ERROR);
    808 	/*
    809 	 * Check to see if data file is a symbolic link. If so, it should
    810 	 * still point to the same file or someone is trying to print something
    811 	 * he shouldn't.
    812 	 */
    813 	if ((stb.st_mode & S_IFMT) == S_IFLNK && fstat(f, &stb) == 0 &&
    814 	    (stb.st_dev != fdev || stb.st_ino != fino))
    815 		return(ACCESS);
    816 	amt = snprintf(buf, sizeof(buf), "%c%qd %s\n", type, stb.st_size, file);
    817 	for (i = 0;  ; i++) {
    818 		if (write(pfd, buf, amt) != amt ||
    819 		    (resp = response()) < 0 || resp == '\1') {
    820 			(void)close(f);
    821 			return(REPRINT);
    822 		} else if (resp == '\0')
    823 			break;
    824 		if (i == 0)
    825 			pstatus("no space on remote; waiting for queue to drain");
    826 		if (i == 10)
    827 			syslog(LOG_ALERT, "%s: can't send to %s; queue full",
    828 				printer, RM);
    829 		sleep(5 * 60);
    830 	}
    831 	if (i)
    832 		pstatus("sending to %s", RM);
    833 	sizerr = 0;
    834 	for (i = 0; i < stb.st_size; i += BUFSIZ) {
    835 		amt = BUFSIZ;
    836 		if (i + amt > stb.st_size)
    837 			amt = stb.st_size - i;
    838 		if (sizerr == 0 && read(f, buf, amt) != amt)
    839 			sizerr = 1;
    840 		if (write(pfd, buf, amt) != amt) {
    841 			(void)close(f);
    842 			return(REPRINT);
    843 		}
    844 	}
    845 
    846 
    847 
    848 
    849 	(void)close(f);
    850 	if (sizerr) {
    851 		syslog(LOG_INFO, "%s: %s: changed size", printer, file);
    852 		/* tell recvjob to ignore this file */
    853 		(void)write(pfd, "\1", 1);
    854 		return(ERROR);
    855 	}
    856 	if (write(pfd, "", 1) != 1 || response())
    857 		return(REPRINT);
    858 	return(OK);
    859 }
    860 
    861 /*
    862  * Check to make sure there have been no errors and that both programs
    863  * are in sync with eachother.
    864  * Return non-zero if the connection was lost.
    865  */
    866 static char
    867 response()
    868 {
    869 	char resp;
    870 
    871 	if (read(pfd, &resp, 1) != 1) {
    872 		syslog(LOG_INFO, "%s: lost connection", printer);
    873 		return(-1);
    874 	}
    875 	return(resp);
    876 }
    877 
    878 /*
    879  * Banner printing stuff
    880  */
    881 static void
    882 banner(name1, name2)
    883 	char *name1, *name2;
    884 {
    885 	time_t tvec;
    886 	extern char *ctime();
    887 
    888 	time(&tvec);
    889 	if (!SF && !tof)
    890 		(void)write(ofd, FF, strlen(FF));
    891 	if (SB) {	/* short banner only */
    892 		if (class[0]) {
    893 			(void)write(ofd, class, strlen(class));
    894 			(void)write(ofd, ":", 1);
    895 		}
    896 		(void)write(ofd, name1, strlen(name1));
    897 		(void)write(ofd, "  Job: ", 7);
    898 		(void)write(ofd, name2, strlen(name2));
    899 		(void)write(ofd, "  Date: ", 8);
    900 		(void)write(ofd, ctime(&tvec), 24);
    901 		(void)write(ofd, "\n", 1);
    902 	} else {	/* normal banner */
    903 		(void)write(ofd, "\n\n\n", 3);
    904 		scan_out(ofd, name1, '\0');
    905 		(void)write(ofd, "\n\n", 2);
    906 		scan_out(ofd, name2, '\0');
    907 		if (class[0]) {
    908 			(void)write(ofd,"\n\n\n",3);
    909 			scan_out(ofd, class, '\0');
    910 		}
    911 		(void)write(ofd, "\n\n\n\n\t\t\t\t\tJob:  ", 15);
    912 		(void)write(ofd, name2, strlen(name2));
    913 		(void)write(ofd, "\n\t\t\t\t\tDate: ", 12);
    914 		(void)write(ofd, ctime(&tvec), 24);
    915 		(void)write(ofd, "\n", 1);
    916 	}
    917 	if (!SF)
    918 		(void)write(ofd, FF, strlen(FF));
    919 	tof = 1;
    920 }
    921 
    922 static char *
    923 scnline(key, p, c)
    924 	register int key;
    925 	register char *p;
    926 	int c;
    927 {
    928 	register scnwidth;
    929 
    930 	for (scnwidth = WIDTH; --scnwidth;) {
    931 		key <<= 1;
    932 		*p++ = key & 0200 ? c : BACKGND;
    933 	}
    934 	return (p);
    935 }
    936 
    937 #define TRC(q)	(((q)-' ')&0177)
    938 
    939 static void
    940 scan_out(scfd, scsp, dlm)
    941 	int scfd, dlm;
    942 	char *scsp;
    943 {
    944 	register char *strp;
    945 	register nchrs, j;
    946 	char outbuf[LINELEN+1], *sp, c, cc;
    947 	int d, scnhgt;
    948 	extern char scnkey[][HEIGHT];	/* in lpdchar.c */
    949 
    950 	for (scnhgt = 0; scnhgt++ < HEIGHT+DROP; ) {
    951 		strp = &outbuf[0];
    952 		sp = scsp;
    953 		for (nchrs = 0; ; ) {
    954 			d = dropit(c = TRC(cc = *sp++));
    955 			if ((!d && scnhgt > HEIGHT) || (scnhgt <= DROP && d))
    956 				for (j = WIDTH; --j;)
    957 					*strp++ = BACKGND;
    958 			else
    959 				strp = scnline(scnkey[c][scnhgt-1-d], strp, cc);
    960 			if (*sp == dlm || *sp == '\0' || nchrs++ >= PW/(WIDTH+1)-1)
    961 				break;
    962 			*strp++ = BACKGND;
    963 			*strp++ = BACKGND;
    964 		}
    965 		while (*--strp == BACKGND && strp >= outbuf)
    966 			;
    967 		strp++;
    968 		*strp++ = '\n';
    969 		(void)write(scfd, outbuf, strp-outbuf);
    970 	}
    971 }
    972 
    973 static int
    974 dropit(c)
    975 	int c;
    976 {
    977 	switch(c) {
    978 
    979 	case TRC('_'):
    980 	case TRC(';'):
    981 	case TRC(','):
    982 	case TRC('g'):
    983 	case TRC('j'):
    984 	case TRC('p'):
    985 	case TRC('q'):
    986 	case TRC('y'):
    987 		return (DROP);
    988 
    989 	default:
    990 		return (0);
    991 	}
    992 }
    993 
    994 /*
    995  * sendmail ---
    996  *   tell people about job completion
    997  */
    998 static void
    999 sendmail(user, bombed)
   1000 	char *user;
   1001 	int bombed;
   1002 {
   1003 	register int i;
   1004 	int p[2], s;
   1005 	register char *cp;
   1006 	char buf[100];
   1007 	struct stat stb;
   1008 	FILE *fp;
   1009 
   1010 	pipe(p);
   1011 	if ((s = dofork(DORETURN)) == 0) {		/* child */
   1012 		dup2(p[0], 0);
   1013 		for (i = 3; i < NOFILE; i++)
   1014 			(void)close(i);
   1015 		if ((cp = rindex(_PATH_SENDMAIL, '/')) != NULL)
   1016 			cp++;
   1017 	else
   1018 			cp = _PATH_SENDMAIL;
   1019 		(void)snprintf(buf, sizeof(buf), "%s@%s", user, fromhost);
   1020 		execl(_PATH_SENDMAIL, cp, buf, 0);
   1021 		exit(0);
   1022 	} else if (s > 0) {				/* parent */
   1023 		dup2(p[1], 1);
   1024 		printf("To: %s@%s\n", user, fromhost);
   1025 		printf("Subject: printer job\n\n");
   1026 		printf("Your printer job ");
   1027 		if (*jobname)
   1028 			printf("(%s) ", jobname);
   1029 		switch (bombed) {
   1030 		case OK:
   1031 			printf("\ncompleted successfully\n");
   1032 			break;
   1033 		default:
   1034 		case FATALERR:
   1035 			printf("\ncould not be printed\n");
   1036 			break;
   1037 		case NOACCT:
   1038 			printf("\ncould not be printed without an account on %s\n", host);
   1039 			break;
   1040 		case FILTERERR:
   1041 			if (stat(tempfile, &stb) < 0 || stb.st_size == 0 ||
   1042 			    (fp = fopen(tempfile, "r")) == NULL) {
   1043 				printf("\nwas printed but had some errors\n");
   1044 				break;
   1045 			}
   1046 			printf("\nwas printed but had the following errors:\n");
   1047 			while ((i = getc(fp)) != EOF)
   1048 				putchar(i);
   1049 			(void)fclose(fp);
   1050 			break;
   1051 		case ACCESS:
   1052 			printf("\nwas not printed because it was not linked to the original file\n");
   1053 		}
   1054 		fflush(stdout);
   1055 		(void)close(1);
   1056 	}
   1057 	(void)close(p[0]);
   1058 	(void)close(p[1]);
   1059 	wait(&s);
   1060 }
   1061 
   1062 /*
   1063  * dofork - fork with retries on failure
   1064  */
   1065 static int
   1066 dofork(action)
   1067 	int action;
   1068 {
   1069 	register int i, pid;
   1070 	struct passwd *pw;
   1071 
   1072 	for (i = 0; i < 20; i++) {
   1073 		if ((pid = fork()) < 0) {
   1074 			sleep((unsigned)(i*i));
   1075 			continue;
   1076 		}
   1077 		/*
   1078 		 * Child should run as daemon instead of root
   1079 		 */
   1080 		if (pid == 0) {
   1081 			pw = getpwuid(DU);
   1082 			if (pw == 0) {
   1083 				syslog(LOG_ERR, "uid %d not in password file",
   1084 				    DU);
   1085 				break;
   1086 			}
   1087 			initgroups(pw->pw_name, pw->pw_gid);
   1088 			setgid(pw->pw_gid);
   1089 			setuid(DU);
   1090 		}
   1091 		return (pid);
   1092 	}
   1093 	syslog(LOG_ERR, "can't fork");
   1094 
   1095 	switch (action) {
   1096 	case DORETURN:
   1097 		return (-1);
   1098 	default:
   1099 		syslog(LOG_ERR, "bad action (%d) to dofork", action);
   1100 		/*FALL THRU*/
   1101 	case DOABORT:
   1102 		exit(1);
   1103 	}
   1104 	/*NOTREACHED*/
   1105 }
   1106 
   1107 /*
   1108  * Kill child processes to abort current job.
   1109  */
   1110 static void
   1111 abortpr(signo)
   1112 	int signo;
   1113 {
   1114 	(void)unlink(tempfile);
   1115 	kill(0, SIGINT);
   1116 	if (ofilter > 0)
   1117 		kill(ofilter, SIGCONT);
   1118 	while (wait(NULL) > 0)
   1119 		;
   1120 	exit(0);
   1121 }
   1122 
   1123 static void
   1124 init()
   1125 {
   1126 	int status;
   1127 	char *s;
   1128 
   1129 	if ((status = cgetent(&bp, printcapdb, printer)) == -2) {
   1130 		syslog(LOG_ERR, "can't open printer description file");
   1131 		exit(1);
   1132 	} else if (status == -1) {
   1133 		syslog(LOG_ERR, "unknown printer: %s", printer);
   1134 		exit(1);
   1135 	} else if (status == -3)
   1136 		fatal("potential reference loop detected in printcap file");
   1137 
   1138 	if (cgetstr(bp, "lp", &LP) == -1)
   1139 		LP = _PATH_DEFDEVLP;
   1140 	if (cgetstr(bp, "rp", &RP) == -1)
   1141 		RP = DEFLP;
   1142 	if (cgetstr(bp, "lo", &LO) == -1)
   1143 		LO = DEFLOCK;
   1144 	if (cgetstr(bp, "st", &ST) == -1)
   1145 		ST = DEFSTAT;
   1146 	if (cgetstr(bp, "lf", &LF) == -1)
   1147 		LF = _PATH_CONSOLE;
   1148 	if (cgetstr(bp, "sd", &SD) == -1)
   1149 		SD = _PATH_DEFSPOOL;
   1150 	if (cgetnum(bp, "du", &DU) < 0)
   1151 		DU = DEFUID;
   1152 	if (cgetstr(bp,"ff", &FF) == -1)
   1153 		FF = DEFFF;
   1154 	if (cgetnum(bp, "pw", &PW) < 0)
   1155 		PW = DEFWIDTH;
   1156 	(void)snprintf(&width[2], sizeof(width) - 2, "%d", PW);
   1157 	if (cgetnum(bp, "pl", &PL) < 0)
   1158 		PL = DEFLENGTH;
   1159 	(void)snprintf(&length[2], sizeof(length) - 2, "%d", PL);
   1160 	if (cgetnum(bp,"px", &PX) < 0)
   1161 		PX = 0;
   1162 	(void)snprintf(&pxwidth[2], sizeof(pxwidth) - 2, "%d", PX);
   1163 	if (cgetnum(bp, "py", &PY) < 0)
   1164 		PY = 0;
   1165 	(void)snprintf(&pxlength[2], sizeof(pxlength) - 2, "%d", PY);
   1166 	cgetstr(bp, "rm", &RM);
   1167 	if (s = checkremote())
   1168 		syslog(LOG_WARNING, s);
   1169 
   1170 	cgetstr(bp, "af", &AF);
   1171 	cgetstr(bp, "of", &OF);
   1172 	cgetstr(bp, "if", &IF);
   1173 	cgetstr(bp, "rf", &RF);
   1174 	cgetstr(bp, "tf", &TF);
   1175 	cgetstr(bp, "nf", &NF);
   1176 	cgetstr(bp, "df", &DF);
   1177 	cgetstr(bp, "gf", &GF);
   1178 	cgetstr(bp, "vf", &VF);
   1179 	cgetstr(bp, "cf", &CF);
   1180 	cgetstr(bp, "tr", &TR);
   1181 
   1182 	RS = (cgetcap(bp, "rs", ':') != NULL);
   1183 	SF = (cgetcap(bp, "sf", ':') != NULL);
   1184 	SH = (cgetcap(bp, "sh", ':') != NULL);
   1185 	SB = (cgetcap(bp, "sb", ':') != NULL);
   1186 	HL = (cgetcap(bp, "hl", ':') != NULL);
   1187 	RW = (cgetcap(bp, "rw", ':') != NULL);
   1188 
   1189 	cgetnum(bp, "br", &BR);
   1190 	if (cgetnum(bp, "fc", &FC) < 0)
   1191 		FC = 0;
   1192 	if (cgetnum(bp, "fs", &FS) < 0)
   1193 		FS = 0;
   1194 	if (cgetnum(bp, "xc", &XC) < 0)
   1195 		XC = 0;
   1196 	if (cgetnum(bp, "xs", &XS) < 0)
   1197 		XS = 0;
   1198 	cgetstr(bp, "ms", &MS);
   1199 
   1200 	tof = (cgetcap(bp, "fo", ':') == NULL);
   1201 }
   1202 
   1203 /*
   1204  * Acquire line printer or remote connection.
   1205  */
   1206 static void
   1207 openpr()
   1208 {
   1209 	register int i, n;
   1210 	int resp;
   1211 
   1212 	if (!sendtorem && *LP) {
   1213 		for (i = 1; ; i = i < 32 ? i << 1 : i) {
   1214 			pfd = open(LP, RW ? O_RDWR : O_WRONLY);
   1215 			if (pfd >= 0)
   1216 				break;
   1217 			if (errno == ENOENT) {
   1218 				syslog(LOG_ERR, "%s: %m", LP);
   1219 				exit(1);
   1220 			}
   1221 			if (i == 1)
   1222 				pstatus("waiting for %s to become ready (offline ?)", printer);
   1223 			sleep(i);
   1224 		}
   1225 		if (isatty(pfd))
   1226 			setty();
   1227 		pstatus("%s is ready and printing", printer);
   1228 	} else if (RM != NULL) {
   1229 		for (i = 1; ; i = i < 256 ? i << 1 : i) {
   1230 			resp = -1;
   1231 			pfd = getport(RM);
   1232 			if (pfd >= 0) {
   1233 				n = snprintf(line, sizeof(line), "\2%s\n", RP);
   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) - 2, msg, ap);
   1432 	va_end(ap);
   1433 	strncat(buf, "\n", 2);
   1434 	(void)write(fd, buf, strlen(buf));
   1435 	(void)close(fd);
   1436 }
   1437