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