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