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