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