Home | History | Annotate | Line # | Download | only in lpd
printjob.c revision 1.12
      1 /*	$NetBSD: printjob.c,v 1.12 1997/03/22 03:20:38 lukem 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 		unlink(tempfile);
    655 		n = open(tempfile, O_WRONLY|O_CREAT|O_TRUNC|O_EXCL, 0664);
    656 		if (n >= 0)
    657 			dup2(n, 2);
    658 		for (n = 3; n < NOFILE; n++)
    659 			(void)close(n);
    660 		execv(prog, av);
    661 		syslog(LOG_ERR, "cannot execv %s", prog);
    662 		exit(2);
    663 	}
    664 	(void)close(fi);
    665 	if (child < 0)
    666 		status.w_retcode = 100;
    667 	else
    668 		while ((pid = wait((int *)&status)) > 0 && pid != child)
    669 			;
    670 	child = 0;
    671 	prchild = 0;
    672 	if (stopped) {		/* restart output filter */
    673 		if (kill(ofilter, SIGCONT) < 0) {
    674 			syslog(LOG_ERR, "cannot restart output filter");
    675 			exit(1);
    676 		}
    677 	}
    678 	tof = 0;
    679 
    680 	/* Copy filter output to "lf" logfile */
    681 	if (fp = fopen(tempfile, "r")) {
    682 		while (fgets(buf, sizeof(buf), fp))
    683 			fputs(buf, stderr);
    684 		fclose(fp);
    685 	}
    686 
    687 	if (!WIFEXITED(status)) {
    688 		syslog(LOG_WARNING, "%s: Daemon filter '%c' terminated (%d)",
    689 			printer, format, status.w_termsig);
    690 		return(ERROR);
    691 	}
    692 	switch (status.w_retcode) {
    693 	case 0:
    694 		tof = 1;
    695 		return(OK);
    696 	case 1:
    697 		return(REPRINT);
    698 	default:
    699 		syslog(LOG_WARNING, "%s: Daemon filter '%c' exited (%d)",
    700 			printer, format, status.w_retcode);
    701 	case 2:
    702 		return(ERROR);
    703 	}
    704 }
    705 
    706 /*
    707  * Send the daemon control file (cf) and any data files.
    708  * Return -1 if a non-recoverable error occured, 1 if a recoverable error and
    709  * 0 if all is well.
    710  */
    711 static int
    712 sendit(file)
    713 	char *file;
    714 {
    715 	register int i, err = OK;
    716 	char *cp, last[BUFSIZ];
    717 
    718 	/*
    719 	 * open control file
    720 	 */
    721 	if ((cfp = fopen(file, "r")) == NULL)
    722 		return(OK);
    723 	/*
    724 	 *      read the control file for work to do
    725 	 *
    726 	 *      file format -- first character in the line is a command
    727 	 *      rest of the line is the argument.
    728 	 *      commands of interest are:
    729 	 *
    730 	 *            a-z -- "file name" name of file to print
    731 	 *              U -- "unlink" name of file to remove
    732 	 *                    (after we print it. (Pass 2 only)).
    733 	 */
    734 
    735 	/*
    736 	 * pass 1
    737 	 */
    738 	while (getline(cfp)) {
    739 	again:
    740 		if (line[0] == 'S') {
    741 			cp = line+1;
    742 			i = 0;
    743 			while (*cp >= '0' && *cp <= '9')
    744 				i = i * 10 + (*cp++ - '0');
    745 			fdev = i;
    746 			cp++;
    747 			i = 0;
    748 			while (*cp >= '0' && *cp <= '9')
    749 				i = i * 10 + (*cp++ - '0');
    750 			fino = i;
    751 			continue;
    752 		}
    753 		if (line[0] >= 'a' && line[0] <= 'z') {
    754 			strncpy(last, line, sizeof(last) - 1);
    755 			while (i = getline(cfp))
    756 				if (strcmp(last, line))
    757 					break;
    758 			switch (sendfile('\3', last+1)) {
    759 			case OK:
    760 				if (i)
    761 					goto again;
    762 				break;
    763 			case REPRINT:
    764 				(void)fclose(cfp);
    765 				return(REPRINT);
    766 			case ACCESS:
    767 				sendmail(logname, ACCESS);
    768 			case ERROR:
    769 				err = ERROR;
    770 			}
    771 			break;
    772 		}
    773 	}
    774 	if (err == OK && sendfile('\2', file) > 0) {
    775 		(void)fclose(cfp);
    776 		return(REPRINT);
    777 	}
    778 	/*
    779 	 * pass 2
    780 	 */
    781 	fseek(cfp, 0L, 0);
    782 	while (getline(cfp))
    783 		if (line[0] == 'U')
    784 			(void)unlink(line+1);
    785 	/*
    786 	 * clean-up in case another control file exists
    787 	 */
    788 	(void)fclose(cfp);
    789 	(void)unlink(file);
    790 	return(err);
    791 }
    792 
    793 /*
    794  * Send a data file to the remote machine and spool it.
    795  * Return positive if we should try resending.
    796  */
    797 static int
    798 sendfile(type, file)
    799 	int type;
    800 	char *file;
    801 {
    802 	register int f, i, amt;
    803 	struct stat stb;
    804 	char buf[BUFSIZ];
    805 	int sizerr, resp;
    806 
    807 	if (lstat(file, &stb) < 0 || (f = open(file, O_RDONLY)) < 0)
    808 		return(ERROR);
    809 	/*
    810 	 * Check to see if data file is a symbolic link. If so, it should
    811 	 * still point to the same file or someone is trying to print something
    812 	 * he shouldn't.
    813 	 */
    814 	if ((stb.st_mode & S_IFMT) == S_IFLNK && fstat(f, &stb) == 0 &&
    815 	    (stb.st_dev != fdev || stb.st_ino != fino))
    816 		return(ACCESS);
    817 	amt = snprintf(buf, sizeof(buf), "%c%qd %s\n", type, stb.st_size, file);
    818 	for (i = 0;  ; i++) {
    819 		if (write(pfd, buf, amt) != amt ||
    820 		    (resp = response()) < 0 || resp == '\1') {
    821 			(void)close(f);
    822 			return(REPRINT);
    823 		} else if (resp == '\0')
    824 			break;
    825 		if (i == 0)
    826 			pstatus("no space on remote; waiting for queue to drain");
    827 		if (i == 10)
    828 			syslog(LOG_ALERT, "%s: can't send to %s; queue full",
    829 				printer, RM);
    830 		sleep(5 * 60);
    831 	}
    832 	if (i)
    833 		pstatus("sending to %s", RM);
    834 	sizerr = 0;
    835 	for (i = 0; i < stb.st_size; i += BUFSIZ) {
    836 		amt = BUFSIZ;
    837 		if (i + amt > stb.st_size)
    838 			amt = stb.st_size - i;
    839 		if (sizerr == 0 && read(f, buf, amt) != amt)
    840 			sizerr = 1;
    841 		if (write(pfd, buf, amt) != amt) {
    842 			(void)close(f);
    843 			return(REPRINT);
    844 		}
    845 	}
    846 
    847 
    848 
    849 
    850 	(void)close(f);
    851 	if (sizerr) {
    852 		syslog(LOG_INFO, "%s: %s: changed size", printer, file);
    853 		/* tell recvjob to ignore this file */
    854 		(void)write(pfd, "\1", 1);
    855 		return(ERROR);
    856 	}
    857 	if (write(pfd, "", 1) != 1 || response())
    858 		return(REPRINT);
    859 	return(OK);
    860 }
    861 
    862 /*
    863  * Check to make sure there have been no errors and that both programs
    864  * are in sync with eachother.
    865  * Return non-zero if the connection was lost.
    866  */
    867 static char
    868 response()
    869 {
    870 	char resp;
    871 
    872 	if (read(pfd, &resp, 1) != 1) {
    873 		syslog(LOG_INFO, "%s: lost connection", printer);
    874 		return(-1);
    875 	}
    876 	return(resp);
    877 }
    878 
    879 /*
    880  * Banner printing stuff
    881  */
    882 static void
    883 banner(name1, name2)
    884 	char *name1, *name2;
    885 {
    886 	time_t tvec;
    887 	extern char *ctime();
    888 
    889 	time(&tvec);
    890 	if (!SF && !tof)
    891 		(void)write(ofd, FF, strlen(FF));
    892 	if (SB) {	/* short banner only */
    893 		if (class[0]) {
    894 			(void)write(ofd, class, strlen(class));
    895 			(void)write(ofd, ":", 1);
    896 		}
    897 		(void)write(ofd, name1, strlen(name1));
    898 		(void)write(ofd, "  Job: ", 7);
    899 		(void)write(ofd, name2, strlen(name2));
    900 		(void)write(ofd, "  Date: ", 8);
    901 		(void)write(ofd, ctime(&tvec), 24);
    902 		(void)write(ofd, "\n", 1);
    903 	} else {	/* normal banner */
    904 		(void)write(ofd, "\n\n\n", 3);
    905 		scan_out(ofd, name1, '\0');
    906 		(void)write(ofd, "\n\n", 2);
    907 		scan_out(ofd, name2, '\0');
    908 		if (class[0]) {
    909 			(void)write(ofd,"\n\n\n",3);
    910 			scan_out(ofd, class, '\0');
    911 		}
    912 		(void)write(ofd, "\n\n\n\n\t\t\t\t\tJob:  ", 15);
    913 		(void)write(ofd, name2, strlen(name2));
    914 		(void)write(ofd, "\n\t\t\t\t\tDate: ", 12);
    915 		(void)write(ofd, ctime(&tvec), 24);
    916 		(void)write(ofd, "\n", 1);
    917 	}
    918 	if (!SF)
    919 		(void)write(ofd, FF, strlen(FF));
    920 	tof = 1;
    921 }
    922 
    923 static char *
    924 scnline(key, p, c)
    925 	register int key;
    926 	register char *p;
    927 	int c;
    928 {
    929 	register scnwidth;
    930 
    931 	for (scnwidth = WIDTH; --scnwidth;) {
    932 		key <<= 1;
    933 		*p++ = key & 0200 ? c : BACKGND;
    934 	}
    935 	return (p);
    936 }
    937 
    938 #define TRC(q)	(((q)-' ')&0177)
    939 
    940 static void
    941 scan_out(scfd, scsp, dlm)
    942 	int scfd, dlm;
    943 	char *scsp;
    944 {
    945 	register char *strp;
    946 	register nchrs, j;
    947 	char outbuf[LINELEN+1], *sp, c, cc;
    948 	int d, scnhgt;
    949 	extern char scnkey[][HEIGHT];	/* in lpdchar.c */
    950 
    951 	for (scnhgt = 0; scnhgt++ < HEIGHT+DROP; ) {
    952 		strp = &outbuf[0];
    953 		sp = scsp;
    954 		for (nchrs = 0; ; ) {
    955 			d = dropit(c = TRC(cc = *sp++));
    956 			if ((!d && scnhgt > HEIGHT) || (scnhgt <= DROP && d))
    957 				for (j = WIDTH; --j;)
    958 					*strp++ = BACKGND;
    959 			else
    960 				strp = scnline(scnkey[c][scnhgt-1-d], strp, cc);
    961 			if (*sp == dlm || *sp == '\0' || nchrs++ >= PW/(WIDTH+1)-1)
    962 				break;
    963 			*strp++ = BACKGND;
    964 			*strp++ = BACKGND;
    965 		}
    966 		while (*--strp == BACKGND && strp >= outbuf)
    967 			;
    968 		strp++;
    969 		*strp++ = '\n';
    970 		(void)write(scfd, outbuf, strp-outbuf);
    971 	}
    972 }
    973 
    974 static int
    975 dropit(c)
    976 	int c;
    977 {
    978 	switch(c) {
    979 
    980 	case TRC('_'):
    981 	case TRC(';'):
    982 	case TRC(','):
    983 	case TRC('g'):
    984 	case TRC('j'):
    985 	case TRC('p'):
    986 	case TRC('q'):
    987 	case TRC('y'):
    988 		return (DROP);
    989 
    990 	default:
    991 		return (0);
    992 	}
    993 }
    994 
    995 /*
    996  * sendmail ---
    997  *   tell people about job completion
    998  */
    999 static void
   1000 sendmail(user, bombed)
   1001 	char *user;
   1002 	int bombed;
   1003 {
   1004 	register int i;
   1005 	int p[2], s;
   1006 	register char *cp;
   1007 	char buf[100];
   1008 	struct stat stb;
   1009 	FILE *fp;
   1010 
   1011 	pipe(p);
   1012 	if ((s = dofork(DORETURN)) == 0) {		/* child */
   1013 		dup2(p[0], 0);
   1014 		for (i = 3; i < NOFILE; i++)
   1015 			(void)close(i);
   1016 		if ((cp = rindex(_PATH_SENDMAIL, '/')) != NULL)
   1017 			cp++;
   1018 	else
   1019 			cp = _PATH_SENDMAIL;
   1020 		(void)snprintf(buf, sizeof(buf), "%s@%s", user, fromhost);
   1021 		execl(_PATH_SENDMAIL, cp, buf, 0);
   1022 		exit(0);
   1023 	} else if (s > 0) {				/* parent */
   1024 		dup2(p[1], 1);
   1025 		printf("To: %s@%s\n", user, fromhost);
   1026 		printf("Subject: printer job\n\n");
   1027 		printf("Your printer job ");
   1028 		if (*jobname)
   1029 			printf("(%s) ", jobname);
   1030 		switch (bombed) {
   1031 		case OK:
   1032 			printf("\ncompleted successfully\n");
   1033 			break;
   1034 		default:
   1035 		case FATALERR:
   1036 			printf("\ncould not be printed\n");
   1037 			break;
   1038 		case NOACCT:
   1039 			printf("\ncould not be printed without an account on %s\n", host);
   1040 			break;
   1041 		case FILTERERR:
   1042 			if (stat(tempfile, &stb) < 0 || stb.st_size == 0 ||
   1043 			    (fp = fopen(tempfile, "r")) == NULL) {
   1044 				printf("\nwas printed but had some errors\n");
   1045 				break;
   1046 			}
   1047 			printf("\nwas printed but had the following errors:\n");
   1048 			while ((i = getc(fp)) != EOF)
   1049 				putchar(i);
   1050 			(void)fclose(fp);
   1051 			break;
   1052 		case ACCESS:
   1053 			printf("\nwas not printed because it was not linked to the original file\n");
   1054 		}
   1055 		fflush(stdout);
   1056 		(void)close(1);
   1057 	}
   1058 	(void)close(p[0]);
   1059 	(void)close(p[1]);
   1060 	wait(&s);
   1061 }
   1062 
   1063 /*
   1064  * dofork - fork with retries on failure
   1065  */
   1066 static int
   1067 dofork(action)
   1068 	int action;
   1069 {
   1070 	register int i, pid;
   1071 	struct passwd *pw;
   1072 
   1073 	for (i = 0; i < 20; i++) {
   1074 		if ((pid = fork()) < 0) {
   1075 			sleep((unsigned)(i*i));
   1076 			continue;
   1077 		}
   1078 		/*
   1079 		 * Child should run as daemon instead of root
   1080 		 */
   1081 		if (pid == 0) {
   1082 			pw = getpwuid(DU);
   1083 			if (pw == 0) {
   1084 				syslog(LOG_ERR, "uid %d not in password file",
   1085 				    DU);
   1086 				break;
   1087 			}
   1088 			initgroups(pw->pw_name, pw->pw_gid);
   1089 			setgid(pw->pw_gid);
   1090 			setuid(DU);
   1091 		}
   1092 		return (pid);
   1093 	}
   1094 	syslog(LOG_ERR, "can't fork");
   1095 
   1096 	switch (action) {
   1097 	case DORETURN:
   1098 		return (-1);
   1099 	default:
   1100 		syslog(LOG_ERR, "bad action (%d) to dofork", action);
   1101 		/*FALL THRU*/
   1102 	case DOABORT:
   1103 		exit(1);
   1104 	}
   1105 	/*NOTREACHED*/
   1106 }
   1107 
   1108 /*
   1109  * Kill child processes to abort current job.
   1110  */
   1111 static void
   1112 abortpr(signo)
   1113 	int signo;
   1114 {
   1115 	(void)unlink(tempfile);
   1116 	kill(0, SIGINT);
   1117 	if (ofilter > 0)
   1118 		kill(ofilter, SIGCONT);
   1119 	while (wait(NULL) > 0)
   1120 		;
   1121 	exit(0);
   1122 }
   1123 
   1124 static void
   1125 init()
   1126 {
   1127 	int status;
   1128 	char *s;
   1129 
   1130 	if ((status = cgetent(&bp, printcapdb, printer)) == -2) {
   1131 		syslog(LOG_ERR, "can't open printer description file");
   1132 		exit(1);
   1133 	} else if (status == -1) {
   1134 		syslog(LOG_ERR, "unknown printer: %s", printer);
   1135 		exit(1);
   1136 	} else if (status == -3)
   1137 		fatal("potential reference loop detected in printcap file");
   1138 
   1139 	if (cgetstr(bp, "lp", &LP) == -1)
   1140 		LP = _PATH_DEFDEVLP;
   1141 	if (cgetstr(bp, "rp", &RP) == -1)
   1142 		RP = DEFLP;
   1143 	if (cgetstr(bp, "lo", &LO) == -1)
   1144 		LO = DEFLOCK;
   1145 	if (cgetstr(bp, "st", &ST) == -1)
   1146 		ST = DEFSTAT;
   1147 	if (cgetstr(bp, "lf", &LF) == -1)
   1148 		LF = _PATH_CONSOLE;
   1149 	if (cgetstr(bp, "sd", &SD) == -1)
   1150 		SD = _PATH_DEFSPOOL;
   1151 	if (cgetnum(bp, "du", &DU) < 0)
   1152 		DU = DEFUID;
   1153 	if (cgetstr(bp,"ff", &FF) == -1)
   1154 		FF = DEFFF;
   1155 	if (cgetnum(bp, "pw", &PW) < 0)
   1156 		PW = DEFWIDTH;
   1157 	(void)snprintf(&width[2], sizeof(width) - 2, "%d", PW);
   1158 	if (cgetnum(bp, "pl", &PL) < 0)
   1159 		PL = DEFLENGTH;
   1160 	(void)snprintf(&length[2], sizeof(length) - 2, "%d", PL);
   1161 	if (cgetnum(bp,"px", &PX) < 0)
   1162 		PX = 0;
   1163 	(void)snprintf(&pxwidth[2], sizeof(pxwidth) - 2, "%d", PX);
   1164 	if (cgetnum(bp, "py", &PY) < 0)
   1165 		PY = 0;
   1166 	(void)snprintf(&pxlength[2], sizeof(pxlength) - 2, "%d", PY);
   1167 	cgetstr(bp, "rm", &RM);
   1168 	if (s = checkremote())
   1169 		syslog(LOG_WARNING, s);
   1170 
   1171 	cgetstr(bp, "af", &AF);
   1172 	cgetstr(bp, "of", &OF);
   1173 	cgetstr(bp, "if", &IF);
   1174 	cgetstr(bp, "rf", &RF);
   1175 	cgetstr(bp, "tf", &TF);
   1176 	cgetstr(bp, "nf", &NF);
   1177 	cgetstr(bp, "df", &DF);
   1178 	cgetstr(bp, "gf", &GF);
   1179 	cgetstr(bp, "vf", &VF);
   1180 	cgetstr(bp, "cf", &CF);
   1181 	cgetstr(bp, "tr", &TR);
   1182 
   1183 	RS = (cgetcap(bp, "rs", ':') != NULL);
   1184 	SF = (cgetcap(bp, "sf", ':') != NULL);
   1185 	SH = (cgetcap(bp, "sh", ':') != NULL);
   1186 	SB = (cgetcap(bp, "sb", ':') != NULL);
   1187 	HL = (cgetcap(bp, "hl", ':') != NULL);
   1188 	RW = (cgetcap(bp, "rw", ':') != NULL);
   1189 
   1190 	cgetnum(bp, "br", &BR);
   1191 	if (cgetnum(bp, "fc", &FC) < 0)
   1192 		FC = 0;
   1193 	if (cgetnum(bp, "fs", &FS) < 0)
   1194 		FS = 0;
   1195 	if (cgetnum(bp, "xc", &XC) < 0)
   1196 		XC = 0;
   1197 	if (cgetnum(bp, "xs", &XS) < 0)
   1198 		XS = 0;
   1199 	cgetstr(bp, "ms", &MS);
   1200 
   1201 	tof = (cgetcap(bp, "fo", ':') == NULL);
   1202 }
   1203 
   1204 /*
   1205  * Acquire line printer or remote connection.
   1206  */
   1207 static void
   1208 openpr()
   1209 {
   1210 	register int i, n;
   1211 	int resp;
   1212 
   1213 	if (!sendtorem && *LP) {
   1214 		for (i = 1; ; i = i < 32 ? i << 1 : i) {
   1215 			pfd = open(LP, RW ? O_RDWR : O_WRONLY);
   1216 			if (pfd >= 0)
   1217 				break;
   1218 			if (errno == ENOENT) {
   1219 				syslog(LOG_ERR, "%s: %m", LP);
   1220 				exit(1);
   1221 			}
   1222 			if (i == 1)
   1223 				pstatus("waiting for %s to become ready (offline ?)", printer);
   1224 			sleep(i);
   1225 		}
   1226 		if (isatty(pfd))
   1227 			setty();
   1228 		pstatus("%s is ready and printing", printer);
   1229 	} else if (RM != NULL) {
   1230 		for (i = 1; ; i = i < 256 ? i << 1 : i) {
   1231 			resp = -1;
   1232 			pfd = getport(RM);
   1233 			if (pfd >= 0) {
   1234 				n = snprintf(line, sizeof(line), "\2%s\n", RP);
   1235 				if (write(pfd, line, n) == n &&
   1236 				    (resp = response()) == '\0')
   1237 					break;
   1238 				(void)close(pfd);
   1239 			}
   1240 			if (i == 1) {
   1241 				if (resp < 0)
   1242 					pstatus("waiting for %s to come up", RM);
   1243 				else {
   1244 					pstatus("waiting for queue to be enabled on %s", RM);
   1245 					i = 256;
   1246 				}
   1247 			}
   1248 			sleep(i);
   1249 		}
   1250 		pstatus("sending to %s", RM);
   1251 		remote = 1;
   1252 	} else {
   1253 		syslog(LOG_ERR, "%s: no line printer device or host name",
   1254 			printer);
   1255 		exit(1);
   1256 	}
   1257 	/*
   1258 	 * Start up an output filter, if needed.
   1259 	 */
   1260 	if (!remote && OF) {
   1261 		int p[2];
   1262 		char *cp;
   1263 
   1264 		pipe(p);
   1265 		if ((ofilter = dofork(DOABORT)) == 0) {	/* child */
   1266 			dup2(p[0], 0);		/* pipe is std in */
   1267 			dup2(pfd, 1);		/* printer is std out */
   1268 			for (i = 3; i < NOFILE; i++)
   1269 				(void)close(i);
   1270 			if ((cp = rindex(OF, '/')) == NULL)
   1271 				cp = OF;
   1272 			else
   1273 				cp++;
   1274 			execl(OF, cp, width, length, 0);
   1275 			syslog(LOG_ERR, "%s: %s: %m", printer, OF);
   1276 			exit(1);
   1277 		}
   1278 		(void)close(p[0]);		/* close input side */
   1279 		ofd = p[1];			/* use pipe for output */
   1280 	} else {
   1281 		ofd = pfd;
   1282 		ofilter = 0;
   1283 	}
   1284 }
   1285 
   1286 #if !defined(__NetBSD__)
   1287 struct bauds {
   1288 	int	baud;
   1289 	int	speed;
   1290 } bauds[] = {
   1291 	50,	B50,
   1292 	75,	B75,
   1293 	110,	B110,
   1294 	134,	B134,
   1295 	150,	B150,
   1296 	200,	B200,
   1297 	300,	B300,
   1298 	600,	B600,
   1299 	1200,	B1200,
   1300 	1800,	B1800,
   1301 	2400,	B2400,
   1302 	4800,	B4800,
   1303 	9600,	B9600,
   1304 	19200,	B19200,
   1305 	38400,	B38400,
   1306 	0,	0
   1307 };
   1308 #endif
   1309 
   1310 /*
   1311  * setup tty lines.
   1312  */
   1313 static void
   1314 setty()
   1315 {
   1316 	struct info i;
   1317 	char **argv, **ap, *p, *val;
   1318 
   1319 	i.fd = pfd;
   1320 	i.set = i.wset = 0;
   1321 	if (ioctl(i.fd, TIOCEXCL, (char *)0) < 0) {
   1322 		syslog(LOG_ERR, "%s: ioctl(TIOCEXCL): %m", printer);
   1323 		exit(1);
   1324 	}
   1325 	if (tcgetattr(i.fd, &i.t) < 0) {
   1326 		syslog(LOG_ERR, "%s: tcgetattr: %m", printer);
   1327 		exit(1);
   1328 	}
   1329 	if (BR > 0) {
   1330 #if !defined(__NetBSD__)
   1331 		register struct bauds *bp;
   1332 		for (bp = bauds; bp->baud; bp++)
   1333 			if (BR == bp->baud)
   1334 				break;
   1335 		if (!bp->baud) {
   1336 			syslog(LOG_ERR, "%s: illegal baud rate %d", printer, BR);
   1337 			exit(1);
   1338 		}
   1339 		cfsetspeed(&i.t, bp->speed);
   1340 #else
   1341 		cfsetspeed(&i.t, BR);
   1342 #endif
   1343 		i.set = 1;
   1344 	}
   1345 	if (MS) {
   1346 		if (ioctl(i.fd, TIOCGETD, &i.ldisc) < 0) {
   1347 			syslog(LOG_ERR, "%s: ioctl(TIOCGETD): %m", printer);
   1348 			exit(1);
   1349 		}
   1350 		if (ioctl(i.fd, TIOCGWINSZ, &i.win) < 0)
   1351 			syslog(LOG_INFO, "%s: ioctl(TIOCGWINSZ): %m",
   1352 			       printer);
   1353 
   1354 		argv = (char **)calloc(256, sizeof(char *));
   1355 		if (argv == NULL) {
   1356 			syslog(LOG_ERR, "%s: calloc: %m", printer);
   1357 			exit(1);
   1358 		}
   1359 		p = strdup(MS);
   1360 		ap = argv;
   1361 		while ((val = strsep(&p, " \t,")) != NULL) {
   1362 			*ap++ = strdup(val);
   1363 		}
   1364 
   1365 		for (; *argv; ++argv) {
   1366 			if (ksearch(&argv, &i))
   1367 				continue;
   1368 			if (msearch(&argv, &i))
   1369 				continue;
   1370 			syslog(LOG_INFO, "%s: unknown stty flag: %s",
   1371 			       printer, *argv);
   1372 		}
   1373 	} else {
   1374 		if (FC) {
   1375 			sttyclearflags(&i.t, FC);
   1376 			i.set = 1;
   1377 		}
   1378 		if (FS) {
   1379 			sttysetflags(&i.t, FS);
   1380 			i.set = 1;
   1381 		}
   1382 		if (XC) {
   1383 			sttyclearlflags(&i.t, XC);
   1384 			i.set = 1;
   1385 		}
   1386 		if (XS) {
   1387 			sttysetlflags(&i.t, XS);
   1388 			i.set = 1;
   1389 		}
   1390 	}
   1391 
   1392 	if (i.set && tcsetattr(i.fd, TCSANOW, &i.t) < 0) {
   1393 		syslog(LOG_ERR, "%s: tcsetattr: %m", printer);
   1394 		exit(1);
   1395 	}
   1396 	if (i.wset && ioctl(i.fd, TIOCSWINSZ, &i.win) < 0)
   1397 		syslog(LOG_INFO, "%s: ioctl(TIOCSWINSZ): %m", printer);
   1398 	return;
   1399 }
   1400 
   1401 #if __STDC__
   1402 #include <stdarg.h>
   1403 #else
   1404 #include <varargs.h>
   1405 #endif
   1406 
   1407 void
   1408 #if __STDC__
   1409 pstatus(const char *msg, ...)
   1410 #else
   1411 pstatus(msg, va_alist)
   1412 	char *msg;
   1413         va_dcl
   1414 #endif
   1415 {
   1416 	register int fd;
   1417 	char buf[BUFSIZ];
   1418 	va_list ap;
   1419 #if __STDC__
   1420 	va_start(ap, msg);
   1421 #else
   1422 	va_start(ap);
   1423 #endif
   1424 
   1425 	umask(0);
   1426 	fd = open(ST, O_WRONLY|O_CREAT, 0664);
   1427 	if (fd < 0 || flock(fd, LOCK_EX) < 0) {
   1428 		syslog(LOG_ERR, "%s: %s: %m", printer, ST);
   1429 		exit(1);
   1430 	}
   1431 	ftruncate(fd, 0);
   1432 	(void)vsnprintf(buf, sizeof(buf) - 2, msg, ap);
   1433 	va_end(ap);
   1434 	strncat(buf, "\n", 2);
   1435 	(void)write(fd, buf, strlen(buf));
   1436 	(void)close(fd);
   1437 }
   1438