File:  [DragonFly] / src / usr.sbin / lpr / lpd / printjob.c
Revision 1.3: download - view: text, annotated - select for diffs
Mon Mar 22 22:32:50 2004 UTC (10 years, 8 months ago) by cpressey
Branches: MAIN
CVS tags: HEAD, DragonFly_Snap29Sep2004, DragonFly_Snap13Sep2004, DragonFly_1_0_REL, DragonFly_1_0_RC1, DragonFly_1_0A_REL
Style(9) cleanup.

- Remove ``register'' keywords and adjust a comment referencing them.
- Remove formfeeds.
- *argv[] -> **argv

    1: /*
    2:  * Copyright (c) 1983, 1993
    3:  *	The Regents of the University of California.  All rights reserved.
    4:  *
    5:  *
    6:  * Redistribution and use in source and binary forms, with or without
    7:  * modification, are permitted provided that the following conditions
    8:  * are met:
    9:  * 1. Redistributions of source code must retain the above copyright
   10:  *    notice, this list of conditions and the following disclaimer.
   11:  * 2. Redistributions in binary form must reproduce the above copyright
   12:  *    notice, this list of conditions and the following disclaimer in the
   13:  *    documentation and/or other materials provided with the distribution.
   14:  * 3. All advertising materials mentioning features or use of this software
   15:  *    must display the following acknowledgement:
   16:  *	This product includes software developed by the University of
   17:  *	California, Berkeley and its contributors.
   18:  * 4. Neither the name of the University nor the names of its contributors
   19:  *    may be used to endorse or promote products derived from this software
   20:  *    without specific prior written permission.
   21:  *
   22:  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
   23:  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   24:  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   25:  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
   26:  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   27:  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   28:  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   29:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   30:  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   31:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   32:  * SUCH DAMAGE.
   33:  *
   34:  * @(#) Copyright (c) 1983, 1993 The Regents of the University of California.  All rights reserved.
   35:  * @(#)printjob.c	8.7 (Berkeley) 5/10/95
   36:  * $FreeBSD: src/usr.sbin/lpr/lpd/printjob.c,v 1.22.2.32 2002/06/19 23:58:16 gad Exp $
   37:  * $DragonFly: src/usr.sbin/lpr/lpd/printjob.c,v 1.3 2004/03/22 22:32:50 cpressey Exp $
   38:  */
   39: 
   40: /*
   41:  * printjob -- print jobs in the queue.
   42:  *
   43:  *	NOTE: the lock file is used to pass information to lpq and lprm.
   44:  *	it does not need to be removed because file locks are dynamic.
   45:  */
   46: 
   47: #include <sys/param.h>
   48: #include <sys/wait.h>
   49: #include <sys/stat.h>
   50: #include <sys/types.h>
   51: 
   52: #include <pwd.h>
   53: #include <unistd.h>
   54: #include <signal.h>
   55: #include <syslog.h>
   56: #include <fcntl.h>
   57: #include <dirent.h>
   58: #include <errno.h>
   59: #include <stdio.h>
   60: #include <string.h>
   61: #include <stdlib.h>
   62: #include <sys/ioctl.h>
   63: #include <termios.h>
   64: #include <time.h>
   65: #include "lp.h"
   66: #include "lp.local.h"
   67: #include "pathnames.h"
   68: #include "extern.h"
   69: 
   70: #define DORETURN	0	/* dofork should return "can't fork" error */
   71: #define DOABORT		1	/* dofork should just die if fork() fails */
   72: 
   73: /*
   74:  * Error tokens
   75:  */
   76: #define REPRINT		-2
   77: #define ERROR		-1
   78: #define	OK		0
   79: #define	FATALERR	1
   80: #define	NOACCT		2
   81: #define	FILTERERR	3
   82: #define	ACCESS		4
   83: 
   84: static dev_t	 fdev;		/* device of file pointed to by symlink */
   85: static ino_t	 fino;		/* inode of file pointed to by symlink */
   86: static FILE	*cfp;		/* control file */
   87: static pid_t	 of_pid;	/* process id of output filter, if any */
   88: static int	 child;		/* id of any filters */
   89: static int	 job_dfcnt;	/* count of datafiles in current user job */
   90: static int	 lfd;		/* lock file descriptor */
   91: static int	 ofd;		/* output filter file descriptor */
   92: static int	 tfd = -1;	/* output filter temp file output */
   93: static int	 pfd;		/* prstatic inter file descriptor */
   94: static int	 prchild;	/* id of pr process */
   95: static char	 title[80];	/* ``pr'' title */
   96: static char      locale[80];    /* ``pr'' locale */
   97: 
   98: /* these two are set from pp->daemon_user, but only if they are needed */
   99: static char	*daemon_uname;	/* set from pwd->pw_name */
  100: static int	 daemon_defgid;
  101: 
  102: static char	class[32];		/* classification field */
  103: static char	origin_host[MAXHOSTNAMELEN];	/* user's host machine */
  104: 				/* indentation size in static characters */
  105: static char	indent[10] = "-i0";
  106: static char	jobname[100];		/* job or file name */
  107: static char	length[10] = "-l";	/* page length in lines */
  108: static char	logname[32];		/* user's login name */
  109: static char	pxlength[10] = "-y";	/* page length in pixels */
  110: static char	pxwidth[10] = "-x";	/* page width in pixels */
  111: /* tempstderr is the filename used to catch stderr from exec-ing filters */
  112: static char	tempstderr[] = "errs.XXXXXXX";
  113: static char	width[10] = "-w";	/* page width in static characters */
  114: #define TFILENAME "fltXXXXXX"
  115: static char	tfile[] = TFILENAME;	/* file name for filter output */
  116: 
  117: static void	 abortpr(int _signo);
  118: static void	 alarmhandler(int _signo);
  119: static void	 banner(struct printer *_pp, char *_name1, char *_name2);
  120: static int	 dofork(const struct printer *_pp, int _action);
  121: static int	 dropit(int _c);
  122: static int	 execfilter(struct printer *_pp, char *_f_cmd, char **_f_av,
  123: 		    int _infd, int _outfd);
  124: static void	 init(struct printer *_pp);
  125: static void	 openpr(const struct printer *_pp);
  126: static void	 opennet(const struct printer *_pp);
  127: static void	 opentty(const struct printer *_pp);
  128: static void	 openrem(const struct printer *pp);
  129: static int	 print(struct printer *_pp, int _format, char *_file);
  130: static int	 printit(struct printer *_pp, char *_file);
  131: static void	 pstatus(const struct printer *_pp, const char *_msg, ...)
  132: 		    __printflike(2, 3);
  133: static char	 response(const struct printer *_pp);
  134: static void	 scan_out(struct printer *_pp, int _scfd, char *_scsp, 
  135: 		    int _dlm);
  136: static char	*scnline(int _key, char *_p, int _c);
  137: static int	 sendfile(struct printer *_pp, int _type, char *_file, 
  138: 		    char _format, int _copyreq);
  139: static int	 sendit(struct printer *_pp, char *_file);
  140: static void	 sendmail(struct printer *_pp, char *_userid, int _bombed);
  141: static void	 setty(const struct printer *_pp);
  142: 
  143: void
  144: printjob(struct printer *pp)
  145: {
  146: 	struct stat stb;
  147: 	struct jobqueue *q, **qp;
  148: 	struct jobqueue **queue;
  149: 	int i, nitems;
  150: 	off_t pidoff;
  151: 	pid_t printpid;
  152: 	int errcnt, jobcount, tempfd;
  153: 
  154: 	jobcount = 0;
  155: 	init(pp); /* set up capabilities */
  156: 	(void) write(1, "", 1);	/* ack that daemon is started */
  157: 	(void) close(2);			/* set up log file */
  158: 	if (open(pp->log_file, O_WRONLY|O_APPEND, LOG_FILE_MODE) < 0) {
  159: 		syslog(LOG_ERR, "%s: open(%s): %m", pp->printer,
  160: 		    pp->log_file);
  161: 		(void) open(_PATH_DEVNULL, O_WRONLY);
  162: 	}
  163: 	setgid(getegid());
  164: 	printpid = getpid();			/* for use with lprm */
  165: 	setpgrp(0, printpid);
  166: 
  167: 	/*
  168: 	 * At initial lpd startup, printjob may be called with various
  169: 	 * signal handlers in effect.  After that initial startup, any
  170: 	 * calls to printjob will have a *different* set of signal-handlers
  171: 	 * in effect.  Make sure all handlers are the ones we want.
  172: 	 */
  173: 	signal(SIGCHLD, SIG_DFL);
  174: 	signal(SIGHUP, abortpr);
  175: 	signal(SIGINT, abortpr);
  176: 	signal(SIGQUIT, abortpr);
  177: 	signal(SIGTERM, abortpr);
  178: 
  179: 	/*
  180: 	 * uses short form file names
  181: 	 */
  182: 	if (chdir(pp->spool_dir) < 0) {
  183: 		syslog(LOG_ERR, "%s: chdir(%s): %m", pp->printer,
  184: 		    pp->spool_dir);
  185: 		exit(1);
  186: 	}
  187: 	if (stat(pp->lock_file, &stb) == 0 && (stb.st_mode & LFM_PRINT_DIS))
  188: 		exit(0);		/* printing disabled */
  189: 	lfd = open(pp->lock_file, O_WRONLY|O_CREAT|O_EXLOCK|O_NONBLOCK, 
  190: 		   LOCK_FILE_MODE);
  191: 	if (lfd < 0) {
  192: 		if (errno == EWOULDBLOCK)	/* active daemon present */
  193: 			exit(0);
  194: 		syslog(LOG_ERR, "%s: open(%s): %m", pp->printer,
  195: 		    pp->lock_file);
  196: 		exit(1);
  197: 	}
  198: 	/* turn off non-blocking mode (was turned on for lock effects only) */
  199: 	if (fcntl(lfd, F_SETFL, 0) < 0) {
  200: 		syslog(LOG_ERR, "%s: fcntl(%s): %m", pp->printer,
  201: 		    pp->lock_file);
  202: 		exit(1);
  203: 	}
  204: 	ftruncate(lfd, 0);
  205: 	/*
  206: 	 * write process id for others to know
  207: 	 */
  208: 	sprintf(line, "%u\n", printpid);
  209: 	pidoff = i = strlen(line);
  210: 	if (write(lfd, line, i) != i) {
  211: 		syslog(LOG_ERR, "%s: write(%s): %m", pp->printer,
  212: 		    pp->lock_file);
  213: 		exit(1);
  214: 	}
  215: 	/*
  216: 	 * search the spool directory for work and sort by queue order.
  217: 	 */
  218: 	if ((nitems = getq(pp, &queue)) < 0) {
  219: 		syslog(LOG_ERR, "%s: can't scan %s", pp->printer, 
  220: 		    pp->spool_dir);
  221: 		exit(1);
  222: 	}
  223: 	if (nitems == 0)		/* no work to do */
  224: 		exit(0);
  225: 	if (stb.st_mode & LFM_RESET_QUE) { /* reset queue flag */
  226: 		if (fchmod(lfd, stb.st_mode & ~LFM_RESET_QUE) < 0)
  227: 			syslog(LOG_ERR, "%s: fchmod(%s): %m", pp->printer,
  228: 			    pp->lock_file);
  229: 	}
  230: 
  231: 	/* create a file which will be used to hold stderr from filters */
  232: 	if ((tempfd = mkstemp(tempstderr)) == -1) {
  233: 		syslog(LOG_ERR, "%s: mkstemp(%s): %m", pp->printer,
  234: 		    tempstderr);
  235: 		exit(1);
  236: 	}
  237: 	if ((i = fchmod(tempfd, 0664)) == -1) {
  238: 		syslog(LOG_ERR, "%s: fchmod(%s): %m", pp->printer,
  239: 		    tempstderr);
  240: 		exit(1);
  241: 	}
  242: 	/* lpd doesn't need it to be open, it just needs it to exist */
  243: 	close(tempfd);
  244: 
  245: 	openpr(pp);			/* open printer or remote */
  246: again:
  247: 	/*
  248: 	 * we found something to do now do it --
  249: 	 *    write the name of the current control file into the lock file
  250: 	 *    so the spool queue program can tell what we're working on
  251: 	 */
  252: 	for (qp = queue; nitems--; free((char *) q)) {
  253: 		q = *qp++;
  254: 		if (stat(q->job_cfname, &stb) < 0)
  255: 			continue;
  256: 		errcnt = 0;
  257: 	restart:
  258: 		(void) lseek(lfd, pidoff, 0);
  259: 		(void) snprintf(line, sizeof(line), "%s\n", q->job_cfname);
  260: 		i = strlen(line);
  261: 		if (write(lfd, line, i) != i)
  262: 			syslog(LOG_ERR, "%s: write(%s): %m", pp->printer,
  263: 			    pp->lock_file);
  264: 		if (!pp->remote)
  265: 			i = printit(pp, q->job_cfname);
  266: 		else
  267: 			i = sendit(pp, q->job_cfname);
  268: 		/*
  269: 		 * Check to see if we are supposed to stop printing or
  270: 		 * if we are to rebuild the queue.
  271: 		 */
  272: 		if (fstat(lfd, &stb) == 0) {
  273: 			/* stop printing before starting next job? */
  274: 			if (stb.st_mode & LFM_PRINT_DIS)
  275: 				goto done;
  276: 			/* rebuild queue (after lpc topq) */
  277: 			if (stb.st_mode & LFM_RESET_QUE) {
  278: 				for (free(q); nitems--; free(q))
  279: 					q = *qp++;
  280: 				if (fchmod(lfd, stb.st_mode & ~LFM_RESET_QUE)
  281: 				    < 0)
  282: 					syslog(LOG_WARNING,
  283: 					    "%s: fchmod(%s): %m",
  284: 					    pp->printer, pp->lock_file);
  285: 				break;
  286: 			}
  287: 		}
  288: 		if (i == OK)		/* all files of this job printed */
  289: 			jobcount++;
  290: 		else if (i == REPRINT && ++errcnt < 5) {
  291: 			/* try reprinting the job */
  292: 			syslog(LOG_INFO, "restarting %s", pp->printer);
  293: 			if (of_pid > 0) {
  294: 				kill(of_pid, SIGCONT); /* to be sure */
  295: 				(void) close(ofd);
  296: 				while ((i = wait(NULL)) > 0 && i != of_pid)
  297: 					;
  298: 				if (i < 0)
  299: 					syslog(LOG_WARNING, "%s: after kill(of=%d), wait() returned: %m",
  300: 					    pp->printer, of_pid);
  301: 				of_pid = 0;
  302: 			}
  303: 			(void) close(pfd);	/* close printer */
  304: 			if (ftruncate(lfd, pidoff) < 0)
  305: 				syslog(LOG_WARNING, "%s: ftruncate(%s): %m", 
  306: 				    pp->printer, pp->lock_file);
  307: 			openpr(pp);		/* try to reopen printer */
  308: 			goto restart;
  309: 		} else {
  310: 			syslog(LOG_WARNING, "%s: job could not be %s (%s)", 
  311: 			    pp->printer,
  312: 			    pp->remote ? "sent to remote host" : "printed",
  313: 			    q->job_cfname);
  314: 			if (i == REPRINT) {
  315: 				/* ensure we don't attempt this job again */
  316: 				(void) unlink(q->job_cfname);
  317: 				q->job_cfname[0] = 'd';
  318: 				(void) unlink(q->job_cfname);
  319: 				if (logname[0])
  320: 					sendmail(pp, logname, FATALERR);
  321: 			}
  322: 		}
  323: 	}
  324: 	free(queue);
  325: 	/*
  326: 	 * search the spool directory for more work.
  327: 	 */
  328: 	if ((nitems = getq(pp, &queue)) < 0) {
  329: 		syslog(LOG_ERR, "%s: can't scan %s", pp->printer,
  330: 		    pp->spool_dir);
  331: 		exit(1);
  332: 	}
  333: 	if (nitems == 0) {		/* no more work to do */
  334: 	done:
  335: 		if (jobcount > 0) {	/* jobs actually printed */
  336: 			if (!pp->no_formfeed && !pp->tof)
  337: 				(void) write(ofd, pp->form_feed,
  338: 					     strlen(pp->form_feed));
  339: 			if (pp->trailer != NULL) /* output trailer */
  340: 				(void) write(ofd, pp->trailer,
  341: 					     strlen(pp->trailer));
  342: 		}
  343: 		(void) close(ofd);
  344: 		(void) wait(NULL);
  345: 		(void) unlink(tempstderr);
  346: 		exit(0);
  347: 	}
  348: 	goto again;
  349: }
  350: 
  351: char	fonts[4][50];	/* fonts for troff */
  352: 
  353: char ifonts[4][40] = {
  354: 	_PATH_VFONTR,
  355: 	_PATH_VFONTI,
  356: 	_PATH_VFONTB,
  357: 	_PATH_VFONTS,
  358: };
  359: 
  360: /*
  361:  * The remaining part is the reading of the control file (cf)
  362:  * and performing the various actions.
  363:  */
  364: static int
  365: printit(struct printer *pp, char *file)
  366: {
  367: 	int i;
  368: 	char *cp;
  369: 	int bombed, didignorehdr;
  370: 
  371: 	bombed = OK;
  372: 	didignorehdr = 0;
  373: 	/*
  374: 	 * open control file; ignore if no longer there.
  375: 	 */
  376: 	if ((cfp = fopen(file, "r")) == NULL) {
  377: 		syslog(LOG_INFO, "%s: fopen(%s): %m", pp->printer, file);
  378: 		return (OK);
  379: 	}
  380: 	/*
  381: 	 * Reset troff fonts.
  382: 	 */
  383: 	for (i = 0; i < 4; i++)
  384: 		strcpy(fonts[i], ifonts[i]);
  385: 	sprintf(&width[2], "%ld", pp->page_width);
  386: 	strcpy(indent+2, "0");
  387: 
  388: 	/* initialize job-specific count of datafiles processed */
  389: 	job_dfcnt = 0;
  390: 	
  391: 	/*
  392: 	 *      read the control file for work to do
  393: 	 *
  394: 	 *      file format -- first character in the line is a command
  395: 	 *      rest of the line is the argument.
  396: 	 *      valid commands are:
  397: 	 *
  398: 	 *		S -- "stat info" for symbolic link protection
  399: 	 *		J -- "job name" on banner page
  400: 	 *		C -- "class name" on banner page
  401: 	 *              L -- "literal" user's name to print on banner
  402: 	 *		T -- "title" for pr
  403: 	 *		H -- "host name" of machine where lpr was done
  404: 	 *              P -- "person" user's login name
  405: 	 *              I -- "indent" amount to indent output
  406: 	 *		R -- laser dpi "resolution"
  407: 	 *              f -- "file name" name of text file to print
  408: 	 *		l -- "file name" text file with control chars
  409: 	 *		o -- "file name" postscript file, according to
  410: 	 *		     the RFC.  Here it is treated like an 'f'.
  411: 	 *		p -- "file name" text file to print with pr(1)
  412: 	 *		t -- "file name" troff(1) file to print
  413: 	 *		n -- "file name" ditroff(1) file to print
  414: 	 *		d -- "file name" dvi file to print
  415: 	 *		g -- "file name" plot(1G) file to print
  416: 	 *		v -- "file name" plain raster file to print
  417: 	 *		c -- "file name" cifplot file to print
  418: 	 *		1 -- "R font file" for troff
  419: 	 *		2 -- "I font file" for troff
  420: 	 *		3 -- "B font file" for troff
  421: 	 *		4 -- "S font file" for troff
  422: 	 *		N -- "name" of file (used by lpq)
  423: 	 *              U -- "unlink" name of file to remove
  424: 	 *                    (after we print it. (Pass 2 only)).
  425: 	 *		M -- "mail" to user when done printing
  426: 	 *              Z -- "locale" for pr
  427: 	 *
  428: 	 *      getline reads a line and expands tabs to blanks
  429: 	 */
  430: 
  431: 	/* pass 1 */
  432: 
  433: 	while (getline(cfp))
  434: 		switch (line[0]) {
  435: 		case 'H':
  436: 			strlcpy(origin_host, line + 1, sizeof(origin_host));
  437: 			if (class[0] == '\0') {
  438: 				strlcpy(class, line+1, sizeof(class));
  439: 			}
  440: 			continue;
  441: 
  442: 		case 'P':
  443: 			strlcpy(logname, line + 1, sizeof(logname));
  444: 			if (pp->restricted) { /* restricted */
  445: 				if (getpwnam(logname) == NULL) {
  446: 					bombed = NOACCT;
  447: 					sendmail(pp, line+1, bombed);
  448: 					goto pass2;
  449: 				}
  450: 			}
  451: 			continue;
  452: 
  453: 		case 'S':
  454: 			cp = line+1;
  455: 			i = 0;
  456: 			while (*cp >= '0' && *cp <= '9')
  457: 				i = i * 10 + (*cp++ - '0');
  458: 			fdev = i;
  459: 			cp++;
  460: 			i = 0;
  461: 			while (*cp >= '0' && *cp <= '9')
  462: 				i = i * 10 + (*cp++ - '0');
  463: 			fino = i;
  464: 			continue;
  465: 
  466: 		case 'J':
  467: 			if (line[1] != '\0') {
  468: 				strlcpy(jobname, line + 1, sizeof(jobname));
  469: 			} else
  470: 				strcpy(jobname, " ");
  471: 			continue;
  472: 
  473: 		case 'C':
  474: 			if (line[1] != '\0')
  475: 				strlcpy(class, line + 1, sizeof(class));
  476: 			else if (class[0] == '\0') {
  477: 				/* XXX - why call gethostname instead of
  478: 				 *       just strlcpy'ing local_host? */
  479: 				gethostname(class, sizeof(class));
  480: 				class[sizeof(class) - 1] = '\0';
  481: 			}
  482: 			continue;
  483: 
  484: 		case 'T':	/* header title for pr */
  485: 			strlcpy(title, line + 1, sizeof(title));
  486: 			continue;
  487: 
  488: 		case 'L':	/* identification line */
  489: 			if (!pp->no_header && !pp->header_last)
  490: 				banner(pp, line+1, jobname);
  491: 			continue;
  492: 
  493: 		case '1':	/* troff fonts */
  494: 		case '2':
  495: 		case '3':
  496: 		case '4':
  497: 			if (line[1] != '\0') {
  498: 				strlcpy(fonts[line[0]-'1'], line + 1,
  499: 				    (size_t)50);
  500: 			}
  501: 			continue;
  502: 
  503: 		case 'W':	/* page width */
  504: 			strlcpy(width+2, line + 1, sizeof(width) - 2);
  505: 			continue;
  506: 
  507: 		case 'I':	/* indent amount */
  508: 			strlcpy(indent+2, line + 1, sizeof(indent) - 2);
  509: 			continue;
  510: 
  511: 		case 'Z':       /* locale for pr */
  512: 			strlcpy(locale, line + 1, sizeof(locale));
  513: 			continue;
  514: 
  515: 		default:	/* some file to print */
  516: 			/* only lowercase cmd-codes include a file-to-print */
  517: 			if ((line[0] < 'a') || (line[0] > 'z')) {
  518: 				/* ignore any other lines */
  519: 				if (lflag <= 1)
  520: 					continue;
  521: 				if (!didignorehdr) {
  522: 					syslog(LOG_INFO, "%s: in %s :",
  523: 					    pp->printer, file);
  524: 					didignorehdr = 1;
  525: 				}
  526: 				syslog(LOG_INFO, "%s: ignoring line: '%c' %s",
  527: 				    pp->printer, line[0], &line[1]);
  528: 				continue;
  529: 			}
  530: 			i = print(pp, line[0], line+1);
  531: 			switch (i) {
  532: 			case ERROR:
  533: 				if (bombed == OK)
  534: 					bombed = FATALERR;
  535: 				break;
  536: 			case REPRINT:
  537: 				(void) fclose(cfp);
  538: 				return (REPRINT);
  539: 			case FILTERERR:
  540: 			case ACCESS:
  541: 				bombed = i;
  542: 				sendmail(pp, logname, bombed);
  543: 			}
  544: 			title[0] = '\0';
  545: 			continue;
  546: 
  547: 		case 'N':
  548: 		case 'U':
  549: 		case 'M':
  550: 		case 'R':
  551: 			continue;
  552: 		}
  553: 
  554: 	/* pass 2 */
  555: 
  556: pass2:
  557: 	fseek(cfp, 0L, 0);
  558: 	while (getline(cfp))
  559: 		switch (line[0]) {
  560: 		case 'L':	/* identification line */
  561: 			if (!pp->no_header && pp->header_last)
  562: 				banner(pp, line+1, jobname);
  563: 			continue;
  564: 
  565: 		case 'M':
  566: 			if (bombed < NOACCT)	/* already sent if >= NOACCT */
  567: 				sendmail(pp, line+1, bombed);
  568: 			continue;
  569: 
  570: 		case 'U':
  571: 			if (strchr(line+1, '/'))
  572: 				continue;
  573: 			(void) unlink(line+1);
  574: 		}
  575: 	/*
  576: 	 * clean-up in case another control file exists
  577: 	 */
  578: 	(void) fclose(cfp);
  579: 	(void) unlink(file);
  580: 	return (bombed == OK ? OK : ERROR);
  581: }
  582: 
  583: /*
  584:  * Print a file.
  585:  * Set up the chain [ PR [ | {IF, OF} ] ] or {IF, RF, TF, NF, DF, CF, VF}.
  586:  * Return -1 if a non-recoverable error occured,
  587:  * 2 if the filter detected some errors (but printed the job anyway),
  588:  * 1 if we should try to reprint this job and
  589:  * 0 if all is well.
  590:  * Note: all filters take stdin as the file, stdout as the printer,
  591:  * stderr as the log file, and must not ignore SIGINT.
  592:  */
  593: static int
  594: print(struct printer *pp, int format, char *file)
  595: {
  596: 	int n, i;
  597: 	char *prog;
  598: 	int fi, fo;
  599: 	FILE *fp;
  600: 	char *av[15], buf[BUFSIZ];
  601: 	pid_t wpid;
  602: 	int p[2], retcode, stopped, wstatus, wstatus_set;
  603: 	struct stat stb;
  604: 
  605: 	if (lstat(file, &stb) < 0 || (fi = open(file, O_RDONLY)) < 0) {
  606: 		syslog(LOG_INFO, "%s: unable to open %s ('%c' line)",
  607: 		    pp->printer, file, format);
  608: 		return (ERROR);
  609: 	}
  610: 	/*
  611: 	 * Check to see if data file is a symbolic link. If so, it should
  612: 	 * still point to the same file or someone is trying to print
  613: 	 * something he shouldn't.
  614: 	 */
  615: 	if ((stb.st_mode & S_IFMT) == S_IFLNK && fstat(fi, &stb) == 0 &&
  616: 	    (stb.st_dev != fdev || stb.st_ino != fino))
  617: 		return (ACCESS);
  618: 
  619: 	job_dfcnt++;		/* increment datafile counter for this job */
  620: 	stopped = 0;		/* output filter is not stopped */
  621: 
  622: 	/* everything seems OK, start it up */
  623: 	if (!pp->no_formfeed && !pp->tof) { /* start on a fresh page */
  624: 		(void) write(ofd, pp->form_feed, strlen(pp->form_feed));
  625: 		pp->tof = 1;
  626: 	}
  627: 	if (pp->filters[LPF_INPUT] == NULL
  628: 	    && (format == 'f' || format == 'l' || format == 'o')) {
  629: 		pp->tof = 0;
  630: 		while ((n = read(fi, buf, BUFSIZ)) > 0)
  631: 			if (write(ofd, buf, n) != n) {
  632: 				(void) close(fi);
  633: 				return (REPRINT);
  634: 			}
  635: 		(void) close(fi);
  636: 		return (OK);
  637: 	}
  638: 	switch (format) {
  639: 	case 'p':	/* print file using 'pr' */
  640: 		if (pp->filters[LPF_INPUT] == NULL) {	/* use output filter */
  641: 			prog = _PATH_PR;
  642: 			i = 0;
  643: 			av[i++] = "pr";
  644: 			av[i++] = width;
  645: 			av[i++] = length;
  646: 			av[i++] = "-h";
  647: 			av[i++] = *title ? title : " ";
  648: 			av[i++] = "-L";
  649: 			av[i++] = *locale ? locale : "C";
  650: 			av[i++] = "-F";
  651: 			av[i] = 0;
  652: 			fo = ofd;
  653: 			goto start;
  654: 		}
  655: 		pipe(p);
  656: 		if ((prchild = dofork(pp, DORETURN)) == 0) {	/* child */
  657: 			dup2(fi, 0);		/* file is stdin */
  658: 			dup2(p[1], 1);		/* pipe is stdout */
  659: 			closelog();
  660: 			closeallfds(3);
  661: 			execl(_PATH_PR, "pr", width, length,
  662: 			    "-h", *title ? title : " ",
  663: 			    "-L", *locale ? locale : "C",
  664: 			    "-F", (char *)0);
  665: 			syslog(LOG_ERR, "cannot execl %s", _PATH_PR);
  666: 			exit(2);
  667: 		}
  668: 		(void) close(p[1]);		/* close output side */
  669: 		(void) close(fi);
  670: 		if (prchild < 0) {
  671: 			prchild = 0;
  672: 			(void) close(p[0]);
  673: 			return (ERROR);
  674: 		}
  675: 		fi = p[0];			/* use pipe for input */
  676: 	case 'f':	/* print plain text file */
  677: 		prog = pp->filters[LPF_INPUT];
  678: 		av[1] = width;
  679: 		av[2] = length;
  680: 		av[3] = indent;
  681: 		n = 4;
  682: 		break;
  683: 	case 'o':	/* print postscript file */
  684: 		/*
  685: 		 * Treat this as a "plain file with control characters", and
  686: 		 * assume the standard LPF_INPUT filter will recognize that
  687: 		 * the data is postscript and know what to do with it.  These
  688: 		 * 'o'-file requests could come from MacOS 10.1 systems.
  689: 		 * (later versions of MacOS 10 will explicitly use 'l')
  690: 		 * A postscript file can contain binary data, which is why 'l'
  691: 		 * is somewhat more appropriate than 'f'.
  692: 		 */
  693: 		/* FALLTHROUGH */
  694: 	case 'l':	/* like 'f' but pass control characters */
  695: 		prog = pp->filters[LPF_INPUT];
  696: 		av[1] = "-c";
  697: 		av[2] = width;
  698: 		av[3] = length;
  699: 		av[4] = indent;
  700: 		n = 5;
  701: 		break;
  702: 	case 'r':	/* print a fortran text file */
  703: 		prog = pp->filters[LPF_FORTRAN];
  704: 		av[1] = width;
  705: 		av[2] = length;
  706: 		n = 3;
  707: 		break;
  708: 	case 't':	/* print troff output */
  709: 	case 'n':	/* print ditroff output */
  710: 	case 'd':	/* print tex output */
  711: 		(void) unlink(".railmag");
  712: 		if ((fo = creat(".railmag", FILMOD)) < 0) {
  713: 			syslog(LOG_ERR, "%s: cannot create .railmag", 
  714: 			    pp->printer);
  715: 			(void) unlink(".railmag");
  716: 		} else {
  717: 			for (n = 0; n < 4; n++) {
  718: 				if (fonts[n][0] != '/')
  719: 					(void) write(fo, _PATH_VFONT,
  720: 					    sizeof(_PATH_VFONT) - 1);
  721: 				(void) write(fo, fonts[n], strlen(fonts[n]));
  722: 				(void) write(fo, "\n", 1);
  723: 			}
  724: 			(void) close(fo);
  725: 		}
  726: 		prog = (format == 't') ? pp->filters[LPF_TROFF] 
  727: 			: ((format == 'n') ? pp->filters[LPF_DITROFF]
  728: 			   : pp->filters[LPF_DVI]);
  729: 		av[1] = pxwidth;
  730: 		av[2] = pxlength;
  731: 		n = 3;
  732: 		break;
  733: 	case 'c':	/* print cifplot output */
  734: 		prog = pp->filters[LPF_CIFPLOT];
  735: 		av[1] = pxwidth;
  736: 		av[2] = pxlength;
  737: 		n = 3;
  738: 		break;
  739: 	case 'g':	/* print plot(1G) output */
  740: 		prog = pp->filters[LPF_GRAPH];
  741: 		av[1] = pxwidth;
  742: 		av[2] = pxlength;
  743: 		n = 3;
  744: 		break;
  745: 	case 'v':	/* print raster output */
  746: 		prog = pp->filters[LPF_RASTER];
  747: 		av[1] = pxwidth;
  748: 		av[2] = pxlength;
  749: 		n = 3;
  750: 		break;
  751: 	default:
  752: 		(void) close(fi);
  753: 		syslog(LOG_ERR, "%s: illegal format character '%c'",
  754: 		    pp->printer, format);
  755: 		return (ERROR);
  756: 	}
  757: 	if (prog == NULL) {
  758: 		(void) close(fi);
  759: 		syslog(LOG_ERR,
  760: 		   "%s: no filter found in printcap for format character '%c'",
  761: 		   pp->printer, format);
  762: 		return (ERROR);
  763: 	}
  764: 	if ((av[0] = strrchr(prog, '/')) != NULL)
  765: 		av[0]++;
  766: 	else
  767: 		av[0] = prog;
  768: 	av[n++] = "-n";
  769: 	av[n++] = logname;
  770: 	av[n++] = "-h";
  771: 	av[n++] = origin_host;
  772: 	av[n++] = pp->acct_file;
  773: 	av[n] = 0;
  774: 	fo = pfd;
  775: 	if (of_pid > 0) {		/* stop output filter */
  776: 		write(ofd, "\031\1", 2);
  777: 		while ((wpid =
  778: 		    wait3(&wstatus, WUNTRACED, 0)) > 0 && wpid != of_pid)
  779: 			;
  780: 		if (wpid < 0)
  781: 			syslog(LOG_WARNING,
  782: 			    "%s: after stopping 'of', wait3() returned: %m",
  783: 			    pp->printer);
  784: 		else if (!WIFSTOPPED(wstatus)) {
  785: 			(void) close(fi);
  786: 			syslog(LOG_WARNING, "%s: output filter died "
  787: 			    "(pid=%d retcode=%d termsig=%d)",
  788: 			    pp->printer, of_pid, WEXITSTATUS(wstatus),
  789: 			    WTERMSIG(wstatus));
  790: 			return (REPRINT);
  791: 		}
  792: 		stopped++;
  793: 	}
  794: start:
  795: 	if ((child = dofork(pp, DORETURN)) == 0) { /* child */
  796: 		dup2(fi, 0);
  797: 		dup2(fo, 1);
  798: 		/* setup stderr for the filter (child process)
  799: 		 * so it goes to our temporary errors file */
  800: 		n = open(tempstderr, O_WRONLY|O_TRUNC, 0664);
  801: 		if (n >= 0)
  802: 			dup2(n, 2);
  803: 		closelog();
  804: 		closeallfds(3);
  805: 		execv(prog, av);
  806: 		syslog(LOG_ERR, "%s: cannot execv(%s): %m", pp->printer,
  807: 		    prog);
  808: 		exit(2);
  809: 	}
  810: 	(void) close(fi);
  811: 	wstatus_set = 0;
  812: 	if (child < 0)
  813: 		retcode = 100;
  814: 	else {
  815: 		while ((wpid = wait(&wstatus)) > 0 && wpid != child)
  816: 			;
  817: 		if (wpid < 0) {
  818: 			retcode = 100;
  819: 			syslog(LOG_WARNING,
  820: 			    "%s: after execv(%s), wait() returned: %m",
  821: 			    pp->printer, prog);
  822: 		} else {
  823: 			wstatus_set = 1;
  824: 			retcode = WEXITSTATUS(wstatus);
  825: 		}
  826: 	}
  827: 	child = 0;
  828: 	prchild = 0;
  829: 	if (stopped) {		/* restart output filter */
  830: 		if (kill(of_pid, SIGCONT) < 0) {
  831: 			syslog(LOG_ERR, "cannot restart output filter");
  832: 			exit(1);
  833: 		}
  834: 	}
  835: 	pp->tof = 0;
  836: 
  837: 	/* Copy the filter's output to "lf" logfile */
  838: 	if ((fp = fopen(tempstderr, "r"))) {
  839: 		while (fgets(buf, sizeof(buf), fp))
  840: 			fputs(buf, stderr);
  841: 		fclose(fp);
  842: 	}
  843: 
  844: 	if (wstatus_set && !WIFEXITED(wstatus)) {
  845: 		syslog(LOG_WARNING, "%s: filter '%c' terminated (termsig=%d)",
  846: 		    pp->printer, format, WTERMSIG(wstatus));
  847: 		return (ERROR);
  848: 	}
  849: 	switch (retcode) {
  850: 	case 0:
  851: 		pp->tof = 1;
  852: 		return (OK);
  853: 	case 1:
  854: 		return (REPRINT);
  855: 	case 2:
  856: 		return (ERROR);
  857: 	default:
  858: 		syslog(LOG_WARNING, "%s: filter '%c' exited (retcode=%d)",
  859: 		    pp->printer, format, retcode);
  860: 		return (FILTERERR);
  861: 	}
  862: }
  863: 
  864: /*
  865:  * Send the daemon control file (cf) and any data files.
  866:  * Return -1 if a non-recoverable error occured, 1 if a recoverable error and
  867:  * 0 if all is well.
  868:  */
  869: static int
  870: sendit(struct printer *pp, char *file)
  871: {
  872: 	int dfcopies, err, i;
  873: 	char *cp, last[BUFSIZ];
  874: 
  875: 	/*
  876: 	 * open control file
  877: 	 */
  878: 	if ((cfp = fopen(file, "r")) == NULL)
  879: 		return (OK);
  880: 
  881: 	/* initialize job-specific count of datafiles processed */
  882: 	job_dfcnt = 0;
  883: 
  884: 	/*
  885: 	 *      read the control file for work to do
  886: 	 *
  887: 	 *      file format -- first character in the line is a command
  888: 	 *      rest of the line is the argument.
  889: 	 *      commands of interest are:
  890: 	 *
  891: 	 *            a-z -- "file name" name of file to print
  892: 	 *              U -- "unlink" name of file to remove
  893: 	 *                    (after we print it. (Pass 2 only)).
  894: 	 */
  895: 
  896: 	/*
  897: 	 * pass 1
  898: 	 */
  899: 	err = OK;
  900: 	while (getline(cfp)) {
  901: 	again:
  902: 		if (line[0] == 'S') {
  903: 			cp = line+1;
  904: 			i = 0;
  905: 			while (*cp >= '0' && *cp <= '9')
  906: 				i = i * 10 + (*cp++ - '0');
  907: 			fdev = i;
  908: 			cp++;
  909: 			i = 0;
  910: 			while (*cp >= '0' && *cp <= '9')
  911: 				i = i * 10 + (*cp++ - '0');
  912: 			fino = i;
  913: 		} else if (line[0] == 'H') {
  914: 			strlcpy(origin_host, line + 1, sizeof(origin_host));
  915: 			if (class[0] == '\0') {
  916: 				strlcpy(class, line + 1, sizeof(class));
  917: 			}
  918: 		} else if (line[0] == 'P') {
  919: 			strlcpy(logname, line + 1, sizeof(logname));
  920: 			if (pp->restricted) { /* restricted */
  921: 				if (getpwnam(logname) == NULL) {
  922: 					sendmail(pp, line+1, NOACCT);
  923: 					err = ERROR;
  924: 					break;
  925: 				}
  926: 			}
  927: 		} else if (line[0] == 'I') {
  928: 			strlcpy(indent+2, line + 1, sizeof(indent) - 2);
  929: 		} else if (line[0] >= 'a' && line[0] <= 'z') {
  930: 			dfcopies = 1;
  931: 			strcpy(last, line);
  932: 			while ((i = getline(cfp)) != 0) {
  933: 				if (strcmp(last, line) != 0)
  934: 					break;
  935: 				dfcopies++;
  936: 			}
  937: 			switch (sendfile(pp, '\3', last+1, *last, dfcopies)) {
  938: 			case OK:
  939: 				if (i)
  940: 					goto again;
  941: 				break;
  942: 			case REPRINT:
  943: 				(void) fclose(cfp);
  944: 				return (REPRINT);
  945: 			case ACCESS:
  946: 				sendmail(pp, logname, ACCESS);
  947: 			case ERROR:
  948: 				err = ERROR;
  949: 			}
  950: 			break;
  951: 		}
  952: 	}
  953: 	if (err == OK && sendfile(pp, '\2', file, '\0', 1) > 0) {
  954: 		(void) fclose(cfp);
  955: 		return (REPRINT);
  956: 	}
  957: 	/*
  958: 	 * pass 2
  959: 	 */
  960: 	fseek(cfp, 0L, 0);
  961: 	while (getline(cfp))
  962: 		if (line[0] == 'U' && !strchr(line+1, '/'))
  963: 			(void) unlink(line+1);
  964: 	/*
  965: 	 * clean-up in case another control file exists
  966: 	 */
  967: 	(void) fclose(cfp);
  968: 	(void) unlink(file);
  969: 	return (err);
  970: }
  971: 
  972: /*
  973:  * Send a data file to the remote machine and spool it.
  974:  * Return positive if we should try resending.
  975:  */
  976: static int
  977: sendfile(struct printer *pp, int type, char *file, char format, int copyreq)
  978: {
  979: 	int i, amt;
  980: 	struct stat stb;
  981: 	char *av[15], *filtcmd;
  982: 	char buf[BUFSIZ], opt_c[4], opt_h[4], opt_n[4];
  983: 	int copycnt, filtstat, narg, resp, sfd, sfres, sizerr, statrc;
  984: 
  985: 	statrc = lstat(file, &stb);
  986: 	if (statrc < 0) {
  987: 		syslog(LOG_ERR, "%s: error from lstat(%s): %m",
  988: 		    pp->printer, file);
  989: 		return (ERROR);
  990: 	}
  991: 	sfd = open(file, O_RDONLY);
  992: 	if (sfd < 0) {
  993: 		syslog(LOG_ERR, "%s: error from open(%s,O_RDONLY): %m",
  994: 		    pp->printer, file);
  995: 		return (ERROR);
  996: 	}
  997: 	/*
  998: 	 * Check to see if data file is a symbolic link. If so, it should
  999: 	 * still point to the same file or someone is trying to print something
 1000: 	 * he shouldn't.
 1001: 	 */
 1002: 	if ((stb.st_mode & S_IFMT) == S_IFLNK && fstat(sfd, &stb) == 0 &&
 1003: 	    (stb.st_dev != fdev || stb.st_ino != fino)) {
 1004: 		close(sfd);
 1005: 		return (ACCESS);
 1006: 	}
 1007: 
 1008: 	/* Everything seems OK for reading the file, now to send it */
 1009: 	filtcmd = NULL;
 1010: 	sizerr = 0;
 1011: 	tfd = -1;
 1012: 	if (type == '\3') {
 1013: 		/*
 1014: 		 * Type == 3 means this is a datafile, not a control file.
 1015: 		 * Increment the counter of data-files in this job, and
 1016: 		 * then check for input or output filters (which are only
 1017: 		 * applied to datafiles, not control files).
 1018: 		 */
 1019: 		job_dfcnt++;
 1020: 
 1021: 		/*
 1022: 		 * Note that here we are filtering datafiles, one at a time,
 1023: 		 * as they are sent to the remote machine.  Here, the *only*
 1024: 		 * difference between an input filter (`if=') and an output
 1025: 		 * filter (`of=') is the argument list that the filter is
 1026: 		 * started up with.  Here, the output filter is executed
 1027: 		 * for each individual file as it is sent.  This is not the
 1028: 		 * same as local print queues, where the output filter is
 1029: 		 * started up once, and then all jobs are passed thru that
 1030: 		 * single invocation of the output filter.
 1031: 		 *
 1032: 		 * Also note that a queue for a remote-machine can have an
 1033: 		 * input filter or an output filter, but not both.
 1034: 		 */
 1035: 		if (pp->filters[LPF_INPUT]) {
 1036: 			filtcmd = pp->filters[LPF_INPUT];
 1037: 			av[0] = filtcmd;
 1038: 			narg = 0;
 1039: 			strcpy(opt_c, "-c");
 1040: 			strcpy(opt_h, "-h");
 1041: 			strcpy(opt_n, "-n");
 1042: 			if (format == 'l')
 1043: 				av[++narg] = opt_c;
 1044: 			av[++narg] = width;
 1045: 			av[++narg] = length;
 1046: 			av[++narg] = indent;
 1047: 			av[++narg] = opt_n;
 1048: 			av[++narg] = logname;
 1049: 			av[++narg] = opt_h;
 1050: 			av[++narg] = origin_host;
 1051: 			av[++narg] = pp->acct_file;
 1052: 			av[++narg] = NULL;
 1053: 		} else if (pp->filters[LPF_OUTPUT]) {
 1054: 			filtcmd = pp->filters[LPF_OUTPUT];
 1055: 			av[0] = filtcmd;
 1056: 			narg = 0;
 1057: 			av[++narg] = width;
 1058: 			av[++narg] = length;
 1059: 			av[++narg] = NULL;
 1060: 		}
 1061: 	}
 1062: 	if (filtcmd) {
 1063: 		/*
 1064: 		 * If there is an input or output filter, we have to run
 1065: 		 * the datafile thru that filter and store the result as
 1066: 		 * a temporary spool file, because the protocol requires
 1067: 		 * that we send the remote host the file-size before we
 1068: 		 * start to send any of the data.
 1069: 		 */
 1070: 		strcpy(tfile, TFILENAME);
 1071: 		tfd = mkstemp(tfile);
 1072: 		if (tfd == -1) {
 1073: 			syslog(LOG_ERR, "%s: mkstemp(%s): %m", pp->printer,
 1074: 			    TFILENAME);
 1075: 			sfres = ERROR;
 1076: 			goto return_sfres;
 1077: 		}
 1078: 		filtstat = execfilter(pp, filtcmd, av, sfd, tfd);
 1079: 
 1080: 		/* process the return-code from the filter */
 1081: 		switch (filtstat) {
 1082: 		case 0:
 1083: 			break;
 1084: 		case 1:
 1085: 			sfres = REPRINT;
 1086: 			goto return_sfres;
 1087: 		case 2:
 1088: 			sfres = ERROR;
 1089: 			goto return_sfres;
 1090: 		default:
 1091: 			syslog(LOG_WARNING,
 1092: 			    "%s: filter '%c' exited (retcode=%d)",
 1093: 			    pp->printer, format, filtstat);
 1094: 			sfres = FILTERERR;
 1095: 			goto return_sfres;
 1096: 		}
 1097: 		statrc = fstat(tfd, &stb);   /* to find size of tfile */
 1098: 		if (statrc < 0)	{
 1099: 			syslog(LOG_ERR,
 1100: 			    "%s: error processing 'if', fstat(%s): %m",
 1101: 			    pp->printer, tfile);
 1102: 			sfres = ERROR;
 1103: 			goto return_sfres;
 1104: 		}
 1105: 		close(sfd);
 1106: 		sfd = tfd;
 1107: 		lseek(sfd, 0, SEEK_SET);
 1108: 	}
 1109: 
 1110: 	copycnt = 0;
 1111: sendagain:
 1112: 	copycnt++;
 1113: 
 1114: 	if (copycnt < 2)
 1115: 		(void) sprintf(buf, "%c%qd %s\n", type, stb.st_size, file);
 1116: 	else
 1117: 		(void) sprintf(buf, "%c%qd %s_c%d\n", type, stb.st_size,
 1118: 		    file, copycnt);
 1119: 	amt = strlen(buf);
 1120: 	for (i = 0;  ; i++) {
 1121: 		if (write(pfd, buf, amt) != amt ||
 1122: 		    (resp = response(pp)) < 0 || resp == '\1') {
 1123: 			sfres = REPRINT;
 1124: 			goto return_sfres;
 1125: 		} else if (resp == '\0')
 1126: 			break;
 1127: 		if (i == 0)
 1128: 			pstatus(pp,
 1129: 				"no space on remote; waiting for queue to drain");
 1130: 		if (i == 10)
 1131: 			syslog(LOG_ALERT, "%s: can't send to %s; queue full",
 1132: 			    pp->printer, pp->remote_host);
 1133: 		sleep(5 * 60);
 1134: 	}
 1135: 	if (i)
 1136: 		pstatus(pp, "sending to %s", pp->remote_host);
 1137: 	/*
 1138: 	 * XXX - we should change trstat_init()/trstat_write() to include
 1139: 	 *	 the copycnt in the statistics record it may write.
 1140: 	 */
 1141: 	if (type == '\3')
 1142: 		trstat_init(pp, file, job_dfcnt);
 1143: 	for (i = 0; i < stb.st_size; i += BUFSIZ) {
 1144: 		amt = BUFSIZ;
 1145: 		if (i + amt > stb.st_size)
 1146: 			amt = stb.st_size - i;
 1147: 		if (sizerr == 0 && read(sfd, buf, amt) != amt)
 1148: 			sizerr = 1;
 1149: 		if (write(pfd, buf, amt) != amt) {
 1150: 			sfres = REPRINT;
 1151: 			goto return_sfres;
 1152: 		}
 1153: 	}
 1154: 
 1155: 	if (sizerr) {
 1156: 		syslog(LOG_INFO, "%s: %s: changed size", pp->printer, file);
 1157: 		/* tell recvjob to ignore this file */
 1158: 		(void) write(pfd, "\1", 1);
 1159: 		sfres = ERROR;
 1160: 		goto return_sfres;
 1161: 	}
 1162: 	if (write(pfd, "", 1) != 1 || response(pp)) {
 1163: 		sfres = REPRINT;
 1164: 		goto return_sfres;
 1165: 	}
 1166: 	if (type == '\3') {
 1167: 		trstat_write(pp, TR_SENDING, stb.st_size, logname,
 1168: 		    pp->remote_host, origin_host);
 1169: 		/*
 1170: 		 * Usually we only need to send one copy of a datafile,
 1171: 		 * because the control-file will simply print the same
 1172: 		 * file multiple times.  However, some printers ignore
 1173: 		 * the control file, and simply print each data file as
 1174: 		 * it arrives.  For such "remote hosts", we need to
 1175: 		 * transfer the same data file multiple times.  Such a
 1176: 		 * a host is indicated by adding 'rc' to the printcap
 1177: 		 * entry.
 1178: 		 * XXX - Right now this ONLY works for remote hosts which
 1179: 		 *	do ignore the name of the data file, because
 1180: 		 *	this sends the file multiple times with slight
 1181: 		 *	changes to the filename.  To do this right would
 1182: 		 *	require that we also rewrite the control file
 1183: 		 *	to match those filenames.
 1184: 		 */
 1185: 		if (pp->resend_copies && (copycnt < copyreq)) {
 1186: 			lseek(sfd, 0, SEEK_SET);
 1187: 			goto sendagain;
 1188: 		}
 1189: 	}
 1190: 	sfres = OK;
 1191: 
 1192: return_sfres:
 1193: 	(void)close(sfd);
 1194: 	if (tfd != -1) {
 1195: 		/*
 1196: 		 * If tfd is set, then it is the same value as sfd, and
 1197: 		 * therefore it is already closed at this point.  All
 1198: 		 * we need to do is remove the temporary file.
 1199: 		 */
 1200: 		tfd = -1;
 1201: 		unlink(tfile);
 1202: 	}
 1203: 	return (sfres);
 1204: }
 1205: 
 1206: /*
 1207:  *  This routine is called to execute one of the filters as was
 1208:  *  specified in a printcap entry.  While the child-process will read
 1209:  *  all of 'infd', it is up to the caller to close that file descriptor
 1210:  *  in the parent process.
 1211:  */
 1212: static int
 1213: execfilter(struct printer *pp, char *f_cmd, char *f_av[], int infd, int outfd)
 1214: {
 1215: 	pid_t fpid, wpid;
 1216: 	int errfd, retcode, wstatus;
 1217: 	FILE *errfp;
 1218: 	char buf[BUFSIZ], *slash;
 1219: 
 1220: 	fpid = dofork(pp, DORETURN);
 1221: 	if (fpid != 0) {
 1222: 		/*
 1223: 		 * This is the parent process, which just waits for the child
 1224: 		 * to complete and then returns the result.  Note that it is
 1225: 		 * the child process which reads the input stream.
 1226: 		 */
 1227: 		if (fpid < 0)
 1228: 			retcode = 100;
 1229: 		else {
 1230: 			while ((wpid = wait(&wstatus)) > 0 &&
 1231: 			    wpid != fpid)
 1232: 				;
 1233: 			if (wpid < 0) {
 1234: 				retcode = 100;
 1235: 				syslog(LOG_WARNING,
 1236: 				    "%s: after execv(%s), wait() returned: %m",
 1237: 				    pp->printer, f_cmd);
 1238: 			} else
 1239: 				retcode = WEXITSTATUS(wstatus);
 1240: 		}
 1241: 
 1242: 		/*
 1243: 		 * Copy everything the filter wrote to stderr from our
 1244: 		 * temporary errors file to the "lf=" logfile.
 1245: 		 */
 1246: 		errfp = fopen(tempstderr, "r");
 1247: 		if (errfp) {
 1248: 			while (fgets(buf, sizeof(buf), errfp))
 1249: 				fputs(buf, stderr);
 1250: 			fclose(errfp);
 1251: 		}
 1252: 
 1253: 		return (retcode);
 1254: 	}
 1255: 
 1256: 	/*
 1257: 	 * This is the child process, which is the one that executes the
 1258: 	 * given filter.
 1259: 	 */
 1260: 	/*
 1261: 	 * If the first parameter has any slashes in it, then change it
 1262: 	 * to point to the first character after the last slash.
 1263: 	 */
 1264: 	slash = strrchr(f_av[0], '/');
 1265: 	if (slash != NULL)
 1266: 		f_av[0] = slash + 1;
 1267: 	/*
 1268: 	 * XXX - in the future, this should setup an explicit list of
 1269: 	 *       environment variables and use execve()!
 1270: 	 */
 1271: 
 1272: 	/*
 1273: 	 * Setup stdin, stdout, and stderr as we want them when the filter
 1274: 	 * is running.  Stderr is setup so it points to a temporary errors
 1275: 	 * file, and the parent process will copy that temporary file to
 1276: 	 * the real logfile after the filter completes.
 1277: 	 */
 1278: 	dup2(infd, 0);
 1279: 	dup2(outfd, 1);
 1280: 	errfd = open(tempstderr, O_WRONLY|O_TRUNC, 0664);
 1281: 	if (errfd >= 0)
 1282: 		dup2(errfd, 2);
 1283: 	closelog();
 1284: 	closeallfds(3);
 1285: 	execv(f_cmd, f_av);
 1286: 	syslog(LOG_ERR, "%s: cannot execv(%s): %m", pp->printer, f_cmd);
 1287: 	exit(2);
 1288: 	/* NOTREACHED */
 1289: }
 1290: 
 1291: /*
 1292:  * Check to make sure there have been no errors and that both programs
 1293:  * are in sync with eachother.
 1294:  * Return non-zero if the connection was lost.
 1295:  */
 1296: static char
 1297: response(const struct printer *pp)
 1298: {
 1299: 	char resp;
 1300: 
 1301: 	if (read(pfd, &resp, 1) != 1) {
 1302: 		syslog(LOG_INFO, "%s: lost connection", pp->printer);
 1303: 		return (-1);
 1304: 	}
 1305: 	return (resp);
 1306: }
 1307: 
 1308: /*
 1309:  * Banner printing stuff
 1310:  */
 1311: static void
 1312: banner(struct printer *pp, char *name1, char *name2)
 1313: {
 1314: 	time_t tvec;
 1315: 
 1316: 	time(&tvec);
 1317: 	if (!pp->no_formfeed && !pp->tof)
 1318: 		(void) write(ofd, pp->form_feed, strlen(pp->form_feed));
 1319: 	if (pp->short_banner) {	/* short banner only */
 1320: 		if (class[0]) {
 1321: 			(void) write(ofd, class, strlen(class));
 1322: 			(void) write(ofd, ":", 1);
 1323: 		}
 1324: 		(void) write(ofd, name1, strlen(name1));
 1325: 		(void) write(ofd, "  Job: ", 7);
 1326: 		(void) write(ofd, name2, strlen(name2));
 1327: 		(void) write(ofd, "  Date: ", 8);
 1328: 		(void) write(ofd, ctime(&tvec), 24);
 1329: 		(void) write(ofd, "\n", 1);
 1330: 	} else {	/* normal banner */
 1331: 		(void) write(ofd, "\n\n\n", 3);
 1332: 		scan_out(pp, ofd, name1, '\0');
 1333: 		(void) write(ofd, "\n\n", 2);
 1334: 		scan_out(pp, ofd, name2, '\0');
 1335: 		if (class[0]) {
 1336: 			(void) write(ofd,"\n\n\n",3);
 1337: 			scan_out(pp, ofd, class, '\0');
 1338: 		}
 1339: 		(void) write(ofd, "\n\n\n\n\t\t\t\t\tJob:  ", 15);
 1340: 		(void) write(ofd, name2, strlen(name2));
 1341: 		(void) write(ofd, "\n\t\t\t\t\tDate: ", 12);
 1342: 		(void) write(ofd, ctime(&tvec), 24);
 1343: 		(void) write(ofd, "\n", 1);
 1344: 	}
 1345: 	if (!pp->no_formfeed)
 1346: 		(void) write(ofd, pp->form_feed, strlen(pp->form_feed));
 1347: 	pp->tof = 1;
 1348: }
 1349: 
 1350: static char *
 1351: scnline(int key, char *p, int c)
 1352: {
 1353: 	int scnwidth;
 1354: 
 1355: 	for (scnwidth = WIDTH; --scnwidth;) {
 1356: 		key <<= 1;
 1357: 		*p++ = key & 0200 ? c : BACKGND;
 1358: 	}
 1359: 	return (p);
 1360: }
 1361: 
 1362: #define TRC(q)	(((q)-' ')&0177)
 1363: 
 1364: static void
 1365: scan_out(struct printer *pp, int scfd, char *scsp, int dlm)
 1366: {
 1367: 	char *strp;
 1368: 	int nchrs, j;
 1369: 	char outbuf[LINELEN+1], *sp, c, cc;
 1370: 	int d, scnhgt;
 1371: 
 1372: 	for (scnhgt = 0; scnhgt++ < HEIGHT+DROP; ) {
 1373: 		strp = &outbuf[0];
 1374: 		sp = scsp;
 1375: 		for (nchrs = 0; ; ) {
 1376: 			d = dropit(c = TRC(cc = *sp++));
 1377: 			if ((!d && scnhgt > HEIGHT) || (scnhgt <= DROP && d))
 1378: 				for (j = WIDTH; --j;)
 1379: 					*strp++ = BACKGND;
 1380: 			else
 1381: 				strp = scnline(scnkey[(int)c][scnhgt-1-d], strp, cc);
 1382: 			if (*sp == dlm || *sp == '\0' || 
 1383: 			    nchrs++ >= pp->page_width/(WIDTH+1)-1)
 1384: 				break;
 1385: 			*strp++ = BACKGND;
 1386: 			*strp++ = BACKGND;
 1387: 		}
 1388: 		while (*--strp == BACKGND && strp >= outbuf)
 1389: 			;
 1390: 		strp++;
 1391: 		*strp++ = '\n';
 1392: 		(void) write(scfd, outbuf, strp-outbuf);
 1393: 	}
 1394: }
 1395: 
 1396: static int
 1397: dropit(int c)
 1398: {
 1399: 	switch(c) {
 1400: 
 1401: 	case TRC('_'):
 1402: 	case TRC(';'):
 1403: 	case TRC(','):
 1404: 	case TRC('g'):
 1405: 	case TRC('j'):
 1406: 	case TRC('p'):
 1407: 	case TRC('q'):
 1408: 	case TRC('y'):
 1409: 		return (DROP);
 1410: 
 1411: 	default:
 1412: 		return (0);
 1413: 	}
 1414: }
 1415: 
 1416: /*
 1417:  * sendmail ---
 1418:  *   tell people about job completion
 1419:  */
 1420: static void
 1421: sendmail(struct printer *pp, char *userid, int bombed)
 1422: {
 1423: 	int i;
 1424: 	int p[2], s;
 1425: 	const char *cp;
 1426: 	struct stat stb;
 1427: 	FILE *fp;
 1428: 
 1429: 	pipe(p);
 1430: 	if ((s = dofork(pp, DORETURN)) == 0) {		/* child */
 1431: 		dup2(p[0], 0);
 1432: 		closelog();
 1433: 		closeallfds(3);
 1434: 		if ((cp = strrchr(_PATH_SENDMAIL, '/')) != NULL)
 1435: 			cp++;
 1436: 		else
 1437: 			cp = _PATH_SENDMAIL;
 1438: 		execl(_PATH_SENDMAIL, cp, "-t", (char *)0);
 1439: 		_exit(0);
 1440: 	} else if (s > 0) {				/* parent */
 1441: 		dup2(p[1], 1);
 1442: 		printf("To: %s@%s\n", userid, origin_host);
 1443: 		printf("Subject: %s printer job \"%s\"\n", pp->printer,
 1444: 			*jobname ? jobname : "<unknown>");
 1445: 		printf("Reply-To: root@%s\n\n", local_host);
 1446: 		printf("Your printer job ");
 1447: 		if (*jobname)
 1448: 			printf("(%s) ", jobname);
 1449: 
 1450: 		switch (bombed) {
 1451: 		case OK:
 1452: 			cp = "OK";
 1453: 			printf("\ncompleted successfully\n");
 1454: 			break;
 1455: 		default:
 1456: 		case FATALERR:
 1457: 			cp = "FATALERR";
 1458: 			printf("\ncould not be printed\n");
 1459: 			break;
 1460: 		case NOACCT:
 1461: 			cp = "NOACCT";
 1462: 			printf("\ncould not be printed without an account on %s\n",
 1463: 			    local_host);
 1464: 			break;
 1465: 		case FILTERERR:
 1466: 			cp = "FILTERERR";
 1467: 			if (stat(tempstderr, &stb) < 0 || stb.st_size == 0
 1468: 			    || (fp = fopen(tempstderr, "r")) == NULL) {
 1469: 				printf("\nhad some errors and may not have printed\n");
 1470: 				break;
 1471: 			}
 1472: 			printf("\nhad the following errors and may not have printed:\n");
 1473: 			while ((i = getc(fp)) != EOF)
 1474: 				putchar(i);
 1475: 			(void) fclose(fp);
 1476: 			break;
 1477: 		case ACCESS:
 1478: 			cp = "ACCESS";
 1479: 			printf("\nwas not printed because it was not linked to the original file\n");
 1480: 		}
 1481: 		fflush(stdout);
 1482: 		(void) close(1);
 1483: 	} else {
 1484: 		syslog(LOG_WARNING, "unable to send mail to %s: %m", userid);
 1485: 		return;
 1486: 	}
 1487: 	(void) close(p[0]);
 1488: 	(void) close(p[1]);
 1489: 	wait(NULL);
 1490: 	syslog(LOG_INFO, "mail sent to user %s about job %s on printer %s (%s)",
 1491: 	    userid, *jobname ? jobname : "<unknown>", pp->printer, cp);
 1492: }
 1493: 
 1494: /*
 1495:  * dofork - fork with retries on failure
 1496:  */
 1497: static int
 1498: dofork(const struct printer *pp, int action)
 1499: {
 1500: 	pid_t forkpid;
 1501: 	int i, fail;
 1502: 	struct passwd *pwd;
 1503: 
 1504: 	forkpid = -1;
 1505: 	if (daemon_uname == NULL) {
 1506: 		pwd = getpwuid(pp->daemon_user);
 1507: 		if (pwd == NULL) {
 1508: 			syslog(LOG_ERR, "%s: Can't lookup default daemon uid (%ld) in password file",
 1509: 			    pp->printer, pp->daemon_user);
 1510: 			goto error_ret;
 1511: 		}
 1512: 		daemon_uname = strdup(pwd->pw_name);
 1513: 		daemon_defgid = pwd->pw_gid;
 1514: 	}
 1515: 
 1516: 	for (i = 0; i < 20; i++) {
 1517: 		forkpid = fork();
 1518: 		if (forkpid < 0) {
 1519: 			sleep((unsigned)(i*i));
 1520: 			continue;
 1521: 		}
 1522: 		/*
 1523: 		 * Child should run as daemon instead of root
 1524: 		 */
 1525: 		if (forkpid == 0) {
 1526: 			errno = 0;
 1527: 			fail = initgroups(daemon_uname, daemon_defgid);
 1528: 			if (fail) {
 1529: 				syslog(LOG_ERR, "%s: initgroups(%s,%u): %m",
 1530: 				    pp->printer, daemon_uname, daemon_defgid);
 1531: 				break;
 1532: 			}
 1533: 			fail = setgid(daemon_defgid);
 1534: 			if (fail) {
 1535: 				syslog(LOG_ERR, "%s: setgid(%u): %m",
 1536: 				    pp->printer, daemon_defgid);
 1537: 				break;
 1538: 			}
 1539: 			fail = setuid(pp->daemon_user);
 1540: 			if (fail) {
 1541: 				syslog(LOG_ERR, "%s: setuid(%ld): %m",
 1542: 				    pp->printer, pp->daemon_user);
 1543: 				break;
 1544: 			}
 1545: 		}
 1546: 		return (forkpid);
 1547: 	}
 1548: 
 1549: 	/*
 1550: 	 * An error occurred.  If the error is in the child process, then
 1551: 	 * this routine MUST always exit().  DORETURN only effects how
 1552: 	 * errors should be handled in the parent process.
 1553: 	 */
 1554: error_ret:
 1555: 	if (forkpid == 0) {
 1556: 		syslog(LOG_ERR, "%s: dofork(): aborting child process...",
 1557: 		    pp->printer);
 1558: 		exit(1);
 1559: 	}
 1560: 	syslog(LOG_ERR, "%s: dofork(): failure in fork", pp->printer);
 1561: 
 1562: 	sleep(1);		/* throttle errors, as a safety measure */
 1563: 	switch (action) {
 1564: 	case DORETURN:
 1565: 		return (-1);
 1566: 	default:
 1567: 		syslog(LOG_ERR, "bad action (%d) to dofork", action);
 1568: 		/* FALLTHROUGH */
 1569: 	case DOABORT:
 1570: 		exit(1);
 1571: 	}
 1572: 	/*NOTREACHED*/
 1573: }
 1574: 
 1575: /*
 1576:  * Kill child processes to abort current job.
 1577:  */
 1578: static void
 1579: abortpr(int signo __unused)
 1580: {
 1581: 
 1582: 	(void) unlink(tempstderr);
 1583: 	kill(0, SIGINT);
 1584: 	if (of_pid > 0)
 1585: 		kill(of_pid, SIGCONT);
 1586: 	while (wait(NULL) > 0)
 1587: 		;
 1588: 	if (of_pid > 0 && tfd != -1)
 1589: 		unlink(tfile);
 1590: 	exit(0);
 1591: }
 1592: 
 1593: static void
 1594: init(struct printer *pp)
 1595: {
 1596: 	char *s;
 1597: 
 1598: 	sprintf(&width[2], "%ld", pp->page_width);
 1599: 	sprintf(&length[2], "%ld", pp->page_length);
 1600: 	sprintf(&pxwidth[2], "%ld", pp->page_pwidth);
 1601: 	sprintf(&pxlength[2], "%ld", pp->page_plength);
 1602: 	if ((s = checkremote(pp)) != 0) {
 1603: 		syslog(LOG_WARNING, "%s", s);
 1604: 		free(s);
 1605: 	}
 1606: }
 1607: 
 1608: void
 1609: startprinting(const char *printer)
 1610: {
 1611: 	struct printer myprinter, *pp = &myprinter;
 1612: 	int status;
 1613: 
 1614: 	init_printer(pp);
 1615: 	status = getprintcap(printer, pp);
 1616: 	switch(status) {
 1617: 	case PCAPERR_OSERR:
 1618: 		syslog(LOG_ERR, "can't open printer description file: %m");
 1619: 		exit(1);
 1620: 	case PCAPERR_NOTFOUND:
 1621: 		syslog(LOG_ERR, "unknown printer: %s", printer);
 1622: 		exit(1);
 1623: 	case PCAPERR_TCLOOP:
 1624: 		fatal(pp, "potential reference loop detected in printcap file");
 1625: 	default:
 1626: 		break;
 1627: 	}
 1628: 	printjob(pp);
 1629: }
 1630: 
 1631: /*
 1632:  * Acquire line printer or remote connection.
 1633:  */
 1634: static void
 1635: openpr(const struct printer *pp)
 1636: {
 1637: 	int p[2];
 1638: 	char *cp;
 1639: 
 1640: 	if (pp->remote) {
 1641: 		openrem(pp);
 1642: 		/*
 1643: 		 * Lpd does support the setting of 'of=' filters for
 1644: 		 * jobs going to remote machines, but that does not
 1645: 		 * have the same meaning as 'of=' does when handling
 1646: 		 * local print queues.  For remote machines, all 'of='
 1647: 		 * filter processing is handled in sendfile(), and that
 1648: 		 * does not use these global "output filter" variables.
 1649: 		 */ 
 1650: 		ofd = -1;
 1651: 		of_pid = 0;
 1652: 		return;
 1653: 	} else if (*pp->lp) {
 1654: 		if ((cp = strchr(pp->lp, '@')) != NULL)
 1655: 			opennet(pp);
 1656: 		else
 1657: 			opentty(pp);
 1658: 	} else {
 1659: 		syslog(LOG_ERR, "%s: no line printer device or host name",
 1660: 		    pp->printer);
 1661: 		exit(1);
 1662: 	}
 1663: 
 1664: 	/*
 1665: 	 * Start up an output filter, if needed.
 1666: 	 */
 1667: 	if (pp->filters[LPF_OUTPUT] && !pp->filters[LPF_INPUT] && !of_pid) {
 1668: 		pipe(p);
 1669: 		if (pp->remote) {
 1670: 			strcpy(tfile, TFILENAME);
 1671: 			tfd = mkstemp(tfile);
 1672: 		}
 1673: 		if ((of_pid = dofork(pp, DOABORT)) == 0) {	/* child */
 1674: 			dup2(p[0], 0);		/* pipe is std in */
 1675: 			/* tfile/printer is stdout */
 1676: 			dup2(pp->remote ? tfd : pfd, 1);
 1677: 			closelog();
 1678: 			closeallfds(3);
 1679: 			if ((cp = strrchr(pp->filters[LPF_OUTPUT], '/')) == NULL)
 1680: 				cp = pp->filters[LPF_OUTPUT];
 1681: 			else
 1682: 				cp++;
 1683: 			execl(pp->filters[LPF_OUTPUT], cp, width, length,
 1684: 			      (char *)0);
 1685: 			syslog(LOG_ERR, "%s: execl(%s): %m", pp->printer,
 1686: 			    pp->filters[LPF_OUTPUT]);
 1687: 			exit(1);
 1688: 		}
 1689: 		(void) close(p[0]);		/* close input side */
 1690: 		ofd = p[1];			/* use pipe for output */
 1691: 	} else {
 1692: 		ofd = pfd;
 1693: 		of_pid = 0;
 1694: 	}
 1695: }
 1696: 
 1697: /*
 1698:  * Printer connected directly to the network
 1699:  * or to a terminal server on the net
 1700:  */
 1701: static void
 1702: opennet(const struct printer *pp)
 1703: {
 1704: 	int i;
 1705: 	int resp;
 1706: 	u_long port;
 1707: 	char *ep;
 1708: 	void (*savealrm)(int);
 1709: 
 1710: 	port = strtoul(pp->lp, &ep, 0);
 1711: 	if (*ep != '@' || port > 65535) {
 1712: 		syslog(LOG_ERR, "%s: bad port number: %s", pp->printer,
 1713: 		    pp->lp);
 1714: 		exit(1);
 1715: 	}
 1716: 	ep++;
 1717: 
 1718: 	for (i = 1; ; i = i < 256 ? i << 1 : i) {
 1719: 		resp = -1;
 1720: 		savealrm = signal(SIGALRM, alarmhandler);
 1721: 		alarm(pp->conn_timeout);
 1722: 		pfd = getport(pp, ep, port);
 1723: 		alarm(0);
 1724: 		(void)signal(SIGALRM, savealrm);
 1725: 		if (pfd < 0 && errno == ECONNREFUSED)
 1726: 			resp = 1;
 1727: 		else if (pfd >= 0) {
 1728: 			/*
 1729: 			 * need to delay a bit for rs232 lines
 1730: 			 * to stabilize in case printer is
 1731: 			 * connected via a terminal server
 1732: 			 */
 1733: 			delay(500);
 1734: 			break;
 1735: 		}
 1736: 		if (i == 1) {
 1737: 			if (resp < 0)
 1738: 				pstatus(pp, "waiting for %s to come up",
 1739: 					pp->lp);
 1740: 			else
 1741: 				pstatus(pp, 
 1742: 					"waiting for access to printer on %s",
 1743: 					pp->lp);
 1744: 		}
 1745: 		sleep(i);
 1746: 	}
 1747: 	pstatus(pp, "sending to %s port %lu", ep, port);
 1748: }
 1749: 
 1750: /*
 1751:  * Printer is connected to an RS232 port on this host
 1752:  */
 1753: static void
 1754: opentty(const struct printer *pp)
 1755: {
 1756: 	int i;
 1757: 
 1758: 	for (i = 1; ; i = i < 32 ? i << 1 : i) {
 1759: 		pfd = open(pp->lp, pp->rw ? O_RDWR : O_WRONLY);
 1760: 		if (pfd >= 0) {
 1761: 			delay(500);
 1762: 			break;
 1763: 		}
 1764: 		if (errno == ENOENT) {
 1765: 			syslog(LOG_ERR, "%s: %m", pp->lp);
 1766: 			exit(1);
 1767: 		}
 1768: 		if (i == 1)
 1769: 			pstatus(pp, 
 1770: 				"waiting for %s to become ready (offline?)",
 1771: 				pp->printer);
 1772: 		sleep(i);
 1773: 	}
 1774: 	if (isatty(pfd))
 1775: 		setty(pp);
 1776: 	pstatus(pp, "%s is ready and printing", pp->printer);
 1777: }
 1778: 
 1779: /*
 1780:  * Printer is on a remote host
 1781:  */
 1782: static void
 1783: openrem(const struct printer *pp)
 1784: {
 1785: 	int i;
 1786: 	int resp;
 1787: 	void (*savealrm)(int);
 1788: 
 1789: 	for (i = 1; ; i = i < 256 ? i << 1 : i) {
 1790: 		resp = -1;
 1791: 		savealrm = signal(SIGALRM, alarmhandler);
 1792: 		alarm(pp->conn_timeout);
 1793: 		pfd = getport(pp, pp->remote_host, 0);
 1794: 		alarm(0);
 1795: 		(void)signal(SIGALRM, savealrm);
 1796: 		if (pfd >= 0) {
 1797: 			if ((writel(pfd, "\2", pp->remote_queue, "\n", 
 1798: 				    (char *)0)
 1799: 			     == 2 + strlen(pp->remote_queue))
 1800: 			    && (resp = response(pp)) == 0)
 1801: 				break;
 1802: 			(void) close(pfd);
 1803: 		}
 1804: 		if (i == 1) {
 1805: 			if (resp < 0)
 1806: 				pstatus(pp, "waiting for %s to come up", 
 1807: 					pp->remote_host);
 1808: 			else {
 1809: 				pstatus(pp,
 1810: 					"waiting for queue to be enabled on %s",
 1811: 					pp->remote_host);
 1812: 				i = 256;
 1813: 			}
 1814: 		}
 1815: 		sleep(i);
 1816: 	}
 1817: 	pstatus(pp, "sending to %s", pp->remote_host);
 1818: }
 1819: 
 1820: /*
 1821:  * setup tty lines.
 1822:  */
 1823: static void
 1824: setty(const struct printer *pp)
 1825: {
 1826: 	struct termios ttybuf;
 1827: 
 1828: 	if (ioctl(pfd, TIOCEXCL, (char *)0) < 0) {
 1829: 		syslog(LOG_ERR, "%s: ioctl(TIOCEXCL): %m", pp->printer);
 1830: 		exit(1);
 1831: 	}
 1832: 	if (tcgetattr(pfd, &ttybuf) < 0) {
 1833: 		syslog(LOG_ERR, "%s: tcgetattr: %m", pp->printer);
 1834: 		exit(1);
 1835: 	}
 1836: 	if (pp->baud_rate > 0)
 1837: 		cfsetspeed(&ttybuf, pp->baud_rate);
 1838: 	if (pp->mode_set) {
 1839: 		char *s = strdup(pp->mode_set), *tmp;
 1840: 
 1841: 		while ((tmp = strsep(&s, ",")) != NULL) {
 1842: 			(void) msearch(tmp, &ttybuf);
 1843: 		}
 1844: 	}
 1845: 	if (pp->mode_set != 0 || pp->baud_rate > 0) {
 1846: 		if (tcsetattr(pfd, TCSAFLUSH, &ttybuf) == -1) {
 1847: 			syslog(LOG_ERR, "%s: tcsetattr: %m", pp->printer);
 1848: 		}
 1849: 	}
 1850: }
 1851: 
 1852: #include <stdarg.h>
 1853: 
 1854: static void
 1855: pstatus(const struct printer *pp, const char *msg, ...)
 1856: {
 1857: 	int fd;
 1858: 	char *buf;
 1859: 	va_list ap;
 1860: 	va_start(ap, msg);
 1861: 
 1862: 	umask(0);
 1863: 	fd = open(pp->status_file, O_WRONLY|O_CREAT|O_EXLOCK, STAT_FILE_MODE);
 1864: 	if (fd < 0) {
 1865: 		syslog(LOG_ERR, "%s: open(%s): %m", pp->printer,
 1866: 		    pp->status_file);
 1867: 		exit(1);
 1868: 	}
 1869: 	ftruncate(fd, 0);
 1870: 	vasprintf(&buf, msg, ap);
 1871: 	va_end(ap);
 1872: 	writel(fd, buf, "\n", (char *)0);
 1873: 	close(fd);
 1874: 	free(buf);
 1875: }
 1876: 
 1877: void
 1878: alarmhandler(int signo __unused)
 1879: {
 1880: 	/* the signal is ignored */
 1881: 	/* (the '__unused' is just to avoid a compile-time warning) */
 1882: }