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