printjob.c revision 24831
11553Srgrimes/*
21553Srgrimes * Copyright (c) 1983, 1993
31553Srgrimes *	The Regents of the University of California.  All rights reserved.
41553Srgrimes *
51553Srgrimes *
61553Srgrimes * Redistribution and use in source and binary forms, with or without
71553Srgrimes * modification, are permitted provided that the following conditions
81553Srgrimes * are met:
91553Srgrimes * 1. Redistributions of source code must retain the above copyright
101553Srgrimes *    notice, this list of conditions and the following disclaimer.
111553Srgrimes * 2. Redistributions in binary form must reproduce the above copyright
121553Srgrimes *    notice, this list of conditions and the following disclaimer in the
131553Srgrimes *    documentation and/or other materials provided with the distribution.
141553Srgrimes * 3. All advertising materials mentioning features or use of this software
151553Srgrimes *    must display the following acknowledgement:
161553Srgrimes *	This product includes software developed by the University of
171553Srgrimes *	California, Berkeley and its contributors.
181553Srgrimes * 4. Neither the name of the University nor the names of its contributors
191553Srgrimes *    may be used to endorse or promote products derived from this software
201553Srgrimes *    without specific prior written permission.
211553Srgrimes *
221553Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
231553Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
241553Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
251553Srgrimes * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
261553Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
271553Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
281553Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
291553Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
301553Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
311553Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
321553Srgrimes * SUCH DAMAGE.
331553Srgrimes */
341553Srgrimes
351553Srgrimes#ifndef lint
361553Srgrimesstatic char copyright[] =
371553Srgrimes"@(#) Copyright (c) 1983, 1993\n\
381553Srgrimes	The Regents of the University of California.  All rights reserved.\n";
391553Srgrimes#endif /* not lint */
401553Srgrimes
411553Srgrimes#ifndef lint
4215648Sjoergstatic char sccsid[] = "@(#)printjob.c	8.7 (Berkeley) 5/10/95";
431553Srgrimes#endif /* not lint */
441553Srgrimes
451553Srgrimes
461553Srgrimes/*
471553Srgrimes * printjob -- print jobs in the queue.
481553Srgrimes *
491553Srgrimes *	NOTE: the lock file is used to pass information to lpq and lprm.
501553Srgrimes *	it does not need to be removed because file locks are dynamic.
511553Srgrimes */
521553Srgrimes
531553Srgrimes#include <sys/param.h>
541553Srgrimes#include <sys/wait.h>
551553Srgrimes#include <sys/stat.h>
561553Srgrimes#include <sys/types.h>
571553Srgrimes
581553Srgrimes#include <pwd.h>
591553Srgrimes#include <unistd.h>
601553Srgrimes#include <signal.h>
611553Srgrimes#include <syslog.h>
621553Srgrimes#include <fcntl.h>
631553Srgrimes#include <dirent.h>
641553Srgrimes#include <errno.h>
651553Srgrimes#include <stdio.h>
661553Srgrimes#include <string.h>
671553Srgrimes#include <stdlib.h>
6815032Ssef#include <sys/ioctl.h>
6915032Ssef#include <termios.h>
7015703Sjoerg#include <time.h>
711553Srgrimes#include "lp.h"
721553Srgrimes#include "lp.local.h"
731553Srgrimes#include "pathnames.h"
741553Srgrimes#include "extern.h"
751553Srgrimes
761553Srgrimes#define DORETURN	0	/* absorb fork error */
771553Srgrimes#define DOABORT		1	/* abort if dofork fails */
781553Srgrimes
791553Srgrimes/*
801553Srgrimes * Error tokens
811553Srgrimes */
821553Srgrimes#define REPRINT		-2
831553Srgrimes#define ERROR		-1
841553Srgrimes#define	OK		0
851553Srgrimes#define	FATALERR	1
861553Srgrimes#define	NOACCT		2
871553Srgrimes#define	FILTERERR	3
881553Srgrimes#define	ACCESS		4
891553Srgrimes
901553Srgrimesstatic dev_t	 fdev;		/* device of file pointed to by symlink */
911553Srgrimesstatic ino_t	 fino;		/* inode of file pointed to by symlink */
921553Srgrimesstatic FILE	*cfp;		/* control file */
931553Srgrimesstatic int	 child;		/* id of any filters */
941553Srgrimesstatic int	 lfd;		/* lock file descriptor */
951553Srgrimesstatic int	 ofd;		/* output filter file descriptor */
961553Srgrimesstatic int	 ofilter;	/* id of output filter, if any */
9724831Sbrianstatic int	 tfd = -1;	/* output filter temp file output */
981553Srgrimesstatic int	 pfd;		/* prstatic inter file descriptor */
991553Srgrimesstatic int	 pid;		/* pid of lpd process */
1001553Srgrimesstatic int	 prchild;	/* id of pr process */
1011553Srgrimesstatic char	 title[80];	/* ``pr'' title */
1021553Srgrimesstatic int	 tof;		/* true if at top of form */
1031553Srgrimes
1041553Srgrimesstatic char	class[32];		/* classification field */
1051553Srgrimesstatic char	fromhost[32];		/* user's host machine */
1061553Srgrimes				/* indentation size in static characters */
1078857Srgrimesstatic char	indent[10] = "-i0";
1081553Srgrimesstatic char	jobname[100];		/* job or file name */
1091553Srgrimesstatic char	length[10] = "-l";	/* page length in lines */
1101553Srgrimesstatic char	logname[32];		/* user's login name */
1111553Srgrimesstatic char	pxlength[10] = "-y";	/* page length in pixels */
1121553Srgrimesstatic char	pxwidth[10] = "-x";	/* page width in pixels */
11324831Sbrianstatic char	tempfile[] = "errsXXXXXX"; /* file name for filter errors */
1141553Srgrimesstatic char	width[10] = "-w";	/* page width in static characters */
11524831Sbrian#define TFILENAME "fltXXXXXX"
11624831Sbrianstatic char	tfile[] = TFILENAME;	/* file name for filter output */
1171553Srgrimes
1181553Srgrimesstatic void       abortpr __P((int));
1191553Srgrimesstatic void       banner __P((char *, char *));
1201553Srgrimesstatic int        dofork __P((int));
1211553Srgrimesstatic int        dropit __P((int));
1221553Srgrimesstatic void       init __P((void));
1231553Srgrimesstatic void       openpr __P((void));
12415648Sjoergstatic void       opennet __P((char *));
12515648Sjoergstatic void       opentty __P((void));
12615648Sjoergstatic void       openrem __P((void));
1271553Srgrimesstatic int        print __P((int, char *));
1281553Srgrimesstatic int        printit __P((char *));
1291553Srgrimesstatic void       pstatus __P((const char *, ...));
1301553Srgrimesstatic char       response __P((void));
1311553Srgrimesstatic void       scan_out __P((int, char *, int));
1321553Srgrimesstatic char      *scnline __P((int, char *, int));
13324831Sbrianstatic int        sendfile __P((int, char *, char));
1341553Srgrimesstatic int        sendit __P((char *));
1351553Srgrimesstatic void       sendmail __P((char *, int));
1361553Srgrimesstatic void       setty __P((void));
1371553Srgrimes
1381553Srgrimesvoid
1391553Srgrimesprintjob()
1401553Srgrimes{
1411553Srgrimes	struct stat stb;
1421553Srgrimes	register struct queue *q, **qp;
1431553Srgrimes	struct queue **queue;
1441553Srgrimes	register int i, nitems;
14515648Sjoerg	off_t pidoff;
14615648Sjoerg	int errcnt, count = 0;
1471553Srgrimes
1481553Srgrimes	init();					/* set up capabilities */
1491553Srgrimes	(void) write(1, "", 1);			/* ack that daemon is started */
1501553Srgrimes	(void) close(2);			/* set up log file */
1511553Srgrimes	if (open(LF, O_WRONLY|O_APPEND, 0664) < 0) {
1521553Srgrimes		syslog(LOG_ERR, "%s: %m", LF);
1531553Srgrimes		(void) open(_PATH_DEVNULL, O_WRONLY);
1541553Srgrimes	}
1551553Srgrimes	setgid(getegid());
1561553Srgrimes	pid = getpid();				/* for use with lprm */
1571553Srgrimes	setpgrp(0, pid);
1581553Srgrimes	signal(SIGHUP, abortpr);
1591553Srgrimes	signal(SIGINT, abortpr);
1601553Srgrimes	signal(SIGQUIT, abortpr);
1611553Srgrimes	signal(SIGTERM, abortpr);
1621553Srgrimes
1631553Srgrimes	(void) mktemp(tempfile);
1641553Srgrimes
1651553Srgrimes	/*
1661553Srgrimes	 * uses short form file names
1671553Srgrimes	 */
1681553Srgrimes	if (chdir(SD) < 0) {
1691553Srgrimes		syslog(LOG_ERR, "%s: %m", SD);
1701553Srgrimes		exit(1);
1711553Srgrimes	}
1721553Srgrimes	if (stat(LO, &stb) == 0 && (stb.st_mode & 0100))
1731553Srgrimes		exit(0);		/* printing disabled */
1741553Srgrimes	lfd = open(LO, O_WRONLY|O_CREAT, 0644);
1751553Srgrimes	if (lfd < 0) {
1761553Srgrimes		syslog(LOG_ERR, "%s: %s: %m", printer, LO);
1771553Srgrimes		exit(1);
1781553Srgrimes	}
1791553Srgrimes	if (flock(lfd, LOCK_EX|LOCK_NB) < 0) {
1801553Srgrimes		if (errno == EWOULDBLOCK)	/* active deamon present */
1811553Srgrimes			exit(0);
1821553Srgrimes		syslog(LOG_ERR, "%s: %s: %m", printer, LO);
1831553Srgrimes		exit(1);
1841553Srgrimes	}
1851553Srgrimes	ftruncate(lfd, 0);
1861553Srgrimes	/*
1871553Srgrimes	 * write process id for others to know
1881553Srgrimes	 */
1891553Srgrimes	sprintf(line, "%u\n", pid);
1901553Srgrimes	pidoff = i = strlen(line);
1911553Srgrimes	if (write(lfd, line, i) != i) {
1921553Srgrimes		syslog(LOG_ERR, "%s: %s: %m", printer, LO);
1931553Srgrimes		exit(1);
1941553Srgrimes	}
1951553Srgrimes	/*
1961553Srgrimes	 * search the spool directory for work and sort by queue order.
1971553Srgrimes	 */
1981553Srgrimes	if ((nitems = getq(&queue)) < 0) {
1991553Srgrimes		syslog(LOG_ERR, "%s: can't scan %s", printer, SD);
2001553Srgrimes		exit(1);
2011553Srgrimes	}
2021553Srgrimes	if (nitems == 0)		/* no work to do */
2031553Srgrimes		exit(0);
2041553Srgrimes	if (stb.st_mode & 01) {		/* reset queue flag */
2051553Srgrimes		if (fchmod(lfd, stb.st_mode & 0776) < 0)
2061553Srgrimes			syslog(LOG_ERR, "%s: %s: %m", printer, LO);
2071553Srgrimes	}
2081553Srgrimes	openpr();			/* open printer or remote */
2091553Srgrimesagain:
2101553Srgrimes	/*
2111553Srgrimes	 * we found something to do now do it --
2121553Srgrimes	 *    write the name of the current control file into the lock file
2131553Srgrimes	 *    so the spool queue program can tell what we're working on
2141553Srgrimes	 */
2151553Srgrimes	for (qp = queue; nitems--; free((char *) q)) {
2161553Srgrimes		q = *qp++;
2171553Srgrimes		if (stat(q->q_name, &stb) < 0)
2181553Srgrimes			continue;
21915648Sjoerg		errcnt = 0;
2201553Srgrimes	restart:
22115648Sjoerg		(void) lseek(lfd, pidoff, 0);
2221553Srgrimes		(void) sprintf(line, "%s\n", q->q_name);
2231553Srgrimes		i = strlen(line);
2241553Srgrimes		if (write(lfd, line, i) != i)
2251553Srgrimes			syslog(LOG_ERR, "%s: %s: %m", printer, LO);
2261553Srgrimes		if (!remote)
2271553Srgrimes			i = printit(q->q_name);
2281553Srgrimes		else
2291553Srgrimes			i = sendit(q->q_name);
2301553Srgrimes		/*
2311553Srgrimes		 * Check to see if we are supposed to stop printing or
2321553Srgrimes		 * if we are to rebuild the queue.
2331553Srgrimes		 */
2341553Srgrimes		if (fstat(lfd, &stb) == 0) {
2351553Srgrimes			/* stop printing before starting next job? */
2361553Srgrimes			if (stb.st_mode & 0100)
2371553Srgrimes				goto done;
2381553Srgrimes			/* rebuild queue (after lpc topq) */
2391553Srgrimes			if (stb.st_mode & 01) {
2401553Srgrimes				for (free((char *) q); nitems--; free((char *) q))
2411553Srgrimes					q = *qp++;
2421553Srgrimes				if (fchmod(lfd, stb.st_mode & 0776) < 0)
2431553Srgrimes					syslog(LOG_WARNING, "%s: %s: %m",
2441553Srgrimes						printer, LO);
2451553Srgrimes				break;
2461553Srgrimes			}
2471553Srgrimes		}
2481553Srgrimes		if (i == OK)		/* file ok and printed */
2491553Srgrimes			count++;
25015648Sjoerg		else if (i == REPRINT && ++errcnt < 5) {
25115648Sjoerg			/* try reprinting the job */
2521553Srgrimes			syslog(LOG_INFO, "restarting %s", printer);
2531553Srgrimes			if (ofilter > 0) {
2541553Srgrimes				kill(ofilter, SIGCONT);	/* to be sure */
2551553Srgrimes				(void) close(ofd);
25615648Sjoerg				while ((i = wait(NULL)) > 0 && i != ofilter)
2571553Srgrimes					;
2581553Srgrimes				ofilter = 0;
2591553Srgrimes			}
2601553Srgrimes			(void) close(pfd);	/* close printer */
2611553Srgrimes			if (ftruncate(lfd, pidoff) < 0)
2621553Srgrimes				syslog(LOG_WARNING, "%s: %s: %m", printer, LO);
2631553Srgrimes			openpr();		/* try to reopen printer */
2641553Srgrimes			goto restart;
26515648Sjoerg		} else {
26615648Sjoerg			syslog(LOG_WARNING, "%s: job could not be %s (%s)", printer,
26715648Sjoerg				remote ? "sent to remote host" : "printed", q->q_name);
26815648Sjoerg			if (i == REPRINT) {
26915648Sjoerg				/* insure we don't attempt this job again */
27015648Sjoerg				(void) unlink(q->q_name);
27115648Sjoerg				q->q_name[0] = 'd';
27215648Sjoerg				(void) unlink(q->q_name);
27315648Sjoerg				if (logname[0])
27415648Sjoerg					sendmail(logname, FATALERR);
27515648Sjoerg			}
2761553Srgrimes		}
2771553Srgrimes	}
2781553Srgrimes	free((char *) queue);
2791553Srgrimes	/*
2801553Srgrimes	 * search the spool directory for more work.
2811553Srgrimes	 */
2821553Srgrimes	if ((nitems = getq(&queue)) < 0) {
2831553Srgrimes		syslog(LOG_ERR, "%s: can't scan %s", printer, SD);
2841553Srgrimes		exit(1);
2851553Srgrimes	}
2861553Srgrimes	if (nitems == 0) {		/* no more work to do */
2871553Srgrimes	done:
2881553Srgrimes		if (count > 0) {	/* Files actually printed */
2891553Srgrimes			if (!SF && !tof)
2901553Srgrimes				(void) write(ofd, FF, strlen(FF));
2911553Srgrimes			if (TR != NULL)		/* output trailer */
2921553Srgrimes				(void) write(ofd, TR, strlen(TR));
2931553Srgrimes		}
29419202Simp		(void) close(ofd);
29519202Simp		(void) wait(NULL);
2961553Srgrimes		(void) unlink(tempfile);
2971553Srgrimes		exit(0);
2981553Srgrimes	}
2991553Srgrimes	goto again;
3001553Srgrimes}
3011553Srgrimes
3021553Srgrimeschar	fonts[4][50];	/* fonts for troff */
3031553Srgrimes
3041553Srgrimeschar ifonts[4][40] = {
3051553Srgrimes	_PATH_VFONTR,
3061553Srgrimes	_PATH_VFONTI,
3071553Srgrimes	_PATH_VFONTB,
3081553Srgrimes	_PATH_VFONTS,
3091553Srgrimes};
3101553Srgrimes
3111553Srgrimes/*
3121553Srgrimes * The remaining part is the reading of the control file (cf)
3131553Srgrimes * and performing the various actions.
3141553Srgrimes */
3151553Srgrimesstatic int
3161553Srgrimesprintit(file)
3171553Srgrimes	char *file;
3181553Srgrimes{
3191553Srgrimes	register int i;
3201553Srgrimes	char *cp;
3211553Srgrimes	int bombed = OK;
3221553Srgrimes
3231553Srgrimes	/*
3241553Srgrimes	 * open control file; ignore if no longer there.
3251553Srgrimes	 */
3261553Srgrimes	if ((cfp = fopen(file, "r")) == NULL) {
3271553Srgrimes		syslog(LOG_INFO, "%s: %s: %m", printer, file);
3281553Srgrimes		return(OK);
3291553Srgrimes	}
3301553Srgrimes	/*
3311553Srgrimes	 * Reset troff fonts.
3321553Srgrimes	 */
3331553Srgrimes	for (i = 0; i < 4; i++)
3341553Srgrimes		strcpy(fonts[i], ifonts[i]);
3351553Srgrimes	sprintf(&width[2], "%d", PW);
3361553Srgrimes	strcpy(indent+2, "0");
3371553Srgrimes
3381553Srgrimes	/*
3391553Srgrimes	 *      read the control file for work to do
3401553Srgrimes	 *
3411553Srgrimes	 *      file format -- first character in the line is a command
3421553Srgrimes	 *      rest of the line is the argument.
3431553Srgrimes	 *      valid commands are:
3441553Srgrimes	 *
3451553Srgrimes	 *		S -- "stat info" for symbolic link protection
3461553Srgrimes	 *		J -- "job name" on banner page
3471553Srgrimes	 *		C -- "class name" on banner page
3481553Srgrimes	 *              L -- "literal" user's name to print on banner
3491553Srgrimes	 *		T -- "title" for pr
3501553Srgrimes	 *		H -- "host name" of machine where lpr was done
3511553Srgrimes	 *              P -- "person" user's login name
3521553Srgrimes	 *              I -- "indent" amount to indent output
35315648Sjoerg	 *		R -- laser dpi "resolution"
3541553Srgrimes	 *              f -- "file name" name of text file to print
3551553Srgrimes	 *		l -- "file name" text file with control chars
3561553Srgrimes	 *		p -- "file name" text file to print with pr(1)
3571553Srgrimes	 *		t -- "file name" troff(1) file to print
3581553Srgrimes	 *		n -- "file name" ditroff(1) file to print
3591553Srgrimes	 *		d -- "file name" dvi file to print
3601553Srgrimes	 *		g -- "file name" plot(1G) file to print
3611553Srgrimes	 *		v -- "file name" plain raster file to print
3621553Srgrimes	 *		c -- "file name" cifplot file to print
3631553Srgrimes	 *		1 -- "R font file" for troff
3641553Srgrimes	 *		2 -- "I font file" for troff
3651553Srgrimes	 *		3 -- "B font file" for troff
3661553Srgrimes	 *		4 -- "S font file" for troff
3671553Srgrimes	 *		N -- "name" of file (used by lpq)
3681553Srgrimes	 *              U -- "unlink" name of file to remove
3691553Srgrimes	 *                    (after we print it. (Pass 2 only)).
3701553Srgrimes	 *		M -- "mail" to user when done printing
3711553Srgrimes	 *
3721553Srgrimes	 *      getline reads a line and expands tabs to blanks
3731553Srgrimes	 */
3741553Srgrimes
3751553Srgrimes	/* pass 1 */
3761553Srgrimes
3771553Srgrimes	while (getline(cfp))
3781553Srgrimes		switch (line[0]) {
3791553Srgrimes		case 'H':
3801553Srgrimes			strcpy(fromhost, line+1);
3811553Srgrimes			if (class[0] == '\0')
3821553Srgrimes				strncpy(class, line+1, sizeof(class)-1);
3831553Srgrimes			continue;
3841553Srgrimes
3851553Srgrimes		case 'P':
3861553Srgrimes			strncpy(logname, line+1, sizeof(logname)-1);
3871553Srgrimes			if (RS) {			/* restricted */
3881553Srgrimes				if (getpwnam(logname) == NULL) {
3891553Srgrimes					bombed = NOACCT;
3901553Srgrimes					sendmail(line+1, bombed);
3911553Srgrimes					goto pass2;
3921553Srgrimes				}
3931553Srgrimes			}
3941553Srgrimes			continue;
3951553Srgrimes
3961553Srgrimes		case 'S':
3971553Srgrimes			cp = line+1;
3981553Srgrimes			i = 0;
3991553Srgrimes			while (*cp >= '0' && *cp <= '9')
4001553Srgrimes				i = i * 10 + (*cp++ - '0');
4011553Srgrimes			fdev = i;
4021553Srgrimes			cp++;
4031553Srgrimes			i = 0;
4041553Srgrimes			while (*cp >= '0' && *cp <= '9')
4051553Srgrimes				i = i * 10 + (*cp++ - '0');
4061553Srgrimes			fino = i;
4071553Srgrimes			continue;
4081553Srgrimes
4091553Srgrimes		case 'J':
4101553Srgrimes			if (line[1] != '\0')
4111553Srgrimes				strncpy(jobname, line+1, sizeof(jobname)-1);
4121553Srgrimes			else
4131553Srgrimes				strcpy(jobname, " ");
4141553Srgrimes			continue;
4151553Srgrimes
4161553Srgrimes		case 'C':
4171553Srgrimes			if (line[1] != '\0')
4181553Srgrimes				strncpy(class, line+1, sizeof(class)-1);
4191553Srgrimes			else if (class[0] == '\0')
4201553Srgrimes				gethostname(class, sizeof(class));
4211553Srgrimes			continue;
4221553Srgrimes
4231553Srgrimes		case 'T':	/* header title for pr */
4241553Srgrimes			strncpy(title, line+1, sizeof(title)-1);
4251553Srgrimes			continue;
4261553Srgrimes
4271553Srgrimes		case 'L':	/* identification line */
4281553Srgrimes			if (!SH && !HL)
4291553Srgrimes				banner(line+1, jobname);
4301553Srgrimes			continue;
4311553Srgrimes
4321553Srgrimes		case '1':	/* troff fonts */
4331553Srgrimes		case '2':
4341553Srgrimes		case '3':
4351553Srgrimes		case '4':
4361553Srgrimes			if (line[1] != '\0')
4371553Srgrimes				strcpy(fonts[line[0]-'1'], line+1);
4381553Srgrimes			continue;
4391553Srgrimes
4401553Srgrimes		case 'W':	/* page width */
4411553Srgrimes			strncpy(width+2, line+1, sizeof(width)-3);
4421553Srgrimes			continue;
4431553Srgrimes
4441553Srgrimes		case 'I':	/* indent amount */
4451553Srgrimes			strncpy(indent+2, line+1, sizeof(indent)-3);
4461553Srgrimes			continue;
4471553Srgrimes
4481553Srgrimes		default:	/* some file to print */
4491553Srgrimes			switch (i = print(line[0], line+1)) {
4501553Srgrimes			case ERROR:
4511553Srgrimes				if (bombed == OK)
4521553Srgrimes					bombed = FATALERR;
4531553Srgrimes				break;
4541553Srgrimes			case REPRINT:
4551553Srgrimes				(void) fclose(cfp);
4561553Srgrimes				return(REPRINT);
4571553Srgrimes			case FILTERERR:
4581553Srgrimes			case ACCESS:
4591553Srgrimes				bombed = i;
4601553Srgrimes				sendmail(logname, bombed);
4611553Srgrimes			}
4621553Srgrimes			title[0] = '\0';
4631553Srgrimes			continue;
4641553Srgrimes
4651553Srgrimes		case 'N':
4661553Srgrimes		case 'U':
4671553Srgrimes		case 'M':
46815648Sjoerg		case 'R':
4691553Srgrimes			continue;
4701553Srgrimes		}
4711553Srgrimes
4721553Srgrimes	/* pass 2 */
4731553Srgrimes
4741553Srgrimespass2:
4751553Srgrimes	fseek(cfp, 0L, 0);
4761553Srgrimes	while (getline(cfp))
4771553Srgrimes		switch (line[0]) {
4781553Srgrimes		case 'L':	/* identification line */
4791553Srgrimes			if (!SH && HL)
4801553Srgrimes				banner(line+1, jobname);
4811553Srgrimes			continue;
4821553Srgrimes
4831553Srgrimes		case 'M':
4841553Srgrimes			if (bombed < NOACCT)	/* already sent if >= NOACCT */
4851553Srgrimes				sendmail(line+1, bombed);
4861553Srgrimes			continue;
4871553Srgrimes
4881553Srgrimes		case 'U':
4891553Srgrimes			(void) unlink(line+1);
4901553Srgrimes		}
4911553Srgrimes	/*
4921553Srgrimes	 * clean-up in case another control file exists
4931553Srgrimes	 */
4941553Srgrimes	(void) fclose(cfp);
4951553Srgrimes	(void) unlink(file);
4961553Srgrimes	return(bombed == OK ? OK : ERROR);
4971553Srgrimes}
4981553Srgrimes
4991553Srgrimes/*
5001553Srgrimes * Print a file.
5011553Srgrimes * Set up the chain [ PR [ | {IF, OF} ] ] or {IF, RF, TF, NF, DF, CF, VF}.
5021553Srgrimes * Return -1 if a non-recoverable error occured,
5031553Srgrimes * 2 if the filter detected some errors (but printed the job anyway),
5041553Srgrimes * 1 if we should try to reprint this job and
5051553Srgrimes * 0 if all is well.
5061553Srgrimes * Note: all filters take stdin as the file, stdout as the printer,
5071553Srgrimes * stderr as the log file, and must not ignore SIGINT.
5081553Srgrimes */
5091553Srgrimesstatic int
5101553Srgrimesprint(format, file)
5111553Srgrimes	int format;
5121553Srgrimes	char *file;
5131553Srgrimes{
5141553Srgrimes	register int n;
5151553Srgrimes	register char *prog;
51618569Sbde	int dtablesize, fi, fo;
5171553Srgrimes	FILE *fp;
5181553Srgrimes	char *av[15], buf[BUFSIZ];
5191553Srgrimes	int pid, p[2], stopped = 0;
5201553Srgrimes	union wait status;
5211553Srgrimes	struct stat stb;
5221553Srgrimes
5231553Srgrimes	if (lstat(file, &stb) < 0 || (fi = open(file, O_RDONLY)) < 0)
5241553Srgrimes		return(ERROR);
5251553Srgrimes	/*
5261553Srgrimes	 * Check to see if data file is a symbolic link. If so, it should
5271553Srgrimes	 * still point to the same file or someone is trying to print
5281553Srgrimes	 * something he shouldn't.
5291553Srgrimes	 */
5301553Srgrimes	if ((stb.st_mode & S_IFMT) == S_IFLNK && fstat(fi, &stb) == 0 &&
5311553Srgrimes	    (stb.st_dev != fdev || stb.st_ino != fino))
5321553Srgrimes		return(ACCESS);
5331553Srgrimes	if (!SF && !tof) {		/* start on a fresh page */
5341553Srgrimes		(void) write(ofd, FF, strlen(FF));
5351553Srgrimes		tof = 1;
5361553Srgrimes	}
5371553Srgrimes	if (IF == NULL && (format == 'f' || format == 'l')) {
5381553Srgrimes		tof = 0;
5391553Srgrimes		while ((n = read(fi, buf, BUFSIZ)) > 0)
5401553Srgrimes			if (write(ofd, buf, n) != n) {
5411553Srgrimes				(void) close(fi);
5421553Srgrimes				return(REPRINT);
5431553Srgrimes			}
5441553Srgrimes		(void) close(fi);
5451553Srgrimes		return(OK);
5461553Srgrimes	}
5471553Srgrimes	switch (format) {
5481553Srgrimes	case 'p':	/* print file using 'pr' */
5491553Srgrimes		if (IF == NULL) {	/* use output filter */
5501553Srgrimes			prog = _PATH_PR;
5511553Srgrimes			av[0] = "pr";
5521553Srgrimes			av[1] = width;
5531553Srgrimes			av[2] = length;
5541553Srgrimes			av[3] = "-h";
5551553Srgrimes			av[4] = *title ? title : " ";
5565445Sjoerg			av[5] = "-F";
5575445Sjoerg			av[6] = 0;
5581553Srgrimes			fo = ofd;
5591553Srgrimes			goto start;
5601553Srgrimes		}
5611553Srgrimes		pipe(p);
5621553Srgrimes		if ((prchild = dofork(DORETURN)) == 0) {	/* child */
5631553Srgrimes			dup2(fi, 0);		/* file is stdin */
5641553Srgrimes			dup2(p[1], 1);		/* pipe is stdout */
5658094Sjkh			closelog();
56618569Sbde			for (n = 3, dtablesize = getdtablesize();
56718569Sbde			     n < dtablesize; n++)
5681553Srgrimes				(void) close(n);
5691553Srgrimes			execl(_PATH_PR, "pr", width, length,
5705445Sjoerg			    "-h", *title ? title : " ", "-F", 0);
5711553Srgrimes			syslog(LOG_ERR, "cannot execl %s", _PATH_PR);
5721553Srgrimes			exit(2);
5731553Srgrimes		}
5741553Srgrimes		(void) close(p[1]);		/* close output side */
5751553Srgrimes		(void) close(fi);
5761553Srgrimes		if (prchild < 0) {
5771553Srgrimes			prchild = 0;
5781553Srgrimes			(void) close(p[0]);
5791553Srgrimes			return(ERROR);
5801553Srgrimes		}
5811553Srgrimes		fi = p[0];			/* use pipe for input */
5821553Srgrimes	case 'f':	/* print plain text file */
5831553Srgrimes		prog = IF;
5841553Srgrimes		av[1] = width;
5851553Srgrimes		av[2] = length;
5861553Srgrimes		av[3] = indent;
5871553Srgrimes		n = 4;
5881553Srgrimes		break;
5891553Srgrimes	case 'l':	/* like 'f' but pass control characters */
5901553Srgrimes		prog = IF;
5911553Srgrimes		av[1] = "-c";
5921553Srgrimes		av[2] = width;
5931553Srgrimes		av[3] = length;
5941553Srgrimes		av[4] = indent;
5951553Srgrimes		n = 5;
5961553Srgrimes		break;
5971553Srgrimes	case 'r':	/* print a fortran text file */
5981553Srgrimes		prog = RF;
5991553Srgrimes		av[1] = width;
6001553Srgrimes		av[2] = length;
6011553Srgrimes		n = 3;
6021553Srgrimes		break;
6031553Srgrimes	case 't':	/* print troff output */
6041553Srgrimes	case 'n':	/* print ditroff output */
6051553Srgrimes	case 'd':	/* print tex output */
6061553Srgrimes		(void) unlink(".railmag");
6071553Srgrimes		if ((fo = creat(".railmag", FILMOD)) < 0) {
6081553Srgrimes			syslog(LOG_ERR, "%s: cannot create .railmag", printer);
6091553Srgrimes			(void) unlink(".railmag");
6101553Srgrimes		} else {
6111553Srgrimes			for (n = 0; n < 4; n++) {
6121553Srgrimes				if (fonts[n][0] != '/')
6131553Srgrimes					(void) write(fo, _PATH_VFONT,
6141553Srgrimes					    sizeof(_PATH_VFONT) - 1);
6151553Srgrimes				(void) write(fo, fonts[n], strlen(fonts[n]));
6161553Srgrimes				(void) write(fo, "\n", 1);
6171553Srgrimes			}
6181553Srgrimes			(void) close(fo);
6191553Srgrimes		}
6201553Srgrimes		prog = (format == 't') ? TF : (format == 'n') ? NF : DF;
6211553Srgrimes		av[1] = pxwidth;
6221553Srgrimes		av[2] = pxlength;
6231553Srgrimes		n = 3;
6241553Srgrimes		break;
6251553Srgrimes	case 'c':	/* print cifplot output */
6261553Srgrimes		prog = CF;
6271553Srgrimes		av[1] = pxwidth;
6281553Srgrimes		av[2] = pxlength;
6291553Srgrimes		n = 3;
6301553Srgrimes		break;
6311553Srgrimes	case 'g':	/* print plot(1G) output */
6321553Srgrimes		prog = GF;
6331553Srgrimes		av[1] = pxwidth;
6341553Srgrimes		av[2] = pxlength;
6351553Srgrimes		n = 3;
6361553Srgrimes		break;
6371553Srgrimes	case 'v':	/* print raster output */
6381553Srgrimes		prog = VF;
6391553Srgrimes		av[1] = pxwidth;
6401553Srgrimes		av[2] = pxlength;
6411553Srgrimes		n = 3;
6421553Srgrimes		break;
6431553Srgrimes	default:
6441553Srgrimes		(void) close(fi);
6451553Srgrimes		syslog(LOG_ERR, "%s: illegal format character '%c'",
6461553Srgrimes			printer, format);
6471553Srgrimes		return(ERROR);
6481553Srgrimes	}
64915648Sjoerg	if (prog == NULL) {
65015648Sjoerg		(void) close(fi);
65115648Sjoerg		syslog(LOG_ERR,
65215648Sjoerg		   "%s: no filter found in printcap for format character '%c'",
65315648Sjoerg		   printer, format);
65415648Sjoerg		return(ERROR);
65515648Sjoerg	}
6561553Srgrimes	if ((av[0] = rindex(prog, '/')) != NULL)
6571553Srgrimes		av[0]++;
6581553Srgrimes	else
6591553Srgrimes		av[0] = prog;
6601553Srgrimes	av[n++] = "-n";
6611553Srgrimes	av[n++] = logname;
6621553Srgrimes	av[n++] = "-h";
6631553Srgrimes	av[n++] = fromhost;
6641553Srgrimes	av[n++] = AF;
6651553Srgrimes	av[n] = 0;
6661553Srgrimes	fo = pfd;
6671553Srgrimes	if (ofilter > 0) {		/* stop output filter */
6681553Srgrimes		write(ofd, "\031\1", 2);
6691553Srgrimes		while ((pid =
6701553Srgrimes		    wait3((int *)&status, WUNTRACED, 0)) > 0 && pid != ofilter)
6711553Srgrimes			;
6721553Srgrimes		if (status.w_stopval != WSTOPPED) {
6731553Srgrimes			(void) close(fi);
67415648Sjoerg			syslog(LOG_WARNING,
67515648Sjoerg				"%s: output filter died (retcode=%d termsig=%d)",
67615648Sjoerg				printer, status.w_retcode, status.w_termsig);
6771553Srgrimes			return(REPRINT);
6781553Srgrimes		}
6791553Srgrimes		stopped++;
6801553Srgrimes	}
6811553Srgrimesstart:
6821553Srgrimes	if ((child = dofork(DORETURN)) == 0) {	/* child */
6831553Srgrimes		dup2(fi, 0);
6841553Srgrimes		dup2(fo, 1);
6851553Srgrimes		n = open(tempfile, O_WRONLY|O_CREAT|O_TRUNC, 0664);
6861553Srgrimes		if (n >= 0)
6871553Srgrimes			dup2(n, 2);
6888094Sjkh		closelog();
68918569Sbde		for (n = 3, dtablesize = getdtablesize(); n < dtablesize; n++)
6901553Srgrimes			(void) close(n);
6911553Srgrimes		execv(prog, av);
6921553Srgrimes		syslog(LOG_ERR, "cannot execv %s", prog);
6931553Srgrimes		exit(2);
6941553Srgrimes	}
6951553Srgrimes	(void) close(fi);
6961553Srgrimes	if (child < 0)
6971553Srgrimes		status.w_retcode = 100;
6981553Srgrimes	else
6991553Srgrimes		while ((pid = wait((int *)&status)) > 0 && pid != child)
7001553Srgrimes			;
7011553Srgrimes	child = 0;
7021553Srgrimes	prchild = 0;
7031553Srgrimes	if (stopped) {		/* restart output filter */
7041553Srgrimes		if (kill(ofilter, SIGCONT) < 0) {
7051553Srgrimes			syslog(LOG_ERR, "cannot restart output filter");
7061553Srgrimes			exit(1);
7071553Srgrimes		}
7081553Srgrimes	}
7091553Srgrimes	tof = 0;
7101553Srgrimes
7111553Srgrimes	/* Copy filter output to "lf" logfile */
7121553Srgrimes	if (fp = fopen(tempfile, "r")) {
7131553Srgrimes		while (fgets(buf, sizeof(buf), fp))
7141553Srgrimes			fputs(buf, stderr);
7151553Srgrimes		fclose(fp);
7161553Srgrimes	}
7171553Srgrimes
7181553Srgrimes	if (!WIFEXITED(status)) {
71915648Sjoerg		syslog(LOG_WARNING, "%s: filter '%c' terminated (termsig=%d)",
7201553Srgrimes			printer, format, status.w_termsig);
7211553Srgrimes		return(ERROR);
7221553Srgrimes	}
7231553Srgrimes	switch (status.w_retcode) {
7241553Srgrimes	case 0:
7251553Srgrimes		tof = 1;
7261553Srgrimes		return(OK);
7271553Srgrimes	case 1:
7281553Srgrimes		return(REPRINT);
72915648Sjoerg	case 2:
73015648Sjoerg		return(ERROR);
7311553Srgrimes	default:
73215648Sjoerg		syslog(LOG_WARNING, "%s: filter '%c' exited (retcode=%d)",
7331553Srgrimes			printer, format, status.w_retcode);
73415648Sjoerg		return(FILTERERR);
7351553Srgrimes	}
7361553Srgrimes}
7371553Srgrimes
7381553Srgrimes/*
7391553Srgrimes * Send the daemon control file (cf) and any data files.
7401553Srgrimes * Return -1 if a non-recoverable error occured, 1 if a recoverable error and
7411553Srgrimes * 0 if all is well.
7421553Srgrimes */
7431553Srgrimesstatic int
7441553Srgrimessendit(file)
7451553Srgrimes	char *file;
7461553Srgrimes{
7471553Srgrimes	register int i, err = OK;
7481553Srgrimes	char *cp, last[BUFSIZ];
7491553Srgrimes
7501553Srgrimes	/*
7511553Srgrimes	 * open control file
7521553Srgrimes	 */
7531553Srgrimes	if ((cfp = fopen(file, "r")) == NULL)
7541553Srgrimes		return(OK);
7551553Srgrimes	/*
7561553Srgrimes	 *      read the control file for work to do
7571553Srgrimes	 *
7581553Srgrimes	 *      file format -- first character in the line is a command
7591553Srgrimes	 *      rest of the line is the argument.
7601553Srgrimes	 *      commands of interest are:
7611553Srgrimes	 *
7621553Srgrimes	 *            a-z -- "file name" name of file to print
7631553Srgrimes	 *              U -- "unlink" name of file to remove
7641553Srgrimes	 *                    (after we print it. (Pass 2 only)).
7651553Srgrimes	 */
7661553Srgrimes
7671553Srgrimes	/*
7681553Srgrimes	 * pass 1
7691553Srgrimes	 */
7701553Srgrimes	while (getline(cfp)) {
7711553Srgrimes	again:
7721553Srgrimes		if (line[0] == 'S') {
7731553Srgrimes			cp = line+1;
7741553Srgrimes			i = 0;
7751553Srgrimes			while (*cp >= '0' && *cp <= '9')
7761553Srgrimes				i = i * 10 + (*cp++ - '0');
7771553Srgrimes			fdev = i;
7781553Srgrimes			cp++;
7791553Srgrimes			i = 0;
7801553Srgrimes			while (*cp >= '0' && *cp <= '9')
7811553Srgrimes				i = i * 10 + (*cp++ - '0');
7821553Srgrimes			fino = i;
78324831Sbrian		} else if (line[0] == 'H') {
78424831Sbrian			strcpy(fromhost, line+1);
78524831Sbrian			if (class[0] == '\0')
78624831Sbrian				strncpy(class, line+1, sizeof(class)-1);
78724831Sbrian		} else if (line[0] == 'P') {
78824831Sbrian			strncpy(logname, line+1, sizeof(logname)-1);
78924831Sbrian			if (RS) {			/* restricted */
79024831Sbrian				if (getpwnam(logname) == NULL) {
79124831Sbrian					sendmail(line+1, NOACCT);
79224831Sbrian					err = ERROR;
79324831Sbrian					break;
79424831Sbrian				}
79524831Sbrian			}
79624831Sbrian		} else if (line[0] == 'I') {
79724831Sbrian			strncpy(indent+2, line+1, sizeof(indent)-3);
79824831Sbrian		} else if (line[0] >= 'a' && line[0] <= 'z') {
7991553Srgrimes			strcpy(last, line);
8001553Srgrimes			while (i = getline(cfp))
8011553Srgrimes				if (strcmp(last, line))
8021553Srgrimes					break;
80324831Sbrian			switch (sendfile('\3', last+1, *last)) {
8041553Srgrimes			case OK:
8051553Srgrimes				if (i)
8061553Srgrimes					goto again;
8071553Srgrimes				break;
8081553Srgrimes			case REPRINT:
8091553Srgrimes				(void) fclose(cfp);
8101553Srgrimes				return(REPRINT);
8111553Srgrimes			case ACCESS:
8121553Srgrimes				sendmail(logname, ACCESS);
8131553Srgrimes			case ERROR:
8141553Srgrimes				err = ERROR;
8151553Srgrimes			}
8161553Srgrimes			break;
8171553Srgrimes		}
8181553Srgrimes	}
81924831Sbrian	if (err == OK && sendfile('\2', file, '\0') > 0) {
8201553Srgrimes		(void) fclose(cfp);
8211553Srgrimes		return(REPRINT);
8221553Srgrimes	}
8231553Srgrimes	/*
8241553Srgrimes	 * pass 2
8251553Srgrimes	 */
8261553Srgrimes	fseek(cfp, 0L, 0);
8271553Srgrimes	while (getline(cfp))
8281553Srgrimes		if (line[0] == 'U')
8291553Srgrimes			(void) unlink(line+1);
8301553Srgrimes	/*
8311553Srgrimes	 * clean-up in case another control file exists
8321553Srgrimes	 */
8331553Srgrimes	(void) fclose(cfp);
8341553Srgrimes	(void) unlink(file);
8351553Srgrimes	return(err);
8361553Srgrimes}
8371553Srgrimes
8381553Srgrimes/*
8391553Srgrimes * Send a data file to the remote machine and spool it.
8401553Srgrimes * Return positive if we should try resending.
8411553Srgrimes */
8421553Srgrimesstatic int
84324831Sbriansendfile(type, file, format)
8441553Srgrimes	int type;
8451553Srgrimes	char *file;
84624831Sbrian	char format;
8471553Srgrimes{
8481553Srgrimes	register int f, i, amt;
8491553Srgrimes	struct stat stb;
8501553Srgrimes	char buf[BUFSIZ];
85124831Sbrian	int sizerr, resp, closedpr;
8521553Srgrimes
8531553Srgrimes	if (lstat(file, &stb) < 0 || (f = open(file, O_RDONLY)) < 0)
8541553Srgrimes		return(ERROR);
8551553Srgrimes	/*
8561553Srgrimes	 * Check to see if data file is a symbolic link. If so, it should
8571553Srgrimes	 * still point to the same file or someone is trying to print something
8581553Srgrimes	 * he shouldn't.
8591553Srgrimes	 */
8601553Srgrimes	if ((stb.st_mode & S_IFMT) == S_IFLNK && fstat(f, &stb) == 0 &&
8611553Srgrimes	    (stb.st_dev != fdev || stb.st_ino != fino))
8621553Srgrimes		return(ACCESS);
86324831Sbrian
86424831Sbrian	sizerr = 0;
86524831Sbrian	closedpr = 0;
86624831Sbrian	if (type == '\3') {
86724831Sbrian		if (IF) {
86824831Sbrian			/*
86924831Sbrian			 * We're sending something with an ifilter, we have to
87024831Sbrian			 * run the ifilter and store the output as a
87124831Sbrian			 * temporary file (tfile)... the protocol requires us
87224831Sbrian			 * to send the file size
87324831Sbrian			 */
87424831Sbrian			char *av[15];
87524831Sbrian			int n;
87624831Sbrian			int nfd;
87724831Sbrian			int ifilter;
87824831Sbrian			union wait status;
87924831Sbrian
88024831Sbrian			strcpy(tfile,TFILENAME);
88124831Sbrian			if ((tfd = mkstemp(tfile)) == -1) {
88224831Sbrian				syslog(LOG_ERR, "mkstemp: %m");
88324831Sbrian				return(ERROR);
88424831Sbrian			}
88524831Sbrian			if ((av[0] = rindex(IF, '/')) == NULL)
88624831Sbrian				av[0] = IF;
88724831Sbrian			else
88824831Sbrian				av[0]++;
88924831Sbrian			if (format == 'l')
89024831Sbrian				av[n=1] = "-c";
89124831Sbrian			else
89224831Sbrian				n = 0;
89324831Sbrian			av[++n] = width;
89424831Sbrian			av[++n] = length;
89524831Sbrian			av[++n] = indent;
89624831Sbrian			av[++n] = "-n";
89724831Sbrian			av[++n] = logname;
89824831Sbrian			av[++n] = "-h";
89924831Sbrian			av[++n] = fromhost;
90024831Sbrian			av[++n] = AF;
90124831Sbrian			av[++n] = 0;
90224831Sbrian			if ((ifilter = dofork(DORETURN)) == 0) {  /* child */
90324831Sbrian				dup2(f, 0);
90424831Sbrian				dup2(tfd, 1);
90524831Sbrian				n = open(tempfile, O_WRONLY|O_CREAT|O_TRUNC, 0664);
90624831Sbrian				if (n >= 0)
90724831Sbrian					dup2(n, 2);
90824831Sbrian				closelog();
90924831Sbrian				for (n = 3, nfd = getdtablesize(); n < nfd; n++)
91024831Sbrian					(void) close(n);
91124831Sbrian				execv(IF, av);
91224831Sbrian				syslog(LOG_ERR, "cannot execv %s", IF);
91324831Sbrian				exit(2);
91424831Sbrian			}
91524831Sbrian			(void) close(f);
91624831Sbrian			if (ifilter < 0)
91724831Sbrian				status.w_retcode = 100;
91824831Sbrian			else
91924831Sbrian				while ((pid = wait((int *)&status)) > 0 &&
92024831Sbrian					pid != ifilter)
92124831Sbrian					;
92224831Sbrian			switch (status.w_retcode) {
92324831Sbrian			case 0:
92424831Sbrian				break;
92524831Sbrian			case 1:
92624831Sbrian				unlink(tfile);
92724831Sbrian				return(REPRINT);
92824831Sbrian			case 2:
92924831Sbrian				unlink(tfile);
93024831Sbrian				return(ERROR);
93124831Sbrian			default:
93224831Sbrian				syslog(LOG_WARNING, "%s: filter '%c' exited"
93324831Sbrian					" (retcode=%d)",
93424831Sbrian					printer, format, status.w_retcode);
93524831Sbrian				unlink(tfile);
93624831Sbrian				return(FILTERERR);
93724831Sbrian			}
93824831Sbrian			if (fstat(tfd, &stb) < 0)	/* the size of tfile */
93924831Sbrian				return(ERROR);
94024831Sbrian			f = tfd;
94124831Sbrian			lseek(f,0,SEEK_SET);
94224831Sbrian		} else if (ofilter) {
94324831Sbrian			/*
94424831Sbrian			 * We're sending something with an ofilter, we have to
94524831Sbrian			 * store the output as a temporary file (tfile)... the
94624831Sbrian			 * protocol requires us to send the file size
94724831Sbrian			 */
94824831Sbrian			int i;
94924831Sbrian			for (i = 0; i < stb.st_size; i += BUFSIZ) {
95024831Sbrian				amt = BUFSIZ;
95124831Sbrian				if (i + amt > stb.st_size)
95224831Sbrian					amt = stb.st_size - i;
95324831Sbrian				if (sizerr == 0 && read(f, buf, amt) != amt) {
95424831Sbrian					sizerr = 1;
95524831Sbrian					break;
95624831Sbrian				}
95724831Sbrian				if (write(ofd, buf, amt) != amt) {
95824831Sbrian					(void) close(f);
95924831Sbrian					return(REPRINT);
96024831Sbrian				}
96124831Sbrian			}
96224831Sbrian			close(ofd);
96324831Sbrian			close(f);
96424831Sbrian			while ((i = wait(NULL)) > 0 && i != ofilter)
96524831Sbrian				;
96624831Sbrian			ofilter = 0;
96724831Sbrian			if (fstat(tfd, &stb) < 0) {	/* the size of tfile */
96824831Sbrian				openpr();
96924831Sbrian				return(ERROR);
97024831Sbrian			}
97124831Sbrian			f = tfd;
97224831Sbrian			lseek(f,0,SEEK_SET);
97324831Sbrian			closedpr = 1;
97424831Sbrian		}
97524831Sbrian	}
97624831Sbrian
9771553Srgrimes	(void) sprintf(buf, "%c%qd %s\n", type, stb.st_size, file);
9781553Srgrimes	amt = strlen(buf);
9791553Srgrimes	for (i = 0;  ; i++) {
9801553Srgrimes		if (write(pfd, buf, amt) != amt ||
9811553Srgrimes		    (resp = response()) < 0 || resp == '\1') {
9821553Srgrimes			(void) close(f);
98324831Sbrian			if (tfd != -1 && type == '\3') {
98424831Sbrian				tfd = -1;
98524831Sbrian				unlink(tfile);
98624831Sbrian				if (closedpr)
98724831Sbrian					openpr();
98824831Sbrian			}
9891553Srgrimes			return(REPRINT);
9901553Srgrimes		} else if (resp == '\0')
9911553Srgrimes			break;
9921553Srgrimes		if (i == 0)
9931553Srgrimes			pstatus("no space on remote; waiting for queue to drain");
9941553Srgrimes		if (i == 10)
9951553Srgrimes			syslog(LOG_ALERT, "%s: can't send to %s; queue full",
9961553Srgrimes				printer, RM);
9971553Srgrimes		sleep(5 * 60);
9981553Srgrimes	}
9991553Srgrimes	if (i)
10001553Srgrimes		pstatus("sending to %s", RM);
10011553Srgrimes	for (i = 0; i < stb.st_size; i += BUFSIZ) {
10021553Srgrimes		amt = BUFSIZ;
10031553Srgrimes		if (i + amt > stb.st_size)
10041553Srgrimes			amt = stb.st_size - i;
10051553Srgrimes		if (sizerr == 0 && read(f, buf, amt) != amt)
10061553Srgrimes			sizerr = 1;
10071553Srgrimes		if (write(pfd, buf, amt) != amt) {
10081553Srgrimes			(void) close(f);
100924831Sbrian			if (tfd != -1 && type == '\3') {
101024831Sbrian				tfd = -1;
101124831Sbrian				unlink(tfile);
101224831Sbrian				if (closedpr)
101324831Sbrian					openpr();
101424831Sbrian			}
10151553Srgrimes			return(REPRINT);
10161553Srgrimes		}
10171553Srgrimes	}
10181553Srgrimes
10191553Srgrimes	(void) close(f);
102024831Sbrian	if (tfd != -1 && type == '\3') {
102124831Sbrian		tfd = -1;
102224831Sbrian		unlink(tfile);
102324831Sbrian	}
10241553Srgrimes	if (sizerr) {
10251553Srgrimes		syslog(LOG_INFO, "%s: %s: changed size", printer, file);
10261553Srgrimes		/* tell recvjob to ignore this file */
10271553Srgrimes		(void) write(pfd, "\1", 1);
102824831Sbrian		if (closedpr)
102924831Sbrian			openpr();
10301553Srgrimes		return(ERROR);
10311553Srgrimes	}
103224831Sbrian	if (write(pfd, "", 1) != 1 || response()) {
103324831Sbrian		if (closedpr)
103424831Sbrian			openpr();
10351553Srgrimes		return(REPRINT);
103624831Sbrian	}
103724831Sbrian	if (closedpr)
103824831Sbrian		openpr();
10391553Srgrimes	return(OK);
10401553Srgrimes}
10411553Srgrimes
10421553Srgrimes/*
10431553Srgrimes * Check to make sure there have been no errors and that both programs
10441553Srgrimes * are in sync with eachother.
10451553Srgrimes * Return non-zero if the connection was lost.
10461553Srgrimes */
10471553Srgrimesstatic char
10481553Srgrimesresponse()
10491553Srgrimes{
10501553Srgrimes	char resp;
10511553Srgrimes
10521553Srgrimes	if (read(pfd, &resp, 1) != 1) {
10531553Srgrimes		syslog(LOG_INFO, "%s: lost connection", printer);
10541553Srgrimes		return(-1);
10551553Srgrimes	}
10561553Srgrimes	return(resp);
10571553Srgrimes}
10581553Srgrimes
10591553Srgrimes/*
10601553Srgrimes * Banner printing stuff
10611553Srgrimes */
10621553Srgrimesstatic void
10631553Srgrimesbanner(name1, name2)
10641553Srgrimes	char *name1, *name2;
10651553Srgrimes{
10661553Srgrimes	time_t tvec;
10671553Srgrimes
10681553Srgrimes	time(&tvec);
10691553Srgrimes	if (!SF && !tof)
10701553Srgrimes		(void) write(ofd, FF, strlen(FF));
10711553Srgrimes	if (SB) {	/* short banner only */
10721553Srgrimes		if (class[0]) {
10731553Srgrimes			(void) write(ofd, class, strlen(class));
10741553Srgrimes			(void) write(ofd, ":", 1);
10751553Srgrimes		}
10761553Srgrimes		(void) write(ofd, name1, strlen(name1));
10771553Srgrimes		(void) write(ofd, "  Job: ", 7);
10781553Srgrimes		(void) write(ofd, name2, strlen(name2));
10791553Srgrimes		(void) write(ofd, "  Date: ", 8);
10801553Srgrimes		(void) write(ofd, ctime(&tvec), 24);
10811553Srgrimes		(void) write(ofd, "\n", 1);
10821553Srgrimes	} else {	/* normal banner */
10831553Srgrimes		(void) write(ofd, "\n\n\n", 3);
10841553Srgrimes		scan_out(ofd, name1, '\0');
10851553Srgrimes		(void) write(ofd, "\n\n", 2);
10861553Srgrimes		scan_out(ofd, name2, '\0');
10871553Srgrimes		if (class[0]) {
10881553Srgrimes			(void) write(ofd,"\n\n\n",3);
10891553Srgrimes			scan_out(ofd, class, '\0');
10901553Srgrimes		}
10911553Srgrimes		(void) write(ofd, "\n\n\n\n\t\t\t\t\tJob:  ", 15);
10921553Srgrimes		(void) write(ofd, name2, strlen(name2));
10931553Srgrimes		(void) write(ofd, "\n\t\t\t\t\tDate: ", 12);
10941553Srgrimes		(void) write(ofd, ctime(&tvec), 24);
10951553Srgrimes		(void) write(ofd, "\n", 1);
10961553Srgrimes	}
10971553Srgrimes	if (!SF)
10981553Srgrimes		(void) write(ofd, FF, strlen(FF));
10991553Srgrimes	tof = 1;
11001553Srgrimes}
11011553Srgrimes
11021553Srgrimesstatic char *
11031553Srgrimesscnline(key, p, c)
11041553Srgrimes	register int key;
11051553Srgrimes	register char *p;
11061553Srgrimes	int c;
11071553Srgrimes{
11081553Srgrimes	register scnwidth;
11091553Srgrimes
11101553Srgrimes	for (scnwidth = WIDTH; --scnwidth;) {
11111553Srgrimes		key <<= 1;
11121553Srgrimes		*p++ = key & 0200 ? c : BACKGND;
11131553Srgrimes	}
11141553Srgrimes	return (p);
11151553Srgrimes}
11161553Srgrimes
11171553Srgrimes#define TRC(q)	(((q)-' ')&0177)
11181553Srgrimes
11191553Srgrimesstatic void
11201553Srgrimesscan_out(scfd, scsp, dlm)
11211553Srgrimes	int scfd, dlm;
11221553Srgrimes	char *scsp;
11231553Srgrimes{
11241553Srgrimes	register char *strp;
11251553Srgrimes	register nchrs, j;
11261553Srgrimes	char outbuf[LINELEN+1], *sp, c, cc;
11271553Srgrimes	int d, scnhgt;
11281553Srgrimes
11291553Srgrimes	for (scnhgt = 0; scnhgt++ < HEIGHT+DROP; ) {
11301553Srgrimes		strp = &outbuf[0];
11311553Srgrimes		sp = scsp;
11321553Srgrimes		for (nchrs = 0; ; ) {
11331553Srgrimes			d = dropit(c = TRC(cc = *sp++));
11341553Srgrimes			if ((!d && scnhgt > HEIGHT) || (scnhgt <= DROP && d))
11351553Srgrimes				for (j = WIDTH; --j;)
11361553Srgrimes					*strp++ = BACKGND;
11371553Srgrimes			else
11381553Srgrimes				strp = scnline(scnkey[c][scnhgt-1-d], strp, cc);
11391553Srgrimes			if (*sp == dlm || *sp == '\0' || nchrs++ >= PW/(WIDTH+1)-1)
11401553Srgrimes				break;
11411553Srgrimes			*strp++ = BACKGND;
11421553Srgrimes			*strp++ = BACKGND;
11431553Srgrimes		}
11441553Srgrimes		while (*--strp == BACKGND && strp >= outbuf)
11451553Srgrimes			;
11461553Srgrimes		strp++;
11478857Srgrimes		*strp++ = '\n';
11481553Srgrimes		(void) write(scfd, outbuf, strp-outbuf);
11491553Srgrimes	}
11501553Srgrimes}
11511553Srgrimes
11521553Srgrimesstatic int
11531553Srgrimesdropit(c)
11541553Srgrimes	int c;
11551553Srgrimes{
11561553Srgrimes	switch(c) {
11571553Srgrimes
11581553Srgrimes	case TRC('_'):
11591553Srgrimes	case TRC(';'):
11601553Srgrimes	case TRC(','):
11611553Srgrimes	case TRC('g'):
11621553Srgrimes	case TRC('j'):
11631553Srgrimes	case TRC('p'):
11641553Srgrimes	case TRC('q'):
11651553Srgrimes	case TRC('y'):
11661553Srgrimes		return (DROP);
11671553Srgrimes
11681553Srgrimes	default:
11691553Srgrimes		return (0);
11701553Srgrimes	}
11711553Srgrimes}
11721553Srgrimes
11731553Srgrimes/*
11741553Srgrimes * sendmail ---
11751553Srgrimes *   tell people about job completion
11761553Srgrimes */
11771553Srgrimesstatic void
11781553Srgrimessendmail(user, bombed)
11791553Srgrimes	char *user;
11801553Srgrimes	int bombed;
11811553Srgrimes{
11821553Srgrimes	register int i;
118318569Sbde	int dtablesize;
11841553Srgrimes	int p[2], s;
11851553Srgrimes	register char *cp;
11861553Srgrimes	char buf[100];
11871553Srgrimes	struct stat stb;
11881553Srgrimes	FILE *fp;
11891553Srgrimes
11901553Srgrimes	pipe(p);
11911553Srgrimes	if ((s = dofork(DORETURN)) == 0) {		/* child */
11921553Srgrimes		dup2(p[0], 0);
11938094Sjkh		closelog();
119418569Sbde		for (i = 3, dtablesize = getdtablesize(); i < dtablesize; i++)
11951553Srgrimes			(void) close(i);
11961553Srgrimes		if ((cp = rindex(_PATH_SENDMAIL, '/')) != NULL)
11971553Srgrimes			cp++;
11981553Srgrimes	else
11991553Srgrimes			cp = _PATH_SENDMAIL;
12001553Srgrimes		sprintf(buf, "%s@%s", user, fromhost);
12011553Srgrimes		execl(_PATH_SENDMAIL, cp, buf, 0);
12021553Srgrimes		exit(0);
12031553Srgrimes	} else if (s > 0) {				/* parent */
12041553Srgrimes		dup2(p[1], 1);
12051553Srgrimes		printf("To: %s@%s\n", user, fromhost);
120615648Sjoerg		printf("Subject: %s printer job \"%s\"\n", printer,
120715648Sjoerg			*jobname ? jobname : "<unknown>");
120815648Sjoerg		printf("Reply-To: root@%s\n\n", host);
12091553Srgrimes		printf("Your printer job ");
12101553Srgrimes		if (*jobname)
12111553Srgrimes			printf("(%s) ", jobname);
12121553Srgrimes		switch (bombed) {
12131553Srgrimes		case OK:
12141553Srgrimes			printf("\ncompleted successfully\n");
121515648Sjoerg			cp = "OK";
12161553Srgrimes			break;
12171553Srgrimes		default:
12181553Srgrimes		case FATALERR:
12191553Srgrimes			printf("\ncould not be printed\n");
122015648Sjoerg			cp = "FATALERR";
12211553Srgrimes			break;
12221553Srgrimes		case NOACCT:
12231553Srgrimes			printf("\ncould not be printed without an account on %s\n", host);
122415648Sjoerg			cp = "NOACCT";
12251553Srgrimes			break;
12261553Srgrimes		case FILTERERR:
12271553Srgrimes			if (stat(tempfile, &stb) < 0 || stb.st_size == 0 ||
12281553Srgrimes			    (fp = fopen(tempfile, "r")) == NULL) {
122915648Sjoerg				printf("\nhad some errors and may not have printed\n");
12301553Srgrimes				break;
12311553Srgrimes			}
123215648Sjoerg			printf("\nhad the following errors and may not have printed:\n");
12331553Srgrimes			while ((i = getc(fp)) != EOF)
12341553Srgrimes				putchar(i);
12351553Srgrimes			(void) fclose(fp);
123615648Sjoerg			cp = "FILTERERR";
12371553Srgrimes			break;
12381553Srgrimes		case ACCESS:
12391553Srgrimes			printf("\nwas not printed because it was not linked to the original file\n");
124015648Sjoerg			cp = "ACCESS";
12411553Srgrimes		}
12421553Srgrimes		fflush(stdout);
12431553Srgrimes		(void) close(1);
12441553Srgrimes	}
12451553Srgrimes	(void) close(p[0]);
12461553Srgrimes	(void) close(p[1]);
124715648Sjoerg	wait(NULL);
124815648Sjoerg	syslog(LOG_INFO, "mail sent to user %s about job %s on printer %s (%s)",
124915648Sjoerg		user, *jobname ? jobname : "<unknown>", printer, cp);
12501553Srgrimes}
12511553Srgrimes
12521553Srgrimes/*
12531553Srgrimes * dofork - fork with retries on failure
12541553Srgrimes */
12551553Srgrimesstatic int
12561553Srgrimesdofork(action)
12571553Srgrimes	int action;
12581553Srgrimes{
12591553Srgrimes	register int i, pid;
12601553Srgrimes
12611553Srgrimes	for (i = 0; i < 20; i++) {
12621553Srgrimes		if ((pid = fork()) < 0) {
12631553Srgrimes			sleep((unsigned)(i*i));
12641553Srgrimes			continue;
12651553Srgrimes		}
12661553Srgrimes		/*
12671553Srgrimes		 * Child should run as daemon instead of root
12681553Srgrimes		 */
126915648Sjoerg		if (pid == 0)
12701553Srgrimes			setuid(DU);
12711553Srgrimes		return(pid);
12721553Srgrimes	}
12731553Srgrimes	syslog(LOG_ERR, "can't fork");
12741553Srgrimes
12751553Srgrimes	switch (action) {
12761553Srgrimes	case DORETURN:
12771553Srgrimes		return (-1);
12781553Srgrimes	default:
12791553Srgrimes		syslog(LOG_ERR, "bad action (%d) to dofork", action);
12801553Srgrimes		/*FALL THRU*/
12811553Srgrimes	case DOABORT:
12821553Srgrimes		exit(1);
12831553Srgrimes	}
12841553Srgrimes	/*NOTREACHED*/
12851553Srgrimes}
12861553Srgrimes
12871553Srgrimes/*
12881553Srgrimes * Kill child processes to abort current job.
12891553Srgrimes */
12901553Srgrimesstatic void
12911553Srgrimesabortpr(signo)
12921553Srgrimes	int signo;
12931553Srgrimes{
12941553Srgrimes	(void) unlink(tempfile);
12951553Srgrimes	kill(0, SIGINT);
12961553Srgrimes	if (ofilter > 0)
12971553Srgrimes		kill(ofilter, SIGCONT);
12981553Srgrimes	while (wait(NULL) > 0)
12991553Srgrimes		;
130024831Sbrian	if (ofilter > 0 && tfd != -1)
130124831Sbrian		unlink(tfile);
13021553Srgrimes	exit(0);
13031553Srgrimes}
13041553Srgrimes
13051553Srgrimesstatic void
13061553Srgrimesinit()
13071553Srgrimes{
13081553Srgrimes	int status;
13091553Srgrimes	char *s;
13101553Srgrimes
13111553Srgrimes	if ((status = cgetent(&bp, printcapdb, printer)) == -2) {
13121553Srgrimes		syslog(LOG_ERR, "can't open printer description file");
13131553Srgrimes		exit(1);
13141553Srgrimes	} else if (status == -1) {
13151553Srgrimes		syslog(LOG_ERR, "unknown printer: %s", printer);
13161553Srgrimes		exit(1);
13171553Srgrimes	} else if (status == -3)
13181553Srgrimes		fatal("potential reference loop detected in printcap file");
13191553Srgrimes
13201553Srgrimes	if (cgetstr(bp, "lp", &LP) == -1)
13211553Srgrimes		LP = _PATH_DEFDEVLP;
13221553Srgrimes	if (cgetstr(bp, "rp", &RP) == -1)
13231553Srgrimes		RP = DEFLP;
13241553Srgrimes	if (cgetstr(bp, "lo", &LO) == -1)
13251553Srgrimes		LO = DEFLOCK;
13261553Srgrimes	if (cgetstr(bp, "st", &ST) == -1)
13271553Srgrimes		ST = DEFSTAT;
13281553Srgrimes	if (cgetstr(bp, "lf", &LF) == -1)
13291553Srgrimes		LF = _PATH_CONSOLE;
13301553Srgrimes	if (cgetstr(bp, "sd", &SD) == -1)
13311553Srgrimes		SD = _PATH_DEFSPOOL;
13321553Srgrimes	if (cgetnum(bp, "du", &DU) < 0)
13331553Srgrimes		DU = DEFUID;
13341553Srgrimes	if (cgetstr(bp,"ff", &FF) == -1)
13351553Srgrimes		FF = DEFFF;
13361553Srgrimes	if (cgetnum(bp, "pw", &PW) < 0)
13371553Srgrimes		PW = DEFWIDTH;
13381553Srgrimes	sprintf(&width[2], "%d", PW);
13391553Srgrimes	if (cgetnum(bp, "pl", &PL) < 0)
13401553Srgrimes		PL = DEFLENGTH;
13411553Srgrimes	sprintf(&length[2], "%d", PL);
13421553Srgrimes	if (cgetnum(bp,"px", &PX) < 0)
13431553Srgrimes		PX = 0;
13441553Srgrimes	sprintf(&pxwidth[2], "%d", PX);
13451553Srgrimes	if (cgetnum(bp, "py", &PY) < 0)
13461553Srgrimes		PY = 0;
13471553Srgrimes	sprintf(&pxlength[2], "%d", PY);
13481553Srgrimes	cgetstr(bp, "rm", &RM);
13491553Srgrimes	if (s = checkremote())
13501553Srgrimes		syslog(LOG_WARNING, s);
13511553Srgrimes
13521553Srgrimes	cgetstr(bp, "af", &AF);
13531553Srgrimes	cgetstr(bp, "of", &OF);
13541553Srgrimes	cgetstr(bp, "if", &IF);
13551553Srgrimes	cgetstr(bp, "rf", &RF);
13561553Srgrimes	cgetstr(bp, "tf", &TF);
13571553Srgrimes	cgetstr(bp, "nf", &NF);
13581553Srgrimes	cgetstr(bp, "df", &DF);
13591553Srgrimes	cgetstr(bp, "gf", &GF);
13601553Srgrimes	cgetstr(bp, "vf", &VF);
13611553Srgrimes	cgetstr(bp, "cf", &CF);
13621553Srgrimes	cgetstr(bp, "tr", &TR);
136315032Ssef	cgetstr(bp, "ms", &MS);
13641553Srgrimes
13651553Srgrimes	RS = (cgetcap(bp, "rs", ':') != NULL);
13661553Srgrimes	SF = (cgetcap(bp, "sf", ':') != NULL);
13671553Srgrimes	SH = (cgetcap(bp, "sh", ':') != NULL);
13681553Srgrimes	SB = (cgetcap(bp, "sb", ':') != NULL);
13691553Srgrimes	HL = (cgetcap(bp, "hl", ':') != NULL);
13701553Srgrimes	RW = (cgetcap(bp, "rw", ':') != NULL);
13711553Srgrimes
13721553Srgrimes	cgetnum(bp, "br", &BR);
13731553Srgrimes
13741553Srgrimes	tof = (cgetcap(bp, "fo", ':') == NULL);
13751553Srgrimes}
13761553Srgrimes
13771553Srgrimes/*
13781553Srgrimes * Acquire line printer or remote connection.
13791553Srgrimes */
13801553Srgrimesstatic void
13811553Srgrimesopenpr()
13821553Srgrimes{
138315648Sjoerg	register int i;
138418569Sbde	int dtablesize;
138515648Sjoerg	char *cp;
13861553Srgrimes
138715648Sjoerg	if (!remote && *LP) {
138815648Sjoerg		if (cp = index(LP, '@'))
138915648Sjoerg			opennet(cp);
139015648Sjoerg		else
139115648Sjoerg			opentty();
139215648Sjoerg	} else if (remote) {
139315648Sjoerg		openrem();
13941553Srgrimes	} else {
13951553Srgrimes		syslog(LOG_ERR, "%s: no line printer device or host name",
13961553Srgrimes			printer);
13971553Srgrimes		exit(1);
13981553Srgrimes	}
139915648Sjoerg
14001553Srgrimes	/*
14011553Srgrimes	 * Start up an output filter, if needed.
14021553Srgrimes	 */
140324831Sbrian	if (OF && !IF && !ofilter) {
14041553Srgrimes		int p[2];
14051553Srgrimes
14061553Srgrimes		pipe(p);
140724831Sbrian		if (remote) {
140824831Sbrian			strcpy(tfile,TFILENAME);
140924831Sbrian			tfd = mkstemp(tfile);
141024831Sbrian		}
14111553Srgrimes		if ((ofilter = dofork(DOABORT)) == 0) {	/* child */
14121553Srgrimes			dup2(p[0], 0);		/* pipe is std in */
141324831Sbrian			/* tfile/printer is stdout */
141424831Sbrian			dup2(remote ? tfd : pfd, 1);
14158094Sjkh			closelog();
141618569Sbde			for (i = 3, dtablesize = getdtablesize();
141718569Sbde			     i < dtablesize; i++)
14181553Srgrimes				(void) close(i);
14191553Srgrimes			if ((cp = rindex(OF, '/')) == NULL)
14201553Srgrimes				cp = OF;
14211553Srgrimes			else
14221553Srgrimes				cp++;
14231553Srgrimes			execl(OF, cp, width, length, 0);
14241553Srgrimes			syslog(LOG_ERR, "%s: %s: %m", printer, OF);
14251553Srgrimes			exit(1);
14261553Srgrimes		}
14271553Srgrimes		(void) close(p[0]);		/* close input side */
14281553Srgrimes		ofd = p[1];			/* use pipe for output */
14291553Srgrimes	} else {
14301553Srgrimes		ofd = pfd;
14311553Srgrimes		ofilter = 0;
14321553Srgrimes	}
14331553Srgrimes}
14341553Srgrimes
143515648Sjoerg/*
143615648Sjoerg * Printer connected directly to the network
143715648Sjoerg * or to a terminal server on the net
143815648Sjoerg */
143915648Sjoergstatic void
144015648Sjoergopennet(cp)
144115648Sjoerg	char *cp;
144215648Sjoerg{
144315648Sjoerg	register int i;
144415648Sjoerg	int resp, port;
144515648Sjoerg	char save_ch;
144615648Sjoerg
144715648Sjoerg	save_ch = *cp;
144815648Sjoerg	*cp = '\0';
144915648Sjoerg	port = atoi(LP);
145015648Sjoerg	if (port <= 0) {
145115648Sjoerg		syslog(LOG_ERR, "%s: bad port number: %s", printer, LP);
145215648Sjoerg		exit(1);
145315648Sjoerg	}
145415648Sjoerg	*cp++ = save_ch;
145515648Sjoerg
145615648Sjoerg	for (i = 1; ; i = i < 256 ? i << 1 : i) {
145715648Sjoerg		resp = -1;
145815648Sjoerg		pfd = getport(cp, port);
145915648Sjoerg		if (pfd < 0 && errno == ECONNREFUSED)
146015648Sjoerg			resp = 1;
146115648Sjoerg		else if (pfd >= 0) {
146215648Sjoerg			/*
146315648Sjoerg			 * need to delay a bit for rs232 lines
146415648Sjoerg			 * to stabilize in case printer is
146515648Sjoerg			 * connected via a terminal server
146615648Sjoerg			 */
146715648Sjoerg			delay(500);
146815648Sjoerg			break;
146915648Sjoerg		}
147015648Sjoerg		if (i == 1) {
147115648Sjoerg		   if (resp < 0)
147215648Sjoerg			pstatus("waiting for %s to come up", LP);
147315648Sjoerg		   else
147415648Sjoerg			pstatus("waiting for access to printer on %s", LP);
147515648Sjoerg		}
147615648Sjoerg		sleep(i);
147715648Sjoerg	}
147815648Sjoerg	pstatus("sending to %s port %d", cp, port);
147915648Sjoerg}
148015648Sjoerg
148115648Sjoerg/*
148215648Sjoerg * Printer is connected to an RS232 port on this host
148315648Sjoerg */
148415648Sjoergstatic void
148515648Sjoergopentty()
148615648Sjoerg{
148715648Sjoerg	register int i;
148815648Sjoerg	int resp, port;
148915648Sjoerg
149015648Sjoerg	for (i = 1; ; i = i < 32 ? i << 1 : i) {
149115648Sjoerg		pfd = open(LP, RW ? O_RDWR : O_WRONLY);
149215648Sjoerg		if (pfd >= 0) {
149315648Sjoerg			delay(500);
149415648Sjoerg			break;
149515648Sjoerg		}
149615648Sjoerg		if (errno == ENOENT) {
149715648Sjoerg			syslog(LOG_ERR, "%s: %m", LP);
149815648Sjoerg			exit(1);
149915648Sjoerg		}
150015648Sjoerg		if (i == 1)
150115648Sjoerg			pstatus("waiting for %s to become ready (offline ?)",
150215648Sjoerg				printer);
150315648Sjoerg		sleep(i);
150415648Sjoerg	}
150515648Sjoerg	if (isatty(pfd))
150615648Sjoerg		setty();
150715648Sjoerg	pstatus("%s is ready and printing", printer);
150815648Sjoerg}
150915648Sjoerg
151015648Sjoerg/*
151115648Sjoerg * Printer is on a remote host
151215648Sjoerg */
151315648Sjoergstatic void
151415648Sjoergopenrem()
151515648Sjoerg{
151615648Sjoerg	register int i, n;
151715648Sjoerg	int resp, port;
151815648Sjoerg
151915648Sjoerg	for (i = 1; ; i = i < 256 ? i << 1 : i) {
152015648Sjoerg		resp = -1;
152115648Sjoerg		pfd = getport(RM, 0);
152215648Sjoerg		if (pfd >= 0) {
152315648Sjoerg			(void) sprintf(line, "\2%s\n", RP);
152415648Sjoerg			n = strlen(line);
152515648Sjoerg			if (write(pfd, line, n) == n &&
152615648Sjoerg			    (resp = response()) == '\0')
152715648Sjoerg				break;
152815648Sjoerg			(void) close(pfd);
152915648Sjoerg		}
153015648Sjoerg		if (i == 1) {
153115648Sjoerg			if (resp < 0)
153215648Sjoerg				pstatus("waiting for %s to come up", RM);
153315648Sjoerg			else {
153415648Sjoerg				pstatus("waiting for queue to be enabled on %s",
153515648Sjoerg					RM);
153615648Sjoerg				i = 256;
153715648Sjoerg			}
153815648Sjoerg		}
153915648Sjoerg		sleep(i);
154015648Sjoerg	}
154115648Sjoerg	pstatus("sending to %s", RM);
154215648Sjoerg}
154315648Sjoerg
15441553Srgrimesstruct bauds {
15451553Srgrimes	int	baud;
15461553Srgrimes	int	speed;
15471553Srgrimes} bauds[] = {
15481553Srgrimes	50,	B50,
15491553Srgrimes	75,	B75,
15501553Srgrimes	110,	B110,
15511553Srgrimes	134,	B134,
15521553Srgrimes	150,	B150,
15531553Srgrimes	200,	B200,
15541553Srgrimes	300,	B300,
15551553Srgrimes	600,	B600,
15561553Srgrimes	1200,	B1200,
15571553Srgrimes	1800,	B1800,
15581553Srgrimes	2400,	B2400,
15591553Srgrimes	4800,	B4800,
15601553Srgrimes	9600,	B9600,
15611553Srgrimes	19200,	EXTA,
15621553Srgrimes	38400,	EXTB,
15639821Swpaul	57600,	B57600,
15649821Swpaul	115200,	B115200,
15651553Srgrimes	0,	0
15661553Srgrimes};
15671553Srgrimes
15681553Srgrimes/*
15691553Srgrimes * setup tty lines.
15701553Srgrimes */
15711553Srgrimesstatic void
15721553Srgrimessetty()
15731553Srgrimes{
157415032Ssef	struct termios ttybuf;
157515032Ssef	struct bauds *bp;
15761553Srgrimes
15771553Srgrimes	if (ioctl(pfd, TIOCEXCL, (char *)0) < 0) {
15781553Srgrimes		syslog(LOG_ERR, "%s: ioctl(TIOCEXCL): %m", printer);
15791553Srgrimes		exit(1);
15801553Srgrimes	}
158115032Ssef	if (tcgetattr(pfd, &ttybuf) < 0) {
158215032Ssef		syslog(LOG_ERR, "%s: tcgetattr: %m", printer);
15831553Srgrimes		exit(1);
15841553Srgrimes	}
15851553Srgrimes	if (BR > 0) {
15861553Srgrimes		for (bp = bauds; bp->baud; bp++)
15871553Srgrimes			if (BR == bp->baud)
15881553Srgrimes				break;
15891553Srgrimes		if (!bp->baud) {
15901553Srgrimes			syslog(LOG_ERR, "%s: illegal baud rate %d", printer, BR);
15911553Srgrimes			exit(1);
15921553Srgrimes		}
159315032Ssef		cfsetspeed(&ttybuf, bp->speed);
15941553Srgrimes	}
159515032Ssef	if (MS) {
159615032Ssef		char *s = strdup(MS), *tmp;
159715032Ssef
159815032Ssef		while (tmp = strsep (&s, ",")) {
159915032Ssef			msearch(tmp, &ttybuf);
16001553Srgrimes		}
16011553Srgrimes	}
160215032Ssef	if (MS || (BR > 0)) {
160315032Ssef		if (tcsetattr(pfd, TCSAFLUSH, &ttybuf) == -1) {
160415032Ssef			syslog(LOG_ERR, "%s: tcsetattr: %m", printer);
16051553Srgrimes		}
16061553Srgrimes	}
16071553Srgrimes}
16081553Srgrimes
16091553Srgrimes#if __STDC__
16101553Srgrimes#include <stdarg.h>
16111553Srgrimes#else
16121553Srgrimes#include <varargs.h>
16131553Srgrimes#endif
16141553Srgrimes
161515648Sjoergstatic void
16161553Srgrimes#if __STDC__
16171553Srgrimespstatus(const char *msg, ...)
16181553Srgrimes#else
16191553Srgrimespstatus(msg, va_alist)
16201553Srgrimes	char *msg;
16211553Srgrimes        va_dcl
16221553Srgrimes#endif
16231553Srgrimes{
16241553Srgrimes	register int fd;
16251553Srgrimes	char buf[BUFSIZ];
16261553Srgrimes	va_list ap;
16271553Srgrimes#if __STDC__
16281553Srgrimes	va_start(ap, msg);
16291553Srgrimes#else
16301553Srgrimes	va_start(ap);
16311553Srgrimes#endif
16321553Srgrimes
16331553Srgrimes	umask(0);
16341553Srgrimes	fd = open(ST, O_WRONLY|O_CREAT, 0664);
16351553Srgrimes	if (fd < 0 || flock(fd, LOCK_EX) < 0) {
16361553Srgrimes		syslog(LOG_ERR, "%s: %s: %m", printer, ST);
16371553Srgrimes		exit(1);
16381553Srgrimes	}
16391553Srgrimes	ftruncate(fd, 0);
16401553Srgrimes	(void)vsnprintf(buf, sizeof(buf), msg, ap);
16411553Srgrimes	va_end(ap);
16421553Srgrimes	strcat(buf, "\n");
16431553Srgrimes	(void) write(fd, buf, strlen(buf));
16441553Srgrimes	(void) close(fd);
16451553Srgrimes}
1646