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