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