printjob.c revision 30407
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));
11930407Sjoergstatic void	  alarmhandler __P((int));
1201553Srgrimesstatic void       banner __P((char *, char *));
1211553Srgrimesstatic int        dofork __P((int));
1221553Srgrimesstatic int        dropit __P((int));
1231553Srgrimesstatic void       init __P((void));
1241553Srgrimesstatic void       openpr __P((void));
12515648Sjoergstatic void       opennet __P((char *));
12615648Sjoergstatic void       opentty __P((void));
12715648Sjoergstatic void       openrem __P((void));
1281553Srgrimesstatic int        print __P((int, char *));
1291553Srgrimesstatic int        printit __P((char *));
1301553Srgrimesstatic void       pstatus __P((const char *, ...));
1311553Srgrimesstatic char       response __P((void));
1321553Srgrimesstatic void       scan_out __P((int, char *, int));
1331553Srgrimesstatic char      *scnline __P((int, char *, int));
13424831Sbrianstatic int        sendfile __P((int, char *, char));
1351553Srgrimesstatic int        sendit __P((char *));
1361553Srgrimesstatic void       sendmail __P((char *, int));
1371553Srgrimesstatic void       setty __P((void));
1381553Srgrimes
1391553Srgrimesvoid
1401553Srgrimesprintjob()
1411553Srgrimes{
1421553Srgrimes	struct stat stb;
1431553Srgrimes	register struct queue *q, **qp;
1441553Srgrimes	struct queue **queue;
1451553Srgrimes	register int i, nitems;
14615648Sjoerg	off_t pidoff;
14715648Sjoerg	int errcnt, count = 0;
1481553Srgrimes
1491553Srgrimes	init();					/* set up capabilities */
1501553Srgrimes	(void) write(1, "", 1);			/* ack that daemon is started */
1511553Srgrimes	(void) close(2);			/* set up log file */
1521553Srgrimes	if (open(LF, O_WRONLY|O_APPEND, 0664) < 0) {
1531553Srgrimes		syslog(LOG_ERR, "%s: %m", LF);
1541553Srgrimes		(void) open(_PATH_DEVNULL, O_WRONLY);
1551553Srgrimes	}
1561553Srgrimes	setgid(getegid());
1571553Srgrimes	pid = getpid();				/* for use with lprm */
1581553Srgrimes	setpgrp(0, pid);
1591553Srgrimes	signal(SIGHUP, abortpr);
1601553Srgrimes	signal(SIGINT, abortpr);
1611553Srgrimes	signal(SIGQUIT, abortpr);
1621553Srgrimes	signal(SIGTERM, abortpr);
1631553Srgrimes
1641553Srgrimes	(void) mktemp(tempfile);
1651553Srgrimes
1661553Srgrimes	/*
1671553Srgrimes	 * uses short form file names
1681553Srgrimes	 */
1691553Srgrimes	if (chdir(SD) < 0) {
1701553Srgrimes		syslog(LOG_ERR, "%s: %m", SD);
1711553Srgrimes		exit(1);
1721553Srgrimes	}
1731553Srgrimes	if (stat(LO, &stb) == 0 && (stb.st_mode & 0100))
1741553Srgrimes		exit(0);		/* printing disabled */
1751553Srgrimes	lfd = open(LO, O_WRONLY|O_CREAT, 0644);
1761553Srgrimes	if (lfd < 0) {
1771553Srgrimes		syslog(LOG_ERR, "%s: %s: %m", printer, LO);
1781553Srgrimes		exit(1);
1791553Srgrimes	}
1801553Srgrimes	if (flock(lfd, LOCK_EX|LOCK_NB) < 0) {
1811553Srgrimes		if (errno == EWOULDBLOCK)	/* active deamon present */
1821553Srgrimes			exit(0);
1831553Srgrimes		syslog(LOG_ERR, "%s: %s: %m", printer, LO);
1841553Srgrimes		exit(1);
1851553Srgrimes	}
1861553Srgrimes	ftruncate(lfd, 0);
1871553Srgrimes	/*
1881553Srgrimes	 * write process id for others to know
1891553Srgrimes	 */
1901553Srgrimes	sprintf(line, "%u\n", pid);
1911553Srgrimes	pidoff = i = strlen(line);
1921553Srgrimes	if (write(lfd, line, i) != i) {
1931553Srgrimes		syslog(LOG_ERR, "%s: %s: %m", printer, LO);
1941553Srgrimes		exit(1);
1951553Srgrimes	}
1961553Srgrimes	/*
1971553Srgrimes	 * search the spool directory for work and sort by queue order.
1981553Srgrimes	 */
1991553Srgrimes	if ((nitems = getq(&queue)) < 0) {
2001553Srgrimes		syslog(LOG_ERR, "%s: can't scan %s", printer, SD);
2011553Srgrimes		exit(1);
2021553Srgrimes	}
2031553Srgrimes	if (nitems == 0)		/* no work to do */
2041553Srgrimes		exit(0);
2051553Srgrimes	if (stb.st_mode & 01) {		/* reset queue flag */
2061553Srgrimes		if (fchmod(lfd, stb.st_mode & 0776) < 0)
2071553Srgrimes			syslog(LOG_ERR, "%s: %s: %m", printer, LO);
2081553Srgrimes	}
2091553Srgrimes	openpr();			/* open printer or remote */
2101553Srgrimesagain:
2111553Srgrimes	/*
2121553Srgrimes	 * we found something to do now do it --
2131553Srgrimes	 *    write the name of the current control file into the lock file
2141553Srgrimes	 *    so the spool queue program can tell what we're working on
2151553Srgrimes	 */
2161553Srgrimes	for (qp = queue; nitems--; free((char *) q)) {
2171553Srgrimes		q = *qp++;
2181553Srgrimes		if (stat(q->q_name, &stb) < 0)
2191553Srgrimes			continue;
22015648Sjoerg		errcnt = 0;
2211553Srgrimes	restart:
22215648Sjoerg		(void) lseek(lfd, pidoff, 0);
22327748Simp		(void) snprintf(line, sizeof(line), "%s\n", q->q_name);
2241553Srgrimes		i = strlen(line);
2251553Srgrimes		if (write(lfd, line, i) != i)
2261553Srgrimes			syslog(LOG_ERR, "%s: %s: %m", printer, LO);
2271553Srgrimes		if (!remote)
2281553Srgrimes			i = printit(q->q_name);
2291553Srgrimes		else
2301553Srgrimes			i = sendit(q->q_name);
2311553Srgrimes		/*
2321553Srgrimes		 * Check to see if we are supposed to stop printing or
2331553Srgrimes		 * if we are to rebuild the queue.
2341553Srgrimes		 */
2351553Srgrimes		if (fstat(lfd, &stb) == 0) {
2361553Srgrimes			/* stop printing before starting next job? */
2371553Srgrimes			if (stb.st_mode & 0100)
2381553Srgrimes				goto done;
2391553Srgrimes			/* rebuild queue (after lpc topq) */
2401553Srgrimes			if (stb.st_mode & 01) {
2411553Srgrimes				for (free((char *) q); nitems--; free((char *) q))
2421553Srgrimes					q = *qp++;
2431553Srgrimes				if (fchmod(lfd, stb.st_mode & 0776) < 0)
2441553Srgrimes					syslog(LOG_WARNING, "%s: %s: %m",
2451553Srgrimes						printer, LO);
2461553Srgrimes				break;
2471553Srgrimes			}
2481553Srgrimes		}
2491553Srgrimes		if (i == OK)		/* file ok and printed */
2501553Srgrimes			count++;
25115648Sjoerg		else if (i == REPRINT && ++errcnt < 5) {
25215648Sjoerg			/* try reprinting the job */
2531553Srgrimes			syslog(LOG_INFO, "restarting %s", printer);
2541553Srgrimes			if (ofilter > 0) {
2551553Srgrimes				kill(ofilter, SIGCONT);	/* to be sure */
2561553Srgrimes				(void) close(ofd);
25715648Sjoerg				while ((i = wait(NULL)) > 0 && i != ofilter)
2581553Srgrimes					;
2591553Srgrimes				ofilter = 0;
2601553Srgrimes			}
2611553Srgrimes			(void) close(pfd);	/* close printer */
2621553Srgrimes			if (ftruncate(lfd, pidoff) < 0)
2631553Srgrimes				syslog(LOG_WARNING, "%s: %s: %m", printer, LO);
2641553Srgrimes			openpr();		/* try to reopen printer */
2651553Srgrimes			goto restart;
26615648Sjoerg		} else {
26715648Sjoerg			syslog(LOG_WARNING, "%s: job could not be %s (%s)", printer,
26815648Sjoerg				remote ? "sent to remote host" : "printed", q->q_name);
26915648Sjoerg			if (i == REPRINT) {
27027748Simp				/* ensure we don't attempt this job again */
27115648Sjoerg				(void) unlink(q->q_name);
27215648Sjoerg				q->q_name[0] = 'd';
27315648Sjoerg				(void) unlink(q->q_name);
27415648Sjoerg				if (logname[0])
27515648Sjoerg					sendmail(logname, FATALERR);
27615648Sjoerg			}
2771553Srgrimes		}
2781553Srgrimes	}
2791553Srgrimes	free((char *) queue);
2801553Srgrimes	/*
2811553Srgrimes	 * search the spool directory for more work.
2821553Srgrimes	 */
2831553Srgrimes	if ((nitems = getq(&queue)) < 0) {
2841553Srgrimes		syslog(LOG_ERR, "%s: can't scan %s", printer, SD);
2851553Srgrimes		exit(1);
2861553Srgrimes	}
2871553Srgrimes	if (nitems == 0) {		/* no more work to do */
2881553Srgrimes	done:
2891553Srgrimes		if (count > 0) {	/* Files actually printed */
2901553Srgrimes			if (!SF && !tof)
2911553Srgrimes				(void) write(ofd, FF, strlen(FF));
2921553Srgrimes			if (TR != NULL)		/* output trailer */
2931553Srgrimes				(void) write(ofd, TR, strlen(TR));
2941553Srgrimes		}
29519202Simp		(void) close(ofd);
29619202Simp		(void) wait(NULL);
2971553Srgrimes		(void) unlink(tempfile);
2981553Srgrimes		exit(0);
2991553Srgrimes	}
3001553Srgrimes	goto again;
3011553Srgrimes}
3021553Srgrimes
3031553Srgrimeschar	fonts[4][50];	/* fonts for troff */
3041553Srgrimes
3051553Srgrimeschar ifonts[4][40] = {
3061553Srgrimes	_PATH_VFONTR,
3071553Srgrimes	_PATH_VFONTI,
3081553Srgrimes	_PATH_VFONTB,
3091553Srgrimes	_PATH_VFONTS,
3101553Srgrimes};
3111553Srgrimes
3121553Srgrimes/*
3131553Srgrimes * The remaining part is the reading of the control file (cf)
3141553Srgrimes * and performing the various actions.
3151553Srgrimes */
3161553Srgrimesstatic int
3171553Srgrimesprintit(file)
3181553Srgrimes	char *file;
3191553Srgrimes{
3201553Srgrimes	register int i;
3211553Srgrimes	char *cp;
3221553Srgrimes	int bombed = OK;
3231553Srgrimes
3241553Srgrimes	/*
3251553Srgrimes	 * open control file; ignore if no longer there.
3261553Srgrimes	 */
3271553Srgrimes	if ((cfp = fopen(file, "r")) == NULL) {
3281553Srgrimes		syslog(LOG_INFO, "%s: %s: %m", printer, file);
3291553Srgrimes		return(OK);
3301553Srgrimes	}
3311553Srgrimes	/*
3321553Srgrimes	 * Reset troff fonts.
3331553Srgrimes	 */
3341553Srgrimes	for (i = 0; i < 4; i++)
3351553Srgrimes		strcpy(fonts[i], ifonts[i]);
33627748Simp	sprintf(&width[2], "%ld", PW);
3371553Srgrimes	strcpy(indent+2, "0");
3381553Srgrimes
3391553Srgrimes	/*
3401553Srgrimes	 *      read the control file for work to do
3411553Srgrimes	 *
3421553Srgrimes	 *      file format -- first character in the line is a command
3431553Srgrimes	 *      rest of the line is the argument.
3441553Srgrimes	 *      valid commands are:
3451553Srgrimes	 *
3461553Srgrimes	 *		S -- "stat info" for symbolic link protection
3471553Srgrimes	 *		J -- "job name" on banner page
3481553Srgrimes	 *		C -- "class name" on banner page
3491553Srgrimes	 *              L -- "literal" user's name to print on banner
3501553Srgrimes	 *		T -- "title" for pr
3511553Srgrimes	 *		H -- "host name" of machine where lpr was done
3521553Srgrimes	 *              P -- "person" user's login name
3531553Srgrimes	 *              I -- "indent" amount to indent output
35415648Sjoerg	 *		R -- laser dpi "resolution"
3551553Srgrimes	 *              f -- "file name" name of text file to print
3561553Srgrimes	 *		l -- "file name" text file with control chars
3571553Srgrimes	 *		p -- "file name" text file to print with pr(1)
3581553Srgrimes	 *		t -- "file name" troff(1) file to print
3591553Srgrimes	 *		n -- "file name" ditroff(1) file to print
3601553Srgrimes	 *		d -- "file name" dvi file to print
3611553Srgrimes	 *		g -- "file name" plot(1G) file to print
3621553Srgrimes	 *		v -- "file name" plain raster file to print
3631553Srgrimes	 *		c -- "file name" cifplot file to print
3641553Srgrimes	 *		1 -- "R font file" for troff
3651553Srgrimes	 *		2 -- "I font file" for troff
3661553Srgrimes	 *		3 -- "B font file" for troff
3671553Srgrimes	 *		4 -- "S font file" for troff
3681553Srgrimes	 *		N -- "name" of file (used by lpq)
3691553Srgrimes	 *              U -- "unlink" name of file to remove
3701553Srgrimes	 *                    (after we print it. (Pass 2 only)).
3711553Srgrimes	 *		M -- "mail" to user when done printing
3721553Srgrimes	 *
3731553Srgrimes	 *      getline reads a line and expands tabs to blanks
3741553Srgrimes	 */
3751553Srgrimes
3761553Srgrimes	/* pass 1 */
3771553Srgrimes
3781553Srgrimes	while (getline(cfp))
3791553Srgrimes		switch (line[0]) {
3801553Srgrimes		case 'H':
38127748Simp			strncpy(fromhost, line+1, sizeof(fromhost) - 1);
38227748Simp			fromhost[sizeof(fromhost) - 1] = '\0';
38327748Simp			if (class[0] == '\0') {
38427748Simp				strncpy(class, line+1, sizeof(class) - 1);
38527748Simp				class[sizeof(class) - 1] = '\0';
38627748Simp			}
3871553Srgrimes			continue;
3881553Srgrimes
3891553Srgrimes		case 'P':
39027748Simp			strncpy(logname, line+1, sizeof(logname) - 1);
39127748Simp			logname[sizeof(logname) - 1] = '\0';
3921553Srgrimes			if (RS) {			/* restricted */
3931553Srgrimes				if (getpwnam(logname) == NULL) {
3941553Srgrimes					bombed = NOACCT;
3951553Srgrimes					sendmail(line+1, bombed);
3961553Srgrimes					goto pass2;
3971553Srgrimes				}
3981553Srgrimes			}
3991553Srgrimes			continue;
4001553Srgrimes
4011553Srgrimes		case 'S':
4021553Srgrimes			cp = line+1;
4031553Srgrimes			i = 0;
4041553Srgrimes			while (*cp >= '0' && *cp <= '9')
4051553Srgrimes				i = i * 10 + (*cp++ - '0');
4061553Srgrimes			fdev = i;
4071553Srgrimes			cp++;
4081553Srgrimes			i = 0;
4091553Srgrimes			while (*cp >= '0' && *cp <= '9')
4101553Srgrimes				i = i * 10 + (*cp++ - '0');
4111553Srgrimes			fino = i;
4121553Srgrimes			continue;
4131553Srgrimes
4141553Srgrimes		case 'J':
41527748Simp			if (line[1] != '\0') {
41627748Simp				strncpy(jobname, line+1, sizeof(jobname) - 1);
41727748Simp				jobname[sizeof(jobname) - 1] = '\0';
41827748Simp			} else
4191553Srgrimes				strcpy(jobname, " ");
4201553Srgrimes			continue;
4211553Srgrimes
4221553Srgrimes		case 'C':
4231553Srgrimes			if (line[1] != '\0')
42427748Simp				strncpy(class, line+1, sizeof(class) - 1);
4251553Srgrimes			else if (class[0] == '\0')
4261553Srgrimes				gethostname(class, sizeof(class));
42727748Simp			class[sizeof(class) - 1] = '\0';
4281553Srgrimes			continue;
4291553Srgrimes
4301553Srgrimes		case 'T':	/* header title for pr */
43127748Simp			strncpy(title, line+1, sizeof(title) - 1);
43227748Simp			title[sizeof(title) - 1] = '\0';
4331553Srgrimes			continue;
4341553Srgrimes
4351553Srgrimes		case 'L':	/* identification line */
4361553Srgrimes			if (!SH && !HL)
4371553Srgrimes				banner(line+1, jobname);
4381553Srgrimes			continue;
4391553Srgrimes
4401553Srgrimes		case '1':	/* troff fonts */
4411553Srgrimes		case '2':
4421553Srgrimes		case '3':
4431553Srgrimes		case '4':
44427748Simp			if (line[1] != '\0') {
44527748Simp				strncpy(fonts[line[0]-'1'], line+1,
44627748Simp				    50-1);
44727748Simp				fonts[line[0]-'1'][50-1] = '\0';
44827748Simp			}
4491553Srgrimes			continue;
4501553Srgrimes
4511553Srgrimes		case 'W':	/* page width */
45227748Simp			strncpy(width+2, line+1, sizeof(width) - 3);
45327748Simp			width[2+sizeof(width) - 3] = '\0';
4541553Srgrimes			continue;
4551553Srgrimes
4561553Srgrimes		case 'I':	/* indent amount */
45727748Simp			strncpy(indent+2, line+1, sizeof(indent) - 3);
45827748Simp			indent[2+sizeof(indent) - 3] = '\0';
4591553Srgrimes			continue;
4601553Srgrimes
4611553Srgrimes		default:	/* some file to print */
4621553Srgrimes			switch (i = print(line[0], line+1)) {
4631553Srgrimes			case ERROR:
4641553Srgrimes				if (bombed == OK)
4651553Srgrimes					bombed = FATALERR;
4661553Srgrimes				break;
4671553Srgrimes			case REPRINT:
4681553Srgrimes				(void) fclose(cfp);
4691553Srgrimes				return(REPRINT);
4701553Srgrimes			case FILTERERR:
4711553Srgrimes			case ACCESS:
4721553Srgrimes				bombed = i;
4731553Srgrimes				sendmail(logname, bombed);
4741553Srgrimes			}
4751553Srgrimes			title[0] = '\0';
4761553Srgrimes			continue;
4771553Srgrimes
4781553Srgrimes		case 'N':
4791553Srgrimes		case 'U':
4801553Srgrimes		case 'M':
48115648Sjoerg		case 'R':
4821553Srgrimes			continue;
4831553Srgrimes		}
4841553Srgrimes
4851553Srgrimes	/* pass 2 */
4861553Srgrimes
4871553Srgrimespass2:
4881553Srgrimes	fseek(cfp, 0L, 0);
4891553Srgrimes	while (getline(cfp))
4901553Srgrimes		switch (line[0]) {
4911553Srgrimes		case 'L':	/* identification line */
4921553Srgrimes			if (!SH && HL)
4931553Srgrimes				banner(line+1, jobname);
4941553Srgrimes			continue;
4951553Srgrimes
4961553Srgrimes		case 'M':
4971553Srgrimes			if (bombed < NOACCT)	/* already sent if >= NOACCT */
4981553Srgrimes				sendmail(line+1, bombed);
4991553Srgrimes			continue;
5001553Srgrimes
5011553Srgrimes		case 'U':
50227748Simp			if (strchr(line+1, '/'))
50327748Simp				continue;
5041553Srgrimes			(void) unlink(line+1);
5051553Srgrimes		}
5061553Srgrimes	/*
5071553Srgrimes	 * clean-up in case another control file exists
5081553Srgrimes	 */
5091553Srgrimes	(void) fclose(cfp);
5101553Srgrimes	(void) unlink(file);
5111553Srgrimes	return(bombed == OK ? OK : ERROR);
5121553Srgrimes}
5131553Srgrimes
5141553Srgrimes/*
5151553Srgrimes * Print a file.
5161553Srgrimes * Set up the chain [ PR [ | {IF, OF} ] ] or {IF, RF, TF, NF, DF, CF, VF}.
5171553Srgrimes * Return -1 if a non-recoverable error occured,
5181553Srgrimes * 2 if the filter detected some errors (but printed the job anyway),
5191553Srgrimes * 1 if we should try to reprint this job and
5201553Srgrimes * 0 if all is well.
5211553Srgrimes * Note: all filters take stdin as the file, stdout as the printer,
5221553Srgrimes * stderr as the log file, and must not ignore SIGINT.
5231553Srgrimes */
5241553Srgrimesstatic int
5251553Srgrimesprint(format, file)
5261553Srgrimes	int format;
5271553Srgrimes	char *file;
5281553Srgrimes{
5291553Srgrimes	register int n;
5301553Srgrimes	register char *prog;
53118569Sbde	int dtablesize, fi, fo;
5321553Srgrimes	FILE *fp;
5331553Srgrimes	char *av[15], buf[BUFSIZ];
5341553Srgrimes	int pid, p[2], stopped = 0;
5351553Srgrimes	union wait status;
5361553Srgrimes	struct stat stb;
5371553Srgrimes
5381553Srgrimes	if (lstat(file, &stb) < 0 || (fi = open(file, O_RDONLY)) < 0)
5391553Srgrimes		return(ERROR);
5401553Srgrimes	/*
5411553Srgrimes	 * Check to see if data file is a symbolic link. If so, it should
5421553Srgrimes	 * still point to the same file or someone is trying to print
5431553Srgrimes	 * something he shouldn't.
5441553Srgrimes	 */
5451553Srgrimes	if ((stb.st_mode & S_IFMT) == S_IFLNK && fstat(fi, &stb) == 0 &&
5461553Srgrimes	    (stb.st_dev != fdev || stb.st_ino != fino))
5471553Srgrimes		return(ACCESS);
5481553Srgrimes	if (!SF && !tof) {		/* start on a fresh page */
5491553Srgrimes		(void) write(ofd, FF, strlen(FF));
5501553Srgrimes		tof = 1;
5511553Srgrimes	}
5521553Srgrimes	if (IF == NULL && (format == 'f' || format == 'l')) {
5531553Srgrimes		tof = 0;
5541553Srgrimes		while ((n = read(fi, buf, BUFSIZ)) > 0)
5551553Srgrimes			if (write(ofd, buf, n) != n) {
5561553Srgrimes				(void) close(fi);
5571553Srgrimes				return(REPRINT);
5581553Srgrimes			}
5591553Srgrimes		(void) close(fi);
5601553Srgrimes		return(OK);
5611553Srgrimes	}
5621553Srgrimes	switch (format) {
5631553Srgrimes	case 'p':	/* print file using 'pr' */
5641553Srgrimes		if (IF == NULL) {	/* use output filter */
5651553Srgrimes			prog = _PATH_PR;
5661553Srgrimes			av[0] = "pr";
5671553Srgrimes			av[1] = width;
5681553Srgrimes			av[2] = length;
5691553Srgrimes			av[3] = "-h";
5701553Srgrimes			av[4] = *title ? title : " ";
5715445Sjoerg			av[5] = "-F";
5725445Sjoerg			av[6] = 0;
5731553Srgrimes			fo = ofd;
5741553Srgrimes			goto start;
5751553Srgrimes		}
5761553Srgrimes		pipe(p);
5771553Srgrimes		if ((prchild = dofork(DORETURN)) == 0) {	/* child */
5781553Srgrimes			dup2(fi, 0);		/* file is stdin */
5791553Srgrimes			dup2(p[1], 1);		/* pipe is stdout */
5808094Sjkh			closelog();
58118569Sbde			for (n = 3, dtablesize = getdtablesize();
58218569Sbde			     n < dtablesize; n++)
5831553Srgrimes				(void) close(n);
5841553Srgrimes			execl(_PATH_PR, "pr", width, length,
5855445Sjoerg			    "-h", *title ? title : " ", "-F", 0);
5861553Srgrimes			syslog(LOG_ERR, "cannot execl %s", _PATH_PR);
5871553Srgrimes			exit(2);
5881553Srgrimes		}
5891553Srgrimes		(void) close(p[1]);		/* close output side */
5901553Srgrimes		(void) close(fi);
5911553Srgrimes		if (prchild < 0) {
5921553Srgrimes			prchild = 0;
5931553Srgrimes			(void) close(p[0]);
5941553Srgrimes			return(ERROR);
5951553Srgrimes		}
5961553Srgrimes		fi = p[0];			/* use pipe for input */
5971553Srgrimes	case 'f':	/* print plain text file */
5981553Srgrimes		prog = IF;
5991553Srgrimes		av[1] = width;
6001553Srgrimes		av[2] = length;
6011553Srgrimes		av[3] = indent;
6021553Srgrimes		n = 4;
6031553Srgrimes		break;
6041553Srgrimes	case 'l':	/* like 'f' but pass control characters */
6051553Srgrimes		prog = IF;
6061553Srgrimes		av[1] = "-c";
6071553Srgrimes		av[2] = width;
6081553Srgrimes		av[3] = length;
6091553Srgrimes		av[4] = indent;
6101553Srgrimes		n = 5;
6111553Srgrimes		break;
6121553Srgrimes	case 'r':	/* print a fortran text file */
6131553Srgrimes		prog = RF;
6141553Srgrimes		av[1] = width;
6151553Srgrimes		av[2] = length;
6161553Srgrimes		n = 3;
6171553Srgrimes		break;
6181553Srgrimes	case 't':	/* print troff output */
6191553Srgrimes	case 'n':	/* print ditroff output */
6201553Srgrimes	case 'd':	/* print tex output */
6211553Srgrimes		(void) unlink(".railmag");
6221553Srgrimes		if ((fo = creat(".railmag", FILMOD)) < 0) {
6231553Srgrimes			syslog(LOG_ERR, "%s: cannot create .railmag", printer);
6241553Srgrimes			(void) unlink(".railmag");
6251553Srgrimes		} else {
6261553Srgrimes			for (n = 0; n < 4; n++) {
6271553Srgrimes				if (fonts[n][0] != '/')
6281553Srgrimes					(void) write(fo, _PATH_VFONT,
6291553Srgrimes					    sizeof(_PATH_VFONT) - 1);
6301553Srgrimes				(void) write(fo, fonts[n], strlen(fonts[n]));
6311553Srgrimes				(void) write(fo, "\n", 1);
6321553Srgrimes			}
6331553Srgrimes			(void) close(fo);
6341553Srgrimes		}
6351553Srgrimes		prog = (format == 't') ? TF : (format == 'n') ? NF : DF;
6361553Srgrimes		av[1] = pxwidth;
6371553Srgrimes		av[2] = pxlength;
6381553Srgrimes		n = 3;
6391553Srgrimes		break;
6401553Srgrimes	case 'c':	/* print cifplot output */
6411553Srgrimes		prog = CF;
6421553Srgrimes		av[1] = pxwidth;
6431553Srgrimes		av[2] = pxlength;
6441553Srgrimes		n = 3;
6451553Srgrimes		break;
6461553Srgrimes	case 'g':	/* print plot(1G) output */
6471553Srgrimes		prog = GF;
6481553Srgrimes		av[1] = pxwidth;
6491553Srgrimes		av[2] = pxlength;
6501553Srgrimes		n = 3;
6511553Srgrimes		break;
6521553Srgrimes	case 'v':	/* print raster output */
6531553Srgrimes		prog = VF;
6541553Srgrimes		av[1] = pxwidth;
6551553Srgrimes		av[2] = pxlength;
6561553Srgrimes		n = 3;
6571553Srgrimes		break;
6581553Srgrimes	default:
6591553Srgrimes		(void) close(fi);
6601553Srgrimes		syslog(LOG_ERR, "%s: illegal format character '%c'",
6611553Srgrimes			printer, format);
6621553Srgrimes		return(ERROR);
6631553Srgrimes	}
66415648Sjoerg	if (prog == NULL) {
66515648Sjoerg		(void) close(fi);
66615648Sjoerg		syslog(LOG_ERR,
66715648Sjoerg		   "%s: no filter found in printcap for format character '%c'",
66815648Sjoerg		   printer, format);
66915648Sjoerg		return(ERROR);
67015648Sjoerg	}
67127635Simp	if ((av[0] = strrchr(prog, '/')) != NULL)
6721553Srgrimes		av[0]++;
6731553Srgrimes	else
6741553Srgrimes		av[0] = prog;
6751553Srgrimes	av[n++] = "-n";
6761553Srgrimes	av[n++] = logname;
6771553Srgrimes	av[n++] = "-h";
6781553Srgrimes	av[n++] = fromhost;
6791553Srgrimes	av[n++] = AF;
6801553Srgrimes	av[n] = 0;
6811553Srgrimes	fo = pfd;
6821553Srgrimes	if (ofilter > 0) {		/* stop output filter */
6831553Srgrimes		write(ofd, "\031\1", 2);
6841553Srgrimes		while ((pid =
6851553Srgrimes		    wait3((int *)&status, WUNTRACED, 0)) > 0 && pid != ofilter)
6861553Srgrimes			;
6871553Srgrimes		if (status.w_stopval != WSTOPPED) {
6881553Srgrimes			(void) close(fi);
68915648Sjoerg			syslog(LOG_WARNING,
69015648Sjoerg				"%s: output filter died (retcode=%d termsig=%d)",
69115648Sjoerg				printer, status.w_retcode, status.w_termsig);
6921553Srgrimes			return(REPRINT);
6931553Srgrimes		}
6941553Srgrimes		stopped++;
6951553Srgrimes	}
6961553Srgrimesstart:
6971553Srgrimes	if ((child = dofork(DORETURN)) == 0) {	/* child */
6981553Srgrimes		dup2(fi, 0);
6991553Srgrimes		dup2(fo, 1);
7001553Srgrimes		n = open(tempfile, O_WRONLY|O_CREAT|O_TRUNC, 0664);
7011553Srgrimes		if (n >= 0)
7021553Srgrimes			dup2(n, 2);
7038094Sjkh		closelog();
70418569Sbde		for (n = 3, dtablesize = getdtablesize(); n < dtablesize; n++)
7051553Srgrimes			(void) close(n);
7061553Srgrimes		execv(prog, av);
7071553Srgrimes		syslog(LOG_ERR, "cannot execv %s", prog);
7081553Srgrimes		exit(2);
7091553Srgrimes	}
7101553Srgrimes	(void) close(fi);
7111553Srgrimes	if (child < 0)
7121553Srgrimes		status.w_retcode = 100;
7131553Srgrimes	else
7141553Srgrimes		while ((pid = wait((int *)&status)) > 0 && pid != child)
7151553Srgrimes			;
7161553Srgrimes	child = 0;
7171553Srgrimes	prchild = 0;
7181553Srgrimes	if (stopped) {		/* restart output filter */
7191553Srgrimes		if (kill(ofilter, SIGCONT) < 0) {
7201553Srgrimes			syslog(LOG_ERR, "cannot restart output filter");
7211553Srgrimes			exit(1);
7221553Srgrimes		}
7231553Srgrimes	}
7241553Srgrimes	tof = 0;
7251553Srgrimes
7261553Srgrimes	/* Copy filter output to "lf" logfile */
72727748Simp	if ((fp = fopen(tempfile, "r"))) {
7281553Srgrimes		while (fgets(buf, sizeof(buf), fp))
7291553Srgrimes			fputs(buf, stderr);
7301553Srgrimes		fclose(fp);
7311553Srgrimes	}
7321553Srgrimes
7331553Srgrimes	if (!WIFEXITED(status)) {
73415648Sjoerg		syslog(LOG_WARNING, "%s: filter '%c' terminated (termsig=%d)",
7351553Srgrimes			printer, format, status.w_termsig);
7361553Srgrimes		return(ERROR);
7371553Srgrimes	}
7381553Srgrimes	switch (status.w_retcode) {
7391553Srgrimes	case 0:
7401553Srgrimes		tof = 1;
7411553Srgrimes		return(OK);
7421553Srgrimes	case 1:
7431553Srgrimes		return(REPRINT);
74415648Sjoerg	case 2:
74515648Sjoerg		return(ERROR);
7461553Srgrimes	default:
74715648Sjoerg		syslog(LOG_WARNING, "%s: filter '%c' exited (retcode=%d)",
7481553Srgrimes			printer, format, status.w_retcode);
74915648Sjoerg		return(FILTERERR);
7501553Srgrimes	}
7511553Srgrimes}
7521553Srgrimes
7531553Srgrimes/*
7541553Srgrimes * Send the daemon control file (cf) and any data files.
7551553Srgrimes * Return -1 if a non-recoverable error occured, 1 if a recoverable error and
7561553Srgrimes * 0 if all is well.
7571553Srgrimes */
7581553Srgrimesstatic int
7591553Srgrimessendit(file)
7601553Srgrimes	char *file;
7611553Srgrimes{
7621553Srgrimes	register int i, err = OK;
7631553Srgrimes	char *cp, last[BUFSIZ];
7641553Srgrimes
7651553Srgrimes	/*
7661553Srgrimes	 * open control file
7671553Srgrimes	 */
7681553Srgrimes	if ((cfp = fopen(file, "r")) == NULL)
7691553Srgrimes		return(OK);
7701553Srgrimes	/*
7711553Srgrimes	 *      read the control file for work to do
7721553Srgrimes	 *
7731553Srgrimes	 *      file format -- first character in the line is a command
7741553Srgrimes	 *      rest of the line is the argument.
7751553Srgrimes	 *      commands of interest are:
7761553Srgrimes	 *
7771553Srgrimes	 *            a-z -- "file name" name of file to print
7781553Srgrimes	 *              U -- "unlink" name of file to remove
7791553Srgrimes	 *                    (after we print it. (Pass 2 only)).
7801553Srgrimes	 */
7811553Srgrimes
7821553Srgrimes	/*
7831553Srgrimes	 * pass 1
7841553Srgrimes	 */
7851553Srgrimes	while (getline(cfp)) {
7861553Srgrimes	again:
7871553Srgrimes		if (line[0] == 'S') {
7881553Srgrimes			cp = line+1;
7891553Srgrimes			i = 0;
7901553Srgrimes			while (*cp >= '0' && *cp <= '9')
7911553Srgrimes				i = i * 10 + (*cp++ - '0');
7921553Srgrimes			fdev = i;
7931553Srgrimes			cp++;
7941553Srgrimes			i = 0;
7951553Srgrimes			while (*cp >= '0' && *cp <= '9')
7961553Srgrimes				i = i * 10 + (*cp++ - '0');
7971553Srgrimes			fino = i;
79824831Sbrian		} else if (line[0] == 'H') {
79924831Sbrian			strcpy(fromhost, line+1);
80024831Sbrian			if (class[0] == '\0')
80127748Simp				strncpy(class, line+1, sizeof(class) - 1);
80224831Sbrian		} else if (line[0] == 'P') {
80327748Simp			strncpy(logname, line+1, sizeof(logname) - 1);
80424831Sbrian			if (RS) {			/* restricted */
80524831Sbrian				if (getpwnam(logname) == NULL) {
80624831Sbrian					sendmail(line+1, NOACCT);
80724831Sbrian					err = ERROR;
80824831Sbrian					break;
80924831Sbrian				}
81024831Sbrian			}
81124831Sbrian		} else if (line[0] == 'I') {
81227748Simp			strncpy(indent+2, line+1, sizeof(indent) - 3);
81324831Sbrian		} else if (line[0] >= 'a' && line[0] <= 'z') {
8141553Srgrimes			strcpy(last, line);
8151553Srgrimes			while (i = getline(cfp))
8161553Srgrimes				if (strcmp(last, line))
8171553Srgrimes					break;
81824831Sbrian			switch (sendfile('\3', last+1, *last)) {
8191553Srgrimes			case OK:
8201553Srgrimes				if (i)
8211553Srgrimes					goto again;
8221553Srgrimes				break;
8231553Srgrimes			case REPRINT:
8241553Srgrimes				(void) fclose(cfp);
8251553Srgrimes				return(REPRINT);
8261553Srgrimes			case ACCESS:
8271553Srgrimes				sendmail(logname, ACCESS);
8281553Srgrimes			case ERROR:
8291553Srgrimes				err = ERROR;
8301553Srgrimes			}
8311553Srgrimes			break;
8321553Srgrimes		}
8331553Srgrimes	}
83424831Sbrian	if (err == OK && sendfile('\2', file, '\0') > 0) {
8351553Srgrimes		(void) fclose(cfp);
8361553Srgrimes		return(REPRINT);
8371553Srgrimes	}
8381553Srgrimes	/*
8391553Srgrimes	 * pass 2
8401553Srgrimes	 */
8411553Srgrimes	fseek(cfp, 0L, 0);
8421553Srgrimes	while (getline(cfp))
84327748Simp		if (line[0] == 'U' && !strchr(line+1, '/'))
8441553Srgrimes			(void) unlink(line+1);
8451553Srgrimes	/*
8461553Srgrimes	 * clean-up in case another control file exists
8471553Srgrimes	 */
8481553Srgrimes	(void) fclose(cfp);
8491553Srgrimes	(void) unlink(file);
8501553Srgrimes	return(err);
8511553Srgrimes}
8521553Srgrimes
8531553Srgrimes/*
8541553Srgrimes * Send a data file to the remote machine and spool it.
8551553Srgrimes * Return positive if we should try resending.
8561553Srgrimes */
8571553Srgrimesstatic int
85824831Sbriansendfile(type, file, format)
8591553Srgrimes	int type;
8601553Srgrimes	char *file;
86124831Sbrian	char format;
8621553Srgrimes{
8631553Srgrimes	register int f, i, amt;
8641553Srgrimes	struct stat stb;
8651553Srgrimes	char buf[BUFSIZ];
86624831Sbrian	int sizerr, resp, closedpr;
8671553Srgrimes
8681553Srgrimes	if (lstat(file, &stb) < 0 || (f = open(file, O_RDONLY)) < 0)
8691553Srgrimes		return(ERROR);
8701553Srgrimes	/*
8711553Srgrimes	 * Check to see if data file is a symbolic link. If so, it should
8721553Srgrimes	 * still point to the same file or someone is trying to print something
8731553Srgrimes	 * he shouldn't.
8741553Srgrimes	 */
8751553Srgrimes	if ((stb.st_mode & S_IFMT) == S_IFLNK && fstat(f, &stb) == 0 &&
8761553Srgrimes	    (stb.st_dev != fdev || stb.st_ino != fino))
8771553Srgrimes		return(ACCESS);
87824831Sbrian
87924831Sbrian	sizerr = 0;
88024831Sbrian	closedpr = 0;
88124831Sbrian	if (type == '\3') {
88224831Sbrian		if (IF) {
88324831Sbrian			/*
88424831Sbrian			 * We're sending something with an ifilter, we have to
88524831Sbrian			 * run the ifilter and store the output as a
88624831Sbrian			 * temporary file (tfile)... the protocol requires us
88724831Sbrian			 * to send the file size
88824831Sbrian			 */
88924831Sbrian			char *av[15];
89024831Sbrian			int n;
89124831Sbrian			int nfd;
89224831Sbrian			int ifilter;
89324831Sbrian			union wait status;
89424831Sbrian
89524831Sbrian			strcpy(tfile,TFILENAME);
89624831Sbrian			if ((tfd = mkstemp(tfile)) == -1) {
89724831Sbrian				syslog(LOG_ERR, "mkstemp: %m");
89824831Sbrian				return(ERROR);
89924831Sbrian			}
90027635Simp			if ((av[0] = strrchr(IF, '/')) == NULL)
90124831Sbrian				av[0] = IF;
90224831Sbrian			else
90324831Sbrian				av[0]++;
90424831Sbrian			if (format == 'l')
90524831Sbrian				av[n=1] = "-c";
90624831Sbrian			else
90724831Sbrian				n = 0;
90824831Sbrian			av[++n] = width;
90924831Sbrian			av[++n] = length;
91024831Sbrian			av[++n] = indent;
91124831Sbrian			av[++n] = "-n";
91224831Sbrian			av[++n] = logname;
91324831Sbrian			av[++n] = "-h";
91424831Sbrian			av[++n] = fromhost;
91524831Sbrian			av[++n] = AF;
91624831Sbrian			av[++n] = 0;
91724831Sbrian			if ((ifilter = dofork(DORETURN)) == 0) {  /* child */
91824831Sbrian				dup2(f, 0);
91924831Sbrian				dup2(tfd, 1);
92024831Sbrian				n = open(tempfile, O_WRONLY|O_CREAT|O_TRUNC, 0664);
92124831Sbrian				if (n >= 0)
92224831Sbrian					dup2(n, 2);
92324831Sbrian				closelog();
92424831Sbrian				for (n = 3, nfd = getdtablesize(); n < nfd; n++)
92524831Sbrian					(void) close(n);
92624831Sbrian				execv(IF, av);
92724831Sbrian				syslog(LOG_ERR, "cannot execv %s", IF);
92824831Sbrian				exit(2);
92924831Sbrian			}
93024831Sbrian			(void) close(f);
93124831Sbrian			if (ifilter < 0)
93224831Sbrian				status.w_retcode = 100;
93324831Sbrian			else
93424831Sbrian				while ((pid = wait((int *)&status)) > 0 &&
93524831Sbrian					pid != ifilter)
93624831Sbrian					;
93724831Sbrian			switch (status.w_retcode) {
93824831Sbrian			case 0:
93924831Sbrian				break;
94024831Sbrian			case 1:
94124831Sbrian				unlink(tfile);
94224831Sbrian				return(REPRINT);
94324831Sbrian			case 2:
94424831Sbrian				unlink(tfile);
94524831Sbrian				return(ERROR);
94624831Sbrian			default:
94724831Sbrian				syslog(LOG_WARNING, "%s: filter '%c' exited"
94824831Sbrian					" (retcode=%d)",
94924831Sbrian					printer, format, status.w_retcode);
95024831Sbrian				unlink(tfile);
95124831Sbrian				return(FILTERERR);
95224831Sbrian			}
95324831Sbrian			if (fstat(tfd, &stb) < 0)	/* the size of tfile */
95424831Sbrian				return(ERROR);
95524831Sbrian			f = tfd;
95624831Sbrian			lseek(f,0,SEEK_SET);
95724831Sbrian		} else if (ofilter) {
95824831Sbrian			/*
95924831Sbrian			 * We're sending something with an ofilter, we have to
96024831Sbrian			 * store the output as a temporary file (tfile)... the
96124831Sbrian			 * protocol requires us to send the file size
96224831Sbrian			 */
96324831Sbrian			int i;
96424831Sbrian			for (i = 0; i < stb.st_size; i += BUFSIZ) {
96524831Sbrian				amt = BUFSIZ;
96624831Sbrian				if (i + amt > stb.st_size)
96724831Sbrian					amt = stb.st_size - i;
96824831Sbrian				if (sizerr == 0 && read(f, buf, amt) != amt) {
96924831Sbrian					sizerr = 1;
97024831Sbrian					break;
97124831Sbrian				}
97224831Sbrian				if (write(ofd, buf, amt) != amt) {
97324831Sbrian					(void) close(f);
97424831Sbrian					return(REPRINT);
97524831Sbrian				}
97624831Sbrian			}
97724831Sbrian			close(ofd);
97824831Sbrian			close(f);
97924831Sbrian			while ((i = wait(NULL)) > 0 && i != ofilter)
98024831Sbrian				;
98124831Sbrian			ofilter = 0;
98224831Sbrian			if (fstat(tfd, &stb) < 0) {	/* the size of tfile */
98324831Sbrian				openpr();
98424831Sbrian				return(ERROR);
98524831Sbrian			}
98624831Sbrian			f = tfd;
98724831Sbrian			lseek(f,0,SEEK_SET);
98824831Sbrian			closedpr = 1;
98924831Sbrian		}
99024831Sbrian	}
99124831Sbrian
9921553Srgrimes	(void) sprintf(buf, "%c%qd %s\n", type, stb.st_size, file);
9931553Srgrimes	amt = strlen(buf);
9941553Srgrimes	for (i = 0;  ; i++) {
9951553Srgrimes		if (write(pfd, buf, amt) != amt ||
9961553Srgrimes		    (resp = response()) < 0 || resp == '\1') {
9971553Srgrimes			(void) close(f);
99824831Sbrian			if (tfd != -1 && type == '\3') {
99924831Sbrian				tfd = -1;
100024831Sbrian				unlink(tfile);
100124831Sbrian				if (closedpr)
100224831Sbrian					openpr();
100324831Sbrian			}
10041553Srgrimes			return(REPRINT);
10051553Srgrimes		} else if (resp == '\0')
10061553Srgrimes			break;
10071553Srgrimes		if (i == 0)
10081553Srgrimes			pstatus("no space on remote; waiting for queue to drain");
10091553Srgrimes		if (i == 10)
10101553Srgrimes			syslog(LOG_ALERT, "%s: can't send to %s; queue full",
10111553Srgrimes				printer, RM);
10121553Srgrimes		sleep(5 * 60);
10131553Srgrimes	}
10141553Srgrimes	if (i)
10151553Srgrimes		pstatus("sending to %s", RM);
10161553Srgrimes	for (i = 0; i < stb.st_size; i += BUFSIZ) {
10171553Srgrimes		amt = BUFSIZ;
10181553Srgrimes		if (i + amt > stb.st_size)
10191553Srgrimes			amt = stb.st_size - i;
10201553Srgrimes		if (sizerr == 0 && read(f, buf, amt) != amt)
10211553Srgrimes			sizerr = 1;
10221553Srgrimes		if (write(pfd, buf, amt) != amt) {
10231553Srgrimes			(void) close(f);
102424831Sbrian			if (tfd != -1 && type == '\3') {
102524831Sbrian				tfd = -1;
102624831Sbrian				unlink(tfile);
102724831Sbrian				if (closedpr)
102824831Sbrian					openpr();
102924831Sbrian			}
10301553Srgrimes			return(REPRINT);
10311553Srgrimes		}
10321553Srgrimes	}
10331553Srgrimes
10341553Srgrimes	(void) close(f);
103524831Sbrian	if (tfd != -1 && type == '\3') {
103624831Sbrian		tfd = -1;
103724831Sbrian		unlink(tfile);
103824831Sbrian	}
10391553Srgrimes	if (sizerr) {
10401553Srgrimes		syslog(LOG_INFO, "%s: %s: changed size", printer, file);
10411553Srgrimes		/* tell recvjob to ignore this file */
10421553Srgrimes		(void) write(pfd, "\1", 1);
104324831Sbrian		if (closedpr)
104424831Sbrian			openpr();
10451553Srgrimes		return(ERROR);
10461553Srgrimes	}
104724831Sbrian	if (write(pfd, "", 1) != 1 || response()) {
104824831Sbrian		if (closedpr)
104924831Sbrian			openpr();
10501553Srgrimes		return(REPRINT);
105124831Sbrian	}
105224831Sbrian	if (closedpr)
105324831Sbrian		openpr();
10541553Srgrimes	return(OK);
10551553Srgrimes}
10561553Srgrimes
10571553Srgrimes/*
10581553Srgrimes * Check to make sure there have been no errors and that both programs
10591553Srgrimes * are in sync with eachother.
10601553Srgrimes * Return non-zero if the connection was lost.
10611553Srgrimes */
10621553Srgrimesstatic char
10631553Srgrimesresponse()
10641553Srgrimes{
10651553Srgrimes	char resp;
10661553Srgrimes
10671553Srgrimes	if (read(pfd, &resp, 1) != 1) {
10681553Srgrimes		syslog(LOG_INFO, "%s: lost connection", printer);
10691553Srgrimes		return(-1);
10701553Srgrimes	}
10711553Srgrimes	return(resp);
10721553Srgrimes}
10731553Srgrimes
10741553Srgrimes/*
10751553Srgrimes * Banner printing stuff
10761553Srgrimes */
10771553Srgrimesstatic void
10781553Srgrimesbanner(name1, name2)
10791553Srgrimes	char *name1, *name2;
10801553Srgrimes{
10811553Srgrimes	time_t tvec;
10821553Srgrimes
10831553Srgrimes	time(&tvec);
10841553Srgrimes	if (!SF && !tof)
10851553Srgrimes		(void) write(ofd, FF, strlen(FF));
10861553Srgrimes	if (SB) {	/* short banner only */
10871553Srgrimes		if (class[0]) {
10881553Srgrimes			(void) write(ofd, class, strlen(class));
10891553Srgrimes			(void) write(ofd, ":", 1);
10901553Srgrimes		}
10911553Srgrimes		(void) write(ofd, name1, strlen(name1));
10921553Srgrimes		(void) write(ofd, "  Job: ", 7);
10931553Srgrimes		(void) write(ofd, name2, strlen(name2));
10941553Srgrimes		(void) write(ofd, "  Date: ", 8);
10951553Srgrimes		(void) write(ofd, ctime(&tvec), 24);
10961553Srgrimes		(void) write(ofd, "\n", 1);
10971553Srgrimes	} else {	/* normal banner */
10981553Srgrimes		(void) write(ofd, "\n\n\n", 3);
10991553Srgrimes		scan_out(ofd, name1, '\0');
11001553Srgrimes		(void) write(ofd, "\n\n", 2);
11011553Srgrimes		scan_out(ofd, name2, '\0');
11021553Srgrimes		if (class[0]) {
11031553Srgrimes			(void) write(ofd,"\n\n\n",3);
11041553Srgrimes			scan_out(ofd, class, '\0');
11051553Srgrimes		}
11061553Srgrimes		(void) write(ofd, "\n\n\n\n\t\t\t\t\tJob:  ", 15);
11071553Srgrimes		(void) write(ofd, name2, strlen(name2));
11081553Srgrimes		(void) write(ofd, "\n\t\t\t\t\tDate: ", 12);
11091553Srgrimes		(void) write(ofd, ctime(&tvec), 24);
11101553Srgrimes		(void) write(ofd, "\n", 1);
11111553Srgrimes	}
11121553Srgrimes	if (!SF)
11131553Srgrimes		(void) write(ofd, FF, strlen(FF));
11141553Srgrimes	tof = 1;
11151553Srgrimes}
11161553Srgrimes
11171553Srgrimesstatic char *
11181553Srgrimesscnline(key, p, c)
11191553Srgrimes	register int key;
11201553Srgrimes	register char *p;
11211553Srgrimes	int c;
11221553Srgrimes{
11231553Srgrimes	register scnwidth;
11241553Srgrimes
11251553Srgrimes	for (scnwidth = WIDTH; --scnwidth;) {
11261553Srgrimes		key <<= 1;
11271553Srgrimes		*p++ = key & 0200 ? c : BACKGND;
11281553Srgrimes	}
11291553Srgrimes	return (p);
11301553Srgrimes}
11311553Srgrimes
11321553Srgrimes#define TRC(q)	(((q)-' ')&0177)
11331553Srgrimes
11341553Srgrimesstatic void
11351553Srgrimesscan_out(scfd, scsp, dlm)
11361553Srgrimes	int scfd, dlm;
11371553Srgrimes	char *scsp;
11381553Srgrimes{
11391553Srgrimes	register char *strp;
11401553Srgrimes	register nchrs, j;
11411553Srgrimes	char outbuf[LINELEN+1], *sp, c, cc;
11421553Srgrimes	int d, scnhgt;
11431553Srgrimes
11441553Srgrimes	for (scnhgt = 0; scnhgt++ < HEIGHT+DROP; ) {
11451553Srgrimes		strp = &outbuf[0];
11461553Srgrimes		sp = scsp;
11471553Srgrimes		for (nchrs = 0; ; ) {
11481553Srgrimes			d = dropit(c = TRC(cc = *sp++));
11491553Srgrimes			if ((!d && scnhgt > HEIGHT) || (scnhgt <= DROP && d))
11501553Srgrimes				for (j = WIDTH; --j;)
11511553Srgrimes					*strp++ = BACKGND;
11521553Srgrimes			else
11531553Srgrimes				strp = scnline(scnkey[c][scnhgt-1-d], strp, cc);
11541553Srgrimes			if (*sp == dlm || *sp == '\0' || nchrs++ >= PW/(WIDTH+1)-1)
11551553Srgrimes				break;
11561553Srgrimes			*strp++ = BACKGND;
11571553Srgrimes			*strp++ = BACKGND;
11581553Srgrimes		}
11591553Srgrimes		while (*--strp == BACKGND && strp >= outbuf)
11601553Srgrimes			;
11611553Srgrimes		strp++;
11628857Srgrimes		*strp++ = '\n';
11631553Srgrimes		(void) write(scfd, outbuf, strp-outbuf);
11641553Srgrimes	}
11651553Srgrimes}
11661553Srgrimes
11671553Srgrimesstatic int
11681553Srgrimesdropit(c)
11691553Srgrimes	int c;
11701553Srgrimes{
11711553Srgrimes	switch(c) {
11721553Srgrimes
11731553Srgrimes	case TRC('_'):
11741553Srgrimes	case TRC(';'):
11751553Srgrimes	case TRC(','):
11761553Srgrimes	case TRC('g'):
11771553Srgrimes	case TRC('j'):
11781553Srgrimes	case TRC('p'):
11791553Srgrimes	case TRC('q'):
11801553Srgrimes	case TRC('y'):
11811553Srgrimes		return (DROP);
11821553Srgrimes
11831553Srgrimes	default:
11841553Srgrimes		return (0);
11851553Srgrimes	}
11861553Srgrimes}
11871553Srgrimes
11881553Srgrimes/*
11891553Srgrimes * sendmail ---
11901553Srgrimes *   tell people about job completion
11911553Srgrimes */
11921553Srgrimesstatic void
11931553Srgrimessendmail(user, bombed)
11941553Srgrimes	char *user;
11951553Srgrimes	int bombed;
11961553Srgrimes{
11971553Srgrimes	register int i;
119818569Sbde	int dtablesize;
11991553Srgrimes	int p[2], s;
12001553Srgrimes	register char *cp;
12011553Srgrimes	struct stat stb;
12021553Srgrimes	FILE *fp;
12031553Srgrimes
12041553Srgrimes	pipe(p);
12051553Srgrimes	if ((s = dofork(DORETURN)) == 0) {		/* child */
12061553Srgrimes		dup2(p[0], 0);
12078094Sjkh		closelog();
120818569Sbde		for (i = 3, dtablesize = getdtablesize(); i < dtablesize; i++)
12091553Srgrimes			(void) close(i);
121027635Simp		if ((cp = strrchr(_PATH_SENDMAIL, '/')) != NULL)
12111553Srgrimes			cp++;
12121553Srgrimes	else
12131553Srgrimes			cp = _PATH_SENDMAIL;
121427757Simp		execl(_PATH_SENDMAIL, cp, "-t", 0);
12151553Srgrimes		exit(0);
12161553Srgrimes	} else if (s > 0) {				/* parent */
12171553Srgrimes		dup2(p[1], 1);
12181553Srgrimes		printf("To: %s@%s\n", user, fromhost);
121915648Sjoerg		printf("Subject: %s printer job \"%s\"\n", printer,
122015648Sjoerg			*jobname ? jobname : "<unknown>");
122115648Sjoerg		printf("Reply-To: root@%s\n\n", host);
12221553Srgrimes		printf("Your printer job ");
12231553Srgrimes		if (*jobname)
12241553Srgrimes			printf("(%s) ", jobname);
12251553Srgrimes		switch (bombed) {
12261553Srgrimes		case OK:
12271553Srgrimes			printf("\ncompleted successfully\n");
122815648Sjoerg			cp = "OK";
12291553Srgrimes			break;
12301553Srgrimes		default:
12311553Srgrimes		case FATALERR:
12321553Srgrimes			printf("\ncould not be printed\n");
123315648Sjoerg			cp = "FATALERR";
12341553Srgrimes			break;
12351553Srgrimes		case NOACCT:
12361553Srgrimes			printf("\ncould not be printed without an account on %s\n", host);
123715648Sjoerg			cp = "NOACCT";
12381553Srgrimes			break;
12391553Srgrimes		case FILTERERR:
12401553Srgrimes			if (stat(tempfile, &stb) < 0 || stb.st_size == 0 ||
12411553Srgrimes			    (fp = fopen(tempfile, "r")) == NULL) {
124215648Sjoerg				printf("\nhad some errors and may not have printed\n");
12431553Srgrimes				break;
12441553Srgrimes			}
124515648Sjoerg			printf("\nhad the following errors and may not have printed:\n");
12461553Srgrimes			while ((i = getc(fp)) != EOF)
12471553Srgrimes				putchar(i);
12481553Srgrimes			(void) fclose(fp);
124915648Sjoerg			cp = "FILTERERR";
12501553Srgrimes			break;
12511553Srgrimes		case ACCESS:
12521553Srgrimes			printf("\nwas not printed because it was not linked to the original file\n");
125315648Sjoerg			cp = "ACCESS";
12541553Srgrimes		}
12551553Srgrimes		fflush(stdout);
12561553Srgrimes		(void) close(1);
12571553Srgrimes	}
12581553Srgrimes	(void) close(p[0]);
12591553Srgrimes	(void) close(p[1]);
126015648Sjoerg	wait(NULL);
126115648Sjoerg	syslog(LOG_INFO, "mail sent to user %s about job %s on printer %s (%s)",
126215648Sjoerg		user, *jobname ? jobname : "<unknown>", printer, cp);
12631553Srgrimes}
12641553Srgrimes
12651553Srgrimes/*
12661553Srgrimes * dofork - fork with retries on failure
12671553Srgrimes */
12681553Srgrimesstatic int
12691553Srgrimesdofork(action)
12701553Srgrimes	int action;
12711553Srgrimes{
12721553Srgrimes	register int i, pid;
12731553Srgrimes
12741553Srgrimes	for (i = 0; i < 20; i++) {
12751553Srgrimes		if ((pid = fork()) < 0) {
12761553Srgrimes			sleep((unsigned)(i*i));
12771553Srgrimes			continue;
12781553Srgrimes		}
12791553Srgrimes		/*
12801553Srgrimes		 * Child should run as daemon instead of root
12811553Srgrimes		 */
128215648Sjoerg		if (pid == 0)
12831553Srgrimes			setuid(DU);
12841553Srgrimes		return(pid);
12851553Srgrimes	}
12861553Srgrimes	syslog(LOG_ERR, "can't fork");
12871553Srgrimes
12881553Srgrimes	switch (action) {
12891553Srgrimes	case DORETURN:
12901553Srgrimes		return (-1);
12911553Srgrimes	default:
12921553Srgrimes		syslog(LOG_ERR, "bad action (%d) to dofork", action);
12931553Srgrimes		/*FALL THRU*/
12941553Srgrimes	case DOABORT:
12951553Srgrimes		exit(1);
12961553Srgrimes	}
12971553Srgrimes	/*NOTREACHED*/
12981553Srgrimes}
12991553Srgrimes
13001553Srgrimes/*
13011553Srgrimes * Kill child processes to abort current job.
13021553Srgrimes */
13031553Srgrimesstatic void
13041553Srgrimesabortpr(signo)
13051553Srgrimes	int signo;
13061553Srgrimes{
13071553Srgrimes	(void) unlink(tempfile);
13081553Srgrimes	kill(0, SIGINT);
13091553Srgrimes	if (ofilter > 0)
13101553Srgrimes		kill(ofilter, SIGCONT);
13111553Srgrimes	while (wait(NULL) > 0)
13121553Srgrimes		;
131324831Sbrian	if (ofilter > 0 && tfd != -1)
131424831Sbrian		unlink(tfile);
13151553Srgrimes	exit(0);
13161553Srgrimes}
13171553Srgrimes
13181553Srgrimesstatic void
13191553Srgrimesinit()
13201553Srgrimes{
13211553Srgrimes	int status;
13221553Srgrimes	char *s;
13231553Srgrimes
13241553Srgrimes	if ((status = cgetent(&bp, printcapdb, printer)) == -2) {
13251553Srgrimes		syslog(LOG_ERR, "can't open printer description file");
13261553Srgrimes		exit(1);
13271553Srgrimes	} else if (status == -1) {
13281553Srgrimes		syslog(LOG_ERR, "unknown printer: %s", printer);
13291553Srgrimes		exit(1);
13301553Srgrimes	} else if (status == -3)
13311553Srgrimes		fatal("potential reference loop detected in printcap file");
13321553Srgrimes
13331553Srgrimes	if (cgetstr(bp, "lp", &LP) == -1)
13341553Srgrimes		LP = _PATH_DEFDEVLP;
13351553Srgrimes	if (cgetstr(bp, "rp", &RP) == -1)
13361553Srgrimes		RP = DEFLP;
13371553Srgrimes	if (cgetstr(bp, "lo", &LO) == -1)
13381553Srgrimes		LO = DEFLOCK;
13391553Srgrimes	if (cgetstr(bp, "st", &ST) == -1)
13401553Srgrimes		ST = DEFSTAT;
13411553Srgrimes	if (cgetstr(bp, "lf", &LF) == -1)
13421553Srgrimes		LF = _PATH_CONSOLE;
13431553Srgrimes	if (cgetstr(bp, "sd", &SD) == -1)
13441553Srgrimes		SD = _PATH_DEFSPOOL;
13451553Srgrimes	if (cgetnum(bp, "du", &DU) < 0)
13461553Srgrimes		DU = DEFUID;
13471553Srgrimes	if (cgetstr(bp,"ff", &FF) == -1)
13481553Srgrimes		FF = DEFFF;
13491553Srgrimes	if (cgetnum(bp, "pw", &PW) < 0)
13501553Srgrimes		PW = DEFWIDTH;
135127748Simp	sprintf(&width[2], "%ld", PW);
13521553Srgrimes	if (cgetnum(bp, "pl", &PL) < 0)
13531553Srgrimes		PL = DEFLENGTH;
135430407Sjoerg	if (cgetnum(bp, "ct", &CT) < 0)
135530407Sjoerg		CT = DEFTIMEOUT;
135627748Simp	sprintf(&length[2], "%ld", PL);
13571553Srgrimes	if (cgetnum(bp,"px", &PX) < 0)
13581553Srgrimes		PX = 0;
135927748Simp	sprintf(&pxwidth[2], "%ld", PX);
13601553Srgrimes	if (cgetnum(bp, "py", &PY) < 0)
13611553Srgrimes		PY = 0;
136227748Simp	sprintf(&pxlength[2], "%ld", PY);
13631553Srgrimes	cgetstr(bp, "rm", &RM);
136427748Simp	if ((s = checkremote()))
13651553Srgrimes		syslog(LOG_WARNING, s);
13661553Srgrimes
13671553Srgrimes	cgetstr(bp, "af", &AF);
13681553Srgrimes	cgetstr(bp, "of", &OF);
13691553Srgrimes	cgetstr(bp, "if", &IF);
13701553Srgrimes	cgetstr(bp, "rf", &RF);
13711553Srgrimes	cgetstr(bp, "tf", &TF);
13721553Srgrimes	cgetstr(bp, "nf", &NF);
13731553Srgrimes	cgetstr(bp, "df", &DF);
13741553Srgrimes	cgetstr(bp, "gf", &GF);
13751553Srgrimes	cgetstr(bp, "vf", &VF);
13761553Srgrimes	cgetstr(bp, "cf", &CF);
13771553Srgrimes	cgetstr(bp, "tr", &TR);
137815032Ssef	cgetstr(bp, "ms", &MS);
13791553Srgrimes
13801553Srgrimes	RS = (cgetcap(bp, "rs", ':') != NULL);
13811553Srgrimes	SF = (cgetcap(bp, "sf", ':') != NULL);
13821553Srgrimes	SH = (cgetcap(bp, "sh", ':') != NULL);
13831553Srgrimes	SB = (cgetcap(bp, "sb", ':') != NULL);
13841553Srgrimes	HL = (cgetcap(bp, "hl", ':') != NULL);
13851553Srgrimes	RW = (cgetcap(bp, "rw", ':') != NULL);
13861553Srgrimes
13871553Srgrimes	cgetnum(bp, "br", &BR);
13881553Srgrimes
13891553Srgrimes	tof = (cgetcap(bp, "fo", ':') == NULL);
13901553Srgrimes}
13911553Srgrimes
13921553Srgrimes/*
13931553Srgrimes * Acquire line printer or remote connection.
13941553Srgrimes */
13951553Srgrimesstatic void
13961553Srgrimesopenpr()
13971553Srgrimes{
139815648Sjoerg	register int i;
139918569Sbde	int dtablesize;
140015648Sjoerg	char *cp;
14011553Srgrimes
140215648Sjoerg	if (!remote && *LP) {
140327635Simp		if (cp = strchr(LP, '@'))
140415648Sjoerg			opennet(cp);
140515648Sjoerg		else
140615648Sjoerg			opentty();
140715648Sjoerg	} else if (remote) {
140815648Sjoerg		openrem();
14091553Srgrimes	} else {
14101553Srgrimes		syslog(LOG_ERR, "%s: no line printer device or host name",
14111553Srgrimes			printer);
14121553Srgrimes		exit(1);
14131553Srgrimes	}
141415648Sjoerg
14151553Srgrimes	/*
14161553Srgrimes	 * Start up an output filter, if needed.
14171553Srgrimes	 */
141824831Sbrian	if (OF && !IF && !ofilter) {
14191553Srgrimes		int p[2];
14201553Srgrimes
14211553Srgrimes		pipe(p);
142224831Sbrian		if (remote) {
142324831Sbrian			strcpy(tfile,TFILENAME);
142424831Sbrian			tfd = mkstemp(tfile);
142524831Sbrian		}
14261553Srgrimes		if ((ofilter = dofork(DOABORT)) == 0) {	/* child */
14271553Srgrimes			dup2(p[0], 0);		/* pipe is std in */
142824831Sbrian			/* tfile/printer is stdout */
142924831Sbrian			dup2(remote ? tfd : pfd, 1);
14308094Sjkh			closelog();
143118569Sbde			for (i = 3, dtablesize = getdtablesize();
143218569Sbde			     i < dtablesize; i++)
14331553Srgrimes				(void) close(i);
143427635Simp			if ((cp = strrchr(OF, '/')) == NULL)
14351553Srgrimes				cp = OF;
14361553Srgrimes			else
14371553Srgrimes				cp++;
14381553Srgrimes			execl(OF, cp, width, length, 0);
14391553Srgrimes			syslog(LOG_ERR, "%s: %s: %m", printer, OF);
14401553Srgrimes			exit(1);
14411553Srgrimes		}
14421553Srgrimes		(void) close(p[0]);		/* close input side */
14431553Srgrimes		ofd = p[1];			/* use pipe for output */
14441553Srgrimes	} else {
14451553Srgrimes		ofd = pfd;
14461553Srgrimes		ofilter = 0;
14471553Srgrimes	}
14481553Srgrimes}
14491553Srgrimes
145015648Sjoerg/*
145115648Sjoerg * Printer connected directly to the network
145215648Sjoerg * or to a terminal server on the net
145315648Sjoerg */
145415648Sjoergstatic void
145515648Sjoergopennet(cp)
145615648Sjoerg	char *cp;
145715648Sjoerg{
145815648Sjoerg	register int i;
145915648Sjoerg	int resp, port;
146015648Sjoerg	char save_ch;
146130407Sjoerg	void (*savealrm)(int);
146215648Sjoerg
146315648Sjoerg	save_ch = *cp;
146415648Sjoerg	*cp = '\0';
146515648Sjoerg	port = atoi(LP);
146615648Sjoerg	if (port <= 0) {
146715648Sjoerg		syslog(LOG_ERR, "%s: bad port number: %s", printer, LP);
146815648Sjoerg		exit(1);
146915648Sjoerg	}
147015648Sjoerg	*cp++ = save_ch;
147115648Sjoerg
147215648Sjoerg	for (i = 1; ; i = i < 256 ? i << 1 : i) {
147315648Sjoerg		resp = -1;
147430407Sjoerg		savealrm = signal(SIGALRM, alarmhandler);
147530407Sjoerg		alarm(CT);
147615648Sjoerg		pfd = getport(cp, port);
147730407Sjoerg		(void)signal(SIGALRM, savealrm);
147815648Sjoerg		if (pfd < 0 && errno == ECONNREFUSED)
147915648Sjoerg			resp = 1;
148015648Sjoerg		else if (pfd >= 0) {
148115648Sjoerg			/*
148215648Sjoerg			 * need to delay a bit for rs232 lines
148315648Sjoerg			 * to stabilize in case printer is
148415648Sjoerg			 * connected via a terminal server
148515648Sjoerg			 */
148615648Sjoerg			delay(500);
148715648Sjoerg			break;
148815648Sjoerg		}
148915648Sjoerg		if (i == 1) {
149015648Sjoerg		   if (resp < 0)
149115648Sjoerg			pstatus("waiting for %s to come up", LP);
149215648Sjoerg		   else
149315648Sjoerg			pstatus("waiting for access to printer on %s", LP);
149415648Sjoerg		}
149515648Sjoerg		sleep(i);
149615648Sjoerg	}
149715648Sjoerg	pstatus("sending to %s port %d", cp, port);
149815648Sjoerg}
149915648Sjoerg
150015648Sjoerg/*
150115648Sjoerg * Printer is connected to an RS232 port on this host
150215648Sjoerg */
150315648Sjoergstatic void
150415648Sjoergopentty()
150515648Sjoerg{
150615648Sjoerg	register int i;
150715648Sjoerg	int resp, port;
150815648Sjoerg
150915648Sjoerg	for (i = 1; ; i = i < 32 ? i << 1 : i) {
151015648Sjoerg		pfd = open(LP, RW ? O_RDWR : O_WRONLY);
151115648Sjoerg		if (pfd >= 0) {
151215648Sjoerg			delay(500);
151315648Sjoerg			break;
151415648Sjoerg		}
151515648Sjoerg		if (errno == ENOENT) {
151615648Sjoerg			syslog(LOG_ERR, "%s: %m", LP);
151715648Sjoerg			exit(1);
151815648Sjoerg		}
151915648Sjoerg		if (i == 1)
152015648Sjoerg			pstatus("waiting for %s to become ready (offline ?)",
152115648Sjoerg				printer);
152215648Sjoerg		sleep(i);
152315648Sjoerg	}
152415648Sjoerg	if (isatty(pfd))
152515648Sjoerg		setty();
152615648Sjoerg	pstatus("%s is ready and printing", printer);
152715648Sjoerg}
152815648Sjoerg
152915648Sjoerg/*
153015648Sjoerg * Printer is on a remote host
153115648Sjoerg */
153215648Sjoergstatic void
153315648Sjoergopenrem()
153415648Sjoerg{
153515648Sjoerg	register int i, n;
153627748Simp	int resp;
153730407Sjoerg	void (*savealrm)(int);
153815648Sjoerg
153915648Sjoerg	for (i = 1; ; i = i < 256 ? i << 1 : i) {
154015648Sjoerg		resp = -1;
154130407Sjoerg		savealrm = signal(SIGALRM, alarmhandler);
154230407Sjoerg		alarm(CT);
154315648Sjoerg		pfd = getport(RM, 0);
154430407Sjoerg		(void)signal(SIGALRM, savealrm);
154515648Sjoerg		if (pfd >= 0) {
154627748Simp			(void) snprintf(line, sizeof(line), "\2%s\n", RP);
154715648Sjoerg			n = strlen(line);
154815648Sjoerg			if (write(pfd, line, n) == n &&
154915648Sjoerg			    (resp = response()) == '\0')
155015648Sjoerg				break;
155115648Sjoerg			(void) close(pfd);
155215648Sjoerg		}
155315648Sjoerg		if (i == 1) {
155415648Sjoerg			if (resp < 0)
155515648Sjoerg				pstatus("waiting for %s to come up", RM);
155615648Sjoerg			else {
155715648Sjoerg				pstatus("waiting for queue to be enabled on %s",
155815648Sjoerg					RM);
155915648Sjoerg				i = 256;
156015648Sjoerg			}
156115648Sjoerg		}
156215648Sjoerg		sleep(i);
156315648Sjoerg	}
156415648Sjoerg	pstatus("sending to %s", RM);
156515648Sjoerg}
156615648Sjoerg
15671553Srgrimesstruct bauds {
15681553Srgrimes	int	baud;
15691553Srgrimes	int	speed;
15701553Srgrimes} bauds[] = {
15711553Srgrimes	50,	B50,
15721553Srgrimes	75,	B75,
15731553Srgrimes	110,	B110,
15741553Srgrimes	134,	B134,
15751553Srgrimes	150,	B150,
15761553Srgrimes	200,	B200,
15771553Srgrimes	300,	B300,
15781553Srgrimes	600,	B600,
15791553Srgrimes	1200,	B1200,
15801553Srgrimes	1800,	B1800,
15811553Srgrimes	2400,	B2400,
15821553Srgrimes	4800,	B4800,
15831553Srgrimes	9600,	B9600,
15841553Srgrimes	19200,	EXTA,
15851553Srgrimes	38400,	EXTB,
15869821Swpaul	57600,	B57600,
15879821Swpaul	115200,	B115200,
15881553Srgrimes	0,	0
15891553Srgrimes};
15901553Srgrimes
15911553Srgrimes/*
15921553Srgrimes * setup tty lines.
15931553Srgrimes */
15941553Srgrimesstatic void
15951553Srgrimessetty()
15961553Srgrimes{
159715032Ssef	struct termios ttybuf;
159815032Ssef	struct bauds *bp;
15991553Srgrimes
16001553Srgrimes	if (ioctl(pfd, TIOCEXCL, (char *)0) < 0) {
16011553Srgrimes		syslog(LOG_ERR, "%s: ioctl(TIOCEXCL): %m", printer);
16021553Srgrimes		exit(1);
16031553Srgrimes	}
160415032Ssef	if (tcgetattr(pfd, &ttybuf) < 0) {
160515032Ssef		syslog(LOG_ERR, "%s: tcgetattr: %m", printer);
16061553Srgrimes		exit(1);
16071553Srgrimes	}
16081553Srgrimes	if (BR > 0) {
16091553Srgrimes		for (bp = bauds; bp->baud; bp++)
16101553Srgrimes			if (BR == bp->baud)
16111553Srgrimes				break;
16121553Srgrimes		if (!bp->baud) {
16131553Srgrimes			syslog(LOG_ERR, "%s: illegal baud rate %d", printer, BR);
16141553Srgrimes			exit(1);
16151553Srgrimes		}
161615032Ssef		cfsetspeed(&ttybuf, bp->speed);
16171553Srgrimes	}
161815032Ssef	if (MS) {
161915032Ssef		char *s = strdup(MS), *tmp;
162015032Ssef
162115032Ssef		while (tmp = strsep (&s, ",")) {
162215032Ssef			msearch(tmp, &ttybuf);
16231553Srgrimes		}
16241553Srgrimes	}
162515032Ssef	if (MS || (BR > 0)) {
162615032Ssef		if (tcsetattr(pfd, TCSAFLUSH, &ttybuf) == -1) {
162715032Ssef			syslog(LOG_ERR, "%s: tcsetattr: %m", printer);
16281553Srgrimes		}
16291553Srgrimes	}
16301553Srgrimes}
16311553Srgrimes
163227757Simp#ifdef __STDC__
16331553Srgrimes#include <stdarg.h>
16341553Srgrimes#else
16351553Srgrimes#include <varargs.h>
16361553Srgrimes#endif
16371553Srgrimes
163815648Sjoergstatic void
163927757Simp#ifdef __STDC__
16401553Srgrimespstatus(const char *msg, ...)
16411553Srgrimes#else
16421553Srgrimespstatus(msg, va_alist)
16431553Srgrimes	char *msg;
16441553Srgrimes        va_dcl
16451553Srgrimes#endif
16461553Srgrimes{
16471553Srgrimes	register int fd;
16481553Srgrimes	char buf[BUFSIZ];
16491553Srgrimes	va_list ap;
165027757Simp#ifdef __STDC__
16511553Srgrimes	va_start(ap, msg);
16521553Srgrimes#else
16531553Srgrimes	va_start(ap);
16541553Srgrimes#endif
16551553Srgrimes
16561553Srgrimes	umask(0);
16571553Srgrimes	fd = open(ST, O_WRONLY|O_CREAT, 0664);
16581553Srgrimes	if (fd < 0 || flock(fd, LOCK_EX) < 0) {
16591553Srgrimes		syslog(LOG_ERR, "%s: %s: %m", printer, ST);
16601553Srgrimes		exit(1);
16611553Srgrimes	}
16621553Srgrimes	ftruncate(fd, 0);
166327757Simp	(void)vsnprintf(buf, sizeof(buf) - 1, msg, ap);
16641553Srgrimes	va_end(ap);
16651553Srgrimes	strcat(buf, "\n");
16661553Srgrimes	(void) write(fd, buf, strlen(buf));
16671553Srgrimes	(void) close(fd);
16681553Srgrimes}
166930407Sjoerg
167030407Sjoergvoid
167130407Sjoergalarmhandler(signo)
167230407Sjoerg{
167330407Sjoerg	/* ignored */
167430407Sjoerg}
1675