printjob.c revision 117587
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#if 0
42#ifndef lint
43static char sccsid[] = "@(#)printjob.c	8.7 (Berkeley) 5/10/95";
44#endif /* not lint */
45#endif
46
47#include "lp.cdefs.h"		/* A cross-platform version of <sys/cdefs.h> */
48__FBSDID("$FreeBSD: head/usr.sbin/lpr/lpd/printjob.c 117587 2003-07-14 19:59:33Z gad $");
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 pid_t	 of_pid;	/* process id of output filter, if any */
98static int	 child;		/* id of any filters */
99static int	 job_dfcnt;	/* count of datafiles in current user job */
100static int	 lfd;		/* lock file descriptor */
101static int	 ofd;		/* output filter file descriptor */
102static int	 tfd = -1;	/* output filter temp file output */
103static int	 pfd;		/* prstatic inter file descriptor */
104static int	 prchild;	/* id of pr process */
105static char	 title[80];	/* ``pr'' title */
106static char      locale[80];    /* ``pr'' locale */
107
108/* these two are set from pp->daemon_user, but only if they are needed */
109static char	*daemon_uname;	/* set from pwd->pw_name */
110static int	 daemon_defgid;
111
112static char	class[32];		/* classification field */
113static char	origin_host[MAXHOSTNAMELEN];	/* user's host machine */
114				/* indentation size in static characters */
115static char	indent[10] = "-i0";
116static char	jobname[100];		/* job or file name */
117static char	length[10] = "-l";	/* page length in lines */
118static char	logname[32];		/* user's login name */
119static char	pxlength[10] = "-y";	/* page length in pixels */
120static char	pxwidth[10] = "-x";	/* page width in pixels */
121/* tempstderr is the filename used to catch stderr from exec-ing filters */
122static char	tempstderr[] = "errs.XXXXXXX";
123static char	width[10] = "-w";	/* page width in static characters */
124#define TFILENAME "fltXXXXXX"
125static char	tfile[] = TFILENAME;	/* file name for filter output */
126
127static void	 abortpr(int _signo);
128static void	 alarmhandler(int _signo);
129static void	 banner(struct printer *_pp, char *_name1, char *_name2);
130static int	 dofork(const struct printer *_pp, int _action);
131static int	 dropit(int _c);
132static int	 execfilter(struct printer *_pp, char *_f_cmd, char **_f_av,
133		    int _infd, int _outfd);
134static void	 init(struct printer *_pp);
135static void	 openpr(const struct printer *_pp);
136static void	 opennet(const struct printer *_pp);
137static void	 opentty(const struct printer *_pp);
138static void	 openrem(const struct printer *pp);
139static int	 print(struct printer *_pp, int _format, char *_file);
140static int	 printit(struct printer *_pp, char *_file);
141static void	 pstatus(const struct printer *_pp, const char *_msg, ...)
142		    __printflike(2, 3);
143static char	 response(const struct printer *_pp);
144static void	 scan_out(struct printer *_pp, int _scfd, char *_scsp,
145		    int _dlm);
146static char	*scnline(int _key, char *_p, int _c);
147static int	 sendfile(struct printer *_pp, int _type, char *_file,
148		    char _format, int _copyreq);
149static int	 sendit(struct printer *_pp, char *_file);
150static void	 sendmail(struct printer *_pp, char *_userid, int _bombed);
151static void	 setty(const struct printer *_pp);
152
153void
154printjob(struct printer *pp)
155{
156	struct stat stb;
157	register struct jobqueue *q, **qp;
158	struct jobqueue **queue;
159	register int i, nitems;
160	off_t pidoff;
161	pid_t printpid;
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	printpid = getpid();			/* for use with lprm */
175	setpgrp(0, printpid);
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", printpid);
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 (of_pid > 0) {
304				kill(of_pid, SIGCONT); /* to be sure */
305				(void) close(ofd);
306				while ((i = wait(NULL)) > 0 && i != of_pid)
307					;
308				if (i < 0)
309					syslog(LOG_WARNING, "%s: after kill(of=%d), wait() returned: %m",
310					    pp->printer, of_pid);
311				of_pid = 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	pid_t wpid;
612	int p[2], retcode, stopped, wstatus, wstatus_set;
613	struct stat stb;
614
615	if (lstat(file, &stb) < 0 || (fi = open(file, O_RDONLY)) < 0) {
616		syslog(LOG_INFO, "%s: unable to open %s ('%c' line)",
617		    pp->printer, file, format);
618		return (ERROR);
619	}
620	/*
621	 * Check to see if data file is a symbolic link. If so, it should
622	 * still point to the same file or someone is trying to print
623	 * something he shouldn't.
624	 */
625	if ((stb.st_mode & S_IFMT) == S_IFLNK && fstat(fi, &stb) == 0 &&
626	    (stb.st_dev != fdev || stb.st_ino != fino))
627		return (ACCESS);
628
629	job_dfcnt++;		/* increment datafile counter for this job */
630	stopped = 0;		/* output filter is not stopped */
631
632	/* everything seems OK, start it up */
633	if (!pp->no_formfeed && !pp->tof) { /* start on a fresh page */
634		(void) write(ofd, pp->form_feed, strlen(pp->form_feed));
635		pp->tof = 1;
636	}
637	if (pp->filters[LPF_INPUT] == NULL
638	    && (format == 'f' || format == 'l' || format == 'o')) {
639		pp->tof = 0;
640		while ((n = read(fi, buf, BUFSIZ)) > 0)
641			if (write(ofd, buf, n) != n) {
642				(void) close(fi);
643				return (REPRINT);
644			}
645		(void) close(fi);
646		return (OK);
647	}
648	switch (format) {
649	case 'p':	/* print file using 'pr' */
650		if (pp->filters[LPF_INPUT] == NULL) {	/* use output filter */
651			prog = _PATH_PR;
652			i = 0;
653			av[i++] = "pr";
654			av[i++] = width;
655			av[i++] = length;
656			av[i++] = "-h";
657			av[i++] = *title ? title : " ";
658			av[i++] = "-L";
659			av[i++] = *locale ? locale : "C";
660			av[i++] = "-F";
661			av[i] = 0;
662			fo = ofd;
663			goto start;
664		}
665		pipe(p);
666		if ((prchild = dofork(pp, DORETURN)) == 0) {	/* child */
667			dup2(fi, 0);		/* file is stdin */
668			dup2(p[1], 1);		/* pipe is stdout */
669			closelog();
670			closeallfds(3);
671			execl(_PATH_PR, "pr", width, length,
672			    "-h", *title ? title : " ",
673			    "-L", *locale ? locale : "C",
674			    "-F", (char *)0);
675			syslog(LOG_ERR, "cannot execl %s", _PATH_PR);
676			exit(2);
677		}
678		(void) close(p[1]);		/* close output side */
679		(void) close(fi);
680		if (prchild < 0) {
681			prchild = 0;
682			(void) close(p[0]);
683			return (ERROR);
684		}
685		fi = p[0];			/* use pipe for input */
686	case 'f':	/* print plain text file */
687		prog = pp->filters[LPF_INPUT];
688		av[1] = width;
689		av[2] = length;
690		av[3] = indent;
691		n = 4;
692		break;
693	case 'o':	/* print postscript file */
694		/*
695		 * Treat this as a "plain file with control characters", and
696		 * assume the standard LPF_INPUT filter will recognize that
697		 * the data is postscript and know what to do with it.  These
698		 * 'o'-file requests could come from MacOS 10.1 systems.
699		 * (later versions of MacOS 10 will explicitly use 'l')
700		 * A postscript file can contain binary data, which is why 'l'
701		 * is somewhat more appropriate than 'f'.
702		 */
703		/* FALLTHROUGH */
704	case 'l':	/* like 'f' but pass control characters */
705		prog = pp->filters[LPF_INPUT];
706		av[1] = "-c";
707		av[2] = width;
708		av[3] = length;
709		av[4] = indent;
710		n = 5;
711		break;
712	case 'r':	/* print a fortran text file */
713		prog = pp->filters[LPF_FORTRAN];
714		av[1] = width;
715		av[2] = length;
716		n = 3;
717		break;
718	case 't':	/* print troff output */
719	case 'n':	/* print ditroff output */
720	case 'd':	/* print tex output */
721		(void) unlink(".railmag");
722		if ((fo = creat(".railmag", FILMOD)) < 0) {
723			syslog(LOG_ERR, "%s: cannot create .railmag",
724			    pp->printer);
725			(void) unlink(".railmag");
726		} else {
727			for (n = 0; n < 4; n++) {
728				if (fonts[n][0] != '/')
729					(void) write(fo, _PATH_VFONT,
730					    sizeof(_PATH_VFONT) - 1);
731				(void) write(fo, fonts[n], strlen(fonts[n]));
732				(void) write(fo, "\n", 1);
733			}
734			(void) close(fo);
735		}
736		prog = (format == 't') ? pp->filters[LPF_TROFF]
737			: ((format == 'n') ? pp->filters[LPF_DITROFF]
738			   : pp->filters[LPF_DVI]);
739		av[1] = pxwidth;
740		av[2] = pxlength;
741		n = 3;
742		break;
743	case 'c':	/* print cifplot output */
744		prog = pp->filters[LPF_CIFPLOT];
745		av[1] = pxwidth;
746		av[2] = pxlength;
747		n = 3;
748		break;
749	case 'g':	/* print plot(1G) output */
750		prog = pp->filters[LPF_GRAPH];
751		av[1] = pxwidth;
752		av[2] = pxlength;
753		n = 3;
754		break;
755	case 'v':	/* print raster output */
756		prog = pp->filters[LPF_RASTER];
757		av[1] = pxwidth;
758		av[2] = pxlength;
759		n = 3;
760		break;
761	default:
762		(void) close(fi);
763		syslog(LOG_ERR, "%s: illegal format character '%c'",
764		    pp->printer, format);
765		return (ERROR);
766	}
767	if (prog == NULL) {
768		(void) close(fi);
769		syslog(LOG_ERR,
770		   "%s: no filter found in printcap for format character '%c'",
771		   pp->printer, format);
772		return (ERROR);
773	}
774	if ((av[0] = strrchr(prog, '/')) != NULL)
775		av[0]++;
776	else
777		av[0] = prog;
778	av[n++] = "-n";
779	av[n++] = logname;
780	av[n++] = "-h";
781	av[n++] = origin_host;
782	av[n++] = pp->acct_file;
783	av[n] = 0;
784	fo = pfd;
785	if (of_pid > 0) {		/* stop output filter */
786		write(ofd, "\031\1", 2);
787		while ((wpid =
788		    wait3(&wstatus, WUNTRACED, 0)) > 0 && wpid != of_pid)
789			;
790		if (wpid < 0)
791			syslog(LOG_WARNING,
792			    "%s: after stopping 'of', wait3() returned: %m",
793			    pp->printer);
794		else if (!WIFSTOPPED(wstatus)) {
795			(void) close(fi);
796			syslog(LOG_WARNING, "%s: output filter died "
797			    "(pid=%d retcode=%d termsig=%d)",
798			    pp->printer, of_pid, WEXITSTATUS(wstatus),
799			    WTERMSIG(wstatus));
800			return (REPRINT);
801		}
802		stopped++;
803	}
804start:
805	if ((child = dofork(pp, DORETURN)) == 0) { /* child */
806		dup2(fi, 0);
807		dup2(fo, 1);
808		/* setup stderr for the filter (child process)
809		 * so it goes to our temporary errors file */
810		n = open(tempstderr, O_WRONLY|O_TRUNC, 0664);
811		if (n >= 0)
812			dup2(n, 2);
813		closelog();
814		closeallfds(3);
815		execv(prog, av);
816		syslog(LOG_ERR, "%s: cannot execv(%s): %m", pp->printer,
817		    prog);
818		exit(2);
819	}
820	(void) close(fi);
821	wstatus_set = 0;
822	if (child < 0)
823		retcode = 100;
824	else {
825		while ((wpid = wait(&wstatus)) > 0 && wpid != child)
826			;
827		if (wpid < 0) {
828			retcode = 100;
829			syslog(LOG_WARNING,
830			    "%s: after execv(%s), wait() returned: %m",
831			    pp->printer, prog);
832		} else {
833			wstatus_set = 1;
834			retcode = WEXITSTATUS(wstatus);
835		}
836	}
837	child = 0;
838	prchild = 0;
839	if (stopped) {		/* restart output filter */
840		if (kill(of_pid, SIGCONT) < 0) {
841			syslog(LOG_ERR, "cannot restart output filter");
842			exit(1);
843		}
844	}
845	pp->tof = 0;
846
847	/* Copy the filter's output to "lf" logfile */
848	if ((fp = fopen(tempstderr, "r"))) {
849		while (fgets(buf, sizeof(buf), fp))
850			fputs(buf, stderr);
851		fclose(fp);
852	}
853
854	if (wstatus_set && !WIFEXITED(wstatus)) {
855		syslog(LOG_WARNING, "%s: filter '%c' terminated (termsig=%d)",
856		    pp->printer, format, WTERMSIG(wstatus));
857		return (ERROR);
858	}
859	switch (retcode) {
860	case 0:
861		pp->tof = 1;
862		return (OK);
863	case 1:
864		return (REPRINT);
865	case 2:
866		return (ERROR);
867	default:
868		syslog(LOG_WARNING, "%s: filter '%c' exited (retcode=%d)",
869		    pp->printer, format, retcode);
870		return (FILTERERR);
871	}
872}
873
874/*
875 * Send the daemon control file (cf) and any data files.
876 * Return -1 if a non-recoverable error occured, 1 if a recoverable error and
877 * 0 if all is well.
878 */
879static int
880sendit(struct printer *pp, char *file)
881{
882	int dfcopies, err, i;
883	char *cp, last[BUFSIZ];
884
885	/*
886	 * open control file
887	 */
888	if ((cfp = fopen(file, "r")) == NULL)
889		return (OK);
890
891	/* initialize job-specific count of datafiles processed */
892	job_dfcnt = 0;
893
894	/*
895	 *      read the control file for work to do
896	 *
897	 *      file format -- first character in the line is a command
898	 *      rest of the line is the argument.
899	 *      commands of interest are:
900	 *
901	 *            a-z -- "file name" name of file to print
902	 *              U -- "unlink" name of file to remove
903	 *                    (after we print it. (Pass 2 only)).
904	 */
905
906	/*
907	 * pass 1
908	 */
909	err = OK;
910	while (getline(cfp)) {
911	again:
912		if (line[0] == 'S') {
913			cp = line+1;
914			i = 0;
915			while (*cp >= '0' && *cp <= '9')
916				i = i * 10 + (*cp++ - '0');
917			fdev = i;
918			cp++;
919			i = 0;
920			while (*cp >= '0' && *cp <= '9')
921				i = i * 10 + (*cp++ - '0');
922			fino = i;
923		} else if (line[0] == 'H') {
924			strlcpy(origin_host, line + 1, sizeof(origin_host));
925			if (class[0] == '\0') {
926				strlcpy(class, line + 1, sizeof(class));
927			}
928		} else if (line[0] == 'P') {
929			strlcpy(logname, line + 1, sizeof(logname));
930			if (pp->restricted) { /* restricted */
931				if (getpwnam(logname) == NULL) {
932					sendmail(pp, line+1, NOACCT);
933					err = ERROR;
934					break;
935				}
936			}
937		} else if (line[0] == 'I') {
938			strlcpy(indent+2, line + 1, sizeof(indent) - 2);
939		} else if (line[0] >= 'a' && line[0] <= 'z') {
940			dfcopies = 1;
941			strcpy(last, line);
942			while ((i = getline(cfp)) != 0) {
943				if (strcmp(last, line) != 0)
944					break;
945				dfcopies++;
946			}
947			switch (sendfile(pp, '\3', last+1, *last, dfcopies)) {
948			case OK:
949				if (i)
950					goto again;
951				break;
952			case REPRINT:
953				(void) fclose(cfp);
954				return (REPRINT);
955			case ACCESS:
956				sendmail(pp, logname, ACCESS);
957			case ERROR:
958				err = ERROR;
959			}
960			break;
961		}
962	}
963	if (err == OK && sendfile(pp, '\2', file, '\0', 1) > 0) {
964		(void) fclose(cfp);
965		return (REPRINT);
966	}
967	/*
968	 * pass 2
969	 */
970	fseek(cfp, 0L, 0);
971	while (getline(cfp))
972		if (line[0] == 'U' && !strchr(line+1, '/'))
973			(void) unlink(line+1);
974	/*
975	 * clean-up in case another control file exists
976	 */
977	(void) fclose(cfp);
978	(void) unlink(file);
979	return (err);
980}
981
982/*
983 * Send a data file to the remote machine and spool it.
984 * Return positive if we should try resending.
985 */
986static int
987sendfile(struct printer *pp, int type, char *file, char format, int copyreq)
988{
989	int i, amt;
990	struct stat stb;
991	char *av[15], *filtcmd;
992	char buf[BUFSIZ], opt_c[4], opt_h[4], opt_n[4];
993	int copycnt, filtstat, narg, resp, sfd, sfres, sizerr, statrc;
994
995	statrc = lstat(file, &stb);
996	if (statrc < 0) {
997		syslog(LOG_ERR, "%s: error from lstat(%s): %m",
998		    pp->printer, file);
999		return (ERROR);
1000	}
1001	sfd = open(file, O_RDONLY);
1002	if (sfd < 0) {
1003		syslog(LOG_ERR, "%s: error from open(%s,O_RDONLY): %m",
1004		    pp->printer, file);
1005		return (ERROR);
1006	}
1007	/*
1008	 * Check to see if data file is a symbolic link. If so, it should
1009	 * still point to the same file or someone is trying to print something
1010	 * he shouldn't.
1011	 */
1012	if ((stb.st_mode & S_IFMT) == S_IFLNK && fstat(sfd, &stb) == 0 &&
1013	    (stb.st_dev != fdev || stb.st_ino != fino)) {
1014		close(sfd);
1015		return (ACCESS);
1016	}
1017
1018	/* Everything seems OK for reading the file, now to send it */
1019	filtcmd = NULL;
1020	sizerr = 0;
1021	tfd = -1;
1022	if (type == '\3') {
1023		/*
1024		 * Type == 3 means this is a datafile, not a control file.
1025		 * Increment the counter of data-files in this job, and
1026		 * then check for input or output filters (which are only
1027		 * applied to datafiles, not control files).
1028		 */
1029		job_dfcnt++;
1030
1031		/*
1032		 * Note that here we are filtering datafiles, one at a time,
1033		 * as they are sent to the remote machine.  Here, the *only*
1034		 * difference between an input filter (`if=') and an output
1035		 * filter (`of=') is the argument list that the filter is
1036		 * started up with.  Here, the output filter is executed
1037		 * for each individual file as it is sent.  This is not the
1038		 * same as local print queues, where the output filter is
1039		 * started up once, and then all jobs are passed thru that
1040		 * single invocation of the output filter.
1041		 *
1042		 * Also note that a queue for a remote-machine can have an
1043		 * input filter or an output filter, but not both.
1044		 */
1045		if (pp->filters[LPF_INPUT]) {
1046			filtcmd = pp->filters[LPF_INPUT];
1047			av[0] = filtcmd;
1048			narg = 0;
1049			strcpy(opt_c, "-c");
1050			strcpy(opt_h, "-h");
1051			strcpy(opt_n, "-n");
1052			if (format == 'l')
1053				av[++narg] = opt_c;
1054			av[++narg] = width;
1055			av[++narg] = length;
1056			av[++narg] = indent;
1057			av[++narg] = opt_n;
1058			av[++narg] = logname;
1059			av[++narg] = opt_h;
1060			av[++narg] = origin_host;
1061			av[++narg] = pp->acct_file;
1062			av[++narg] = NULL;
1063		} else if (pp->filters[LPF_OUTPUT]) {
1064			filtcmd = pp->filters[LPF_OUTPUT];
1065			av[0] = filtcmd;
1066			narg = 0;
1067			av[++narg] = width;
1068			av[++narg] = length;
1069			av[++narg] = NULL;
1070		}
1071	}
1072	if (filtcmd) {
1073		/*
1074		 * If there is an input or output filter, we have to run
1075		 * the datafile thru that filter and store the result as
1076		 * a temporary spool file, because the protocol requires
1077		 * that we send the remote host the file-size before we
1078		 * start to send any of the data.
1079		 */
1080		strcpy(tfile, TFILENAME);
1081		tfd = mkstemp(tfile);
1082		if (tfd == -1) {
1083			syslog(LOG_ERR, "%s: mkstemp(%s): %m", pp->printer,
1084			    TFILENAME);
1085			sfres = ERROR;
1086			goto return_sfres;
1087		}
1088		filtstat = execfilter(pp, filtcmd, av, sfd, tfd);
1089
1090		/* process the return-code from the filter */
1091		switch (filtstat) {
1092		case 0:
1093			break;
1094		case 1:
1095			sfres = REPRINT;
1096			goto return_sfres;
1097		case 2:
1098			sfres = ERROR;
1099			goto return_sfres;
1100		default:
1101			syslog(LOG_WARNING,
1102			    "%s: filter '%c' exited (retcode=%d)",
1103			    pp->printer, format, filtstat);
1104			sfres = FILTERERR;
1105			goto return_sfres;
1106		}
1107		statrc = fstat(tfd, &stb);   /* to find size of tfile */
1108		if (statrc < 0)	{
1109			syslog(LOG_ERR,
1110			    "%s: error processing 'if', fstat(%s): %m",
1111			    pp->printer, tfile);
1112			sfres = ERROR;
1113			goto return_sfres;
1114		}
1115		close(sfd);
1116		sfd = tfd;
1117		lseek(sfd, 0, SEEK_SET);
1118	}
1119
1120	copycnt = 0;
1121sendagain:
1122	copycnt++;
1123
1124	if (copycnt < 2)
1125		(void) sprintf(buf, "%c%qd %s\n", type, stb.st_size, file);
1126	else
1127		(void) sprintf(buf, "%c%qd %s_c%d\n", type, stb.st_size,
1128		    file, copycnt);
1129	amt = strlen(buf);
1130	for (i = 0;  ; i++) {
1131		if (write(pfd, buf, amt) != amt ||
1132		    (resp = response(pp)) < 0 || resp == '\1') {
1133			sfres = REPRINT;
1134			goto return_sfres;
1135		} else if (resp == '\0')
1136			break;
1137		if (i == 0)
1138			pstatus(pp,
1139				"no space on remote; waiting for queue to drain");
1140		if (i == 10)
1141			syslog(LOG_ALERT, "%s: can't send to %s; queue full",
1142			    pp->printer, pp->remote_host);
1143		sleep(5 * 60);
1144	}
1145	if (i)
1146		pstatus(pp, "sending to %s", pp->remote_host);
1147	/*
1148	 * XXX - we should change trstat_init()/trstat_write() to include
1149	 *	 the copycnt in the statistics record it may write.
1150	 */
1151	if (type == '\3')
1152		trstat_init(pp, file, job_dfcnt);
1153	for (i = 0; i < stb.st_size; i += BUFSIZ) {
1154		amt = BUFSIZ;
1155		if (i + amt > stb.st_size)
1156			amt = stb.st_size - i;
1157		if (sizerr == 0 && read(sfd, buf, amt) != amt)
1158			sizerr = 1;
1159		if (write(pfd, buf, amt) != amt) {
1160			sfres = REPRINT;
1161			goto return_sfres;
1162		}
1163	}
1164
1165	if (sizerr) {
1166		syslog(LOG_INFO, "%s: %s: changed size", pp->printer, file);
1167		/* tell recvjob to ignore this file */
1168		(void) write(pfd, "\1", 1);
1169		sfres = ERROR;
1170		goto return_sfres;
1171	}
1172	if (write(pfd, "", 1) != 1 || response(pp)) {
1173		sfres = REPRINT;
1174		goto return_sfres;
1175	}
1176	if (type == '\3') {
1177		trstat_write(pp, TR_SENDING, stb.st_size, logname,
1178		    pp->remote_host, origin_host);
1179		/*
1180		 * Usually we only need to send one copy of a datafile,
1181		 * because the control-file will simply print the same
1182		 * file multiple times.  However, some printers ignore
1183		 * the control file, and simply print each data file as
1184		 * it arrives.  For such "remote hosts", we need to
1185		 * transfer the same data file multiple times.  Such a
1186		 * a host is indicated by adding 'rc' to the printcap
1187		 * entry.
1188		 * XXX - Right now this ONLY works for remote hosts which
1189		 *	do ignore the name of the data file, because
1190		 *	this sends the file multiple times with slight
1191		 *	changes to the filename.  To do this right would
1192		 *	require that we also rewrite the control file
1193		 *	to match those filenames.
1194		 */
1195		if (pp->resend_copies && (copycnt < copyreq)) {
1196			lseek(sfd, 0, SEEK_SET);
1197			goto sendagain;
1198		}
1199	}
1200	sfres = OK;
1201
1202return_sfres:
1203	(void)close(sfd);
1204	if (tfd != -1) {
1205		/*
1206		 * If tfd is set, then it is the same value as sfd, and
1207		 * therefore it is already closed at this point.  All
1208		 * we need to do is remove the temporary file.
1209		 */
1210		tfd = -1;
1211		unlink(tfile);
1212	}
1213	return (sfres);
1214}
1215
1216/*
1217 *  This routine is called to execute one of the filters as was
1218 *  specified in a printcap entry.  While the child-process will read
1219 *  all of 'infd', it is up to the caller to close that file descriptor
1220 *  in the parent process.
1221 */
1222static int
1223execfilter(struct printer *pp, char *f_cmd, char *f_av[], int infd, int outfd)
1224{
1225	pid_t fpid, wpid;
1226	int errfd, retcode, wstatus;
1227	FILE *errfp;
1228	char buf[BUFSIZ], *slash;
1229
1230	fpid = dofork(pp, DORETURN);
1231	if (fpid != 0) {
1232		/*
1233		 * This is the parent process, which just waits for the child
1234		 * to complete and then returns the result.  Note that it is
1235		 * the child process which reads the input stream.
1236		 */
1237		if (fpid < 0)
1238			retcode = 100;
1239		else {
1240			while ((wpid = wait(&wstatus)) > 0 &&
1241			    wpid != fpid)
1242				;
1243			if (wpid < 0) {
1244				retcode = 100;
1245				syslog(LOG_WARNING,
1246				    "%s: after execv(%s), wait() returned: %m",
1247				    pp->printer, f_cmd);
1248			} else
1249				retcode = WEXITSTATUS(wstatus);
1250		}
1251
1252		/*
1253		 * Copy everything the filter wrote to stderr from our
1254		 * temporary errors file to the "lf=" logfile.
1255		 */
1256		errfp = fopen(tempstderr, "r");
1257		if (errfp) {
1258			while (fgets(buf, sizeof(buf), errfp))
1259				fputs(buf, stderr);
1260			fclose(errfp);
1261		}
1262
1263		return (retcode);
1264	}
1265
1266	/*
1267	 * This is the child process, which is the one that executes the
1268	 * given filter.
1269	 */
1270	/*
1271	 * If the first parameter has any slashes in it, then change it
1272	 * to point to the first character after the last slash.
1273	 */
1274	slash = strrchr(f_av[0], '/');
1275	if (slash != NULL)
1276		f_av[0] = slash + 1;
1277	/*
1278	 * XXX - in the future, this should setup an explicit list of
1279	 *       environment variables and use execve()!
1280	 */
1281
1282	/*
1283	 * Setup stdin, stdout, and stderr as we want them when the filter
1284	 * is running.  Stderr is setup so it points to a temporary errors
1285	 * file, and the parent process will copy that temporary file to
1286	 * the real logfile after the filter completes.
1287	 */
1288	dup2(infd, 0);
1289	dup2(outfd, 1);
1290	errfd = open(tempstderr, O_WRONLY|O_TRUNC, 0664);
1291	if (errfd >= 0)
1292		dup2(errfd, 2);
1293	closelog();
1294	closeallfds(3);
1295	execv(f_cmd, f_av);
1296	syslog(LOG_ERR, "%s: cannot execv(%s): %m", pp->printer, f_cmd);
1297	exit(2);
1298	/* NOTREACHED */
1299}
1300
1301/*
1302 * Check to make sure there have been no errors and that both programs
1303 * are in sync with eachother.
1304 * Return non-zero if the connection was lost.
1305 */
1306static char
1307response(const struct printer *pp)
1308{
1309	char resp;
1310
1311	if (read(pfd, &resp, 1) != 1) {
1312		syslog(LOG_INFO, "%s: lost connection", pp->printer);
1313		return (-1);
1314	}
1315	return (resp);
1316}
1317
1318/*
1319 * Banner printing stuff
1320 */
1321static void
1322banner(struct printer *pp, char *name1, char *name2)
1323{
1324	time_t tvec;
1325
1326	time(&tvec);
1327	if (!pp->no_formfeed && !pp->tof)
1328		(void) write(ofd, pp->form_feed, strlen(pp->form_feed));
1329	if (pp->short_banner) {	/* short banner only */
1330		if (class[0]) {
1331			(void) write(ofd, class, strlen(class));
1332			(void) write(ofd, ":", 1);
1333		}
1334		(void) write(ofd, name1, strlen(name1));
1335		(void) write(ofd, "  Job: ", 7);
1336		(void) write(ofd, name2, strlen(name2));
1337		(void) write(ofd, "  Date: ", 8);
1338		(void) write(ofd, ctime(&tvec), 24);
1339		(void) write(ofd, "\n", 1);
1340	} else {	/* normal banner */
1341		(void) write(ofd, "\n\n\n", 3);
1342		scan_out(pp, ofd, name1, '\0');
1343		(void) write(ofd, "\n\n", 2);
1344		scan_out(pp, ofd, name2, '\0');
1345		if (class[0]) {
1346			(void) write(ofd,"\n\n\n",3);
1347			scan_out(pp, ofd, class, '\0');
1348		}
1349		(void) write(ofd, "\n\n\n\n\t\t\t\t\tJob:  ", 15);
1350		(void) write(ofd, name2, strlen(name2));
1351		(void) write(ofd, "\n\t\t\t\t\tDate: ", 12);
1352		(void) write(ofd, ctime(&tvec), 24);
1353		(void) write(ofd, "\n", 1);
1354	}
1355	if (!pp->no_formfeed)
1356		(void) write(ofd, pp->form_feed, strlen(pp->form_feed));
1357	pp->tof = 1;
1358}
1359
1360static char *
1361scnline(int key, char *p, int c)
1362{
1363	register int scnwidth;
1364
1365	for (scnwidth = WIDTH; --scnwidth;) {
1366		key <<= 1;
1367		*p++ = key & 0200 ? c : BACKGND;
1368	}
1369	return (p);
1370}
1371
1372#define TRC(q)	(((q)-' ')&0177)
1373
1374static void
1375scan_out(struct printer *pp, int scfd, char *scsp, int dlm)
1376{
1377	register char *strp;
1378	register int nchrs, j;
1379	char outbuf[LINELEN+1], *sp, c, cc;
1380	int d, scnhgt;
1381
1382	for (scnhgt = 0; scnhgt++ < HEIGHT+DROP; ) {
1383		strp = &outbuf[0];
1384		sp = scsp;
1385		for (nchrs = 0; ; ) {
1386			d = dropit(c = TRC(cc = *sp++));
1387			if ((!d && scnhgt > HEIGHT) || (scnhgt <= DROP && d))
1388				for (j = WIDTH; --j;)
1389					*strp++ = BACKGND;
1390			else
1391				strp = scnline(scnkey[(int)c][scnhgt-1-d], strp, cc);
1392			if (*sp == dlm || *sp == '\0' ||
1393			    nchrs++ >= pp->page_width/(WIDTH+1)-1)
1394				break;
1395			*strp++ = BACKGND;
1396			*strp++ = BACKGND;
1397		}
1398		while (*--strp == BACKGND && strp >= outbuf)
1399			;
1400		strp++;
1401		*strp++ = '\n';
1402		(void) write(scfd, outbuf, strp-outbuf);
1403	}
1404}
1405
1406static int
1407dropit(int c)
1408{
1409	switch(c) {
1410
1411	case TRC('_'):
1412	case TRC(';'):
1413	case TRC(','):
1414	case TRC('g'):
1415	case TRC('j'):
1416	case TRC('p'):
1417	case TRC('q'):
1418	case TRC('y'):
1419		return (DROP);
1420
1421	default:
1422		return (0);
1423	}
1424}
1425
1426/*
1427 * sendmail ---
1428 *   tell people about job completion
1429 */
1430static void
1431sendmail(struct printer *pp, char *userid, int bombed)
1432{
1433	register int i;
1434	int p[2], s;
1435	register const char *cp;
1436	struct stat stb;
1437	FILE *fp;
1438
1439	pipe(p);
1440	if ((s = dofork(pp, DORETURN)) == 0) {		/* child */
1441		dup2(p[0], 0);
1442		closelog();
1443		closeallfds(3);
1444		if ((cp = strrchr(_PATH_SENDMAIL, '/')) != NULL)
1445			cp++;
1446		else
1447			cp = _PATH_SENDMAIL;
1448		execl(_PATH_SENDMAIL, cp, "-t", (char *)0);
1449		_exit(0);
1450	} else if (s > 0) {				/* parent */
1451		dup2(p[1], 1);
1452		printf("To: %s@%s\n", userid, origin_host);
1453		printf("Subject: %s printer job \"%s\"\n", pp->printer,
1454			*jobname ? jobname : "<unknown>");
1455		printf("Reply-To: root@%s\n\n", local_host);
1456		printf("Your printer job ");
1457		if (*jobname)
1458			printf("(%s) ", jobname);
1459
1460		switch (bombed) {
1461		case OK:
1462			cp = "OK";
1463			printf("\ncompleted successfully\n");
1464			break;
1465		default:
1466		case FATALERR:
1467			cp = "FATALERR";
1468			printf("\ncould not be printed\n");
1469			break;
1470		case NOACCT:
1471			cp = "NOACCT";
1472			printf("\ncould not be printed without an account on %s\n",
1473			    local_host);
1474			break;
1475		case FILTERERR:
1476			cp = "FILTERERR";
1477			if (stat(tempstderr, &stb) < 0 || stb.st_size == 0
1478			    || (fp = fopen(tempstderr, "r")) == NULL) {
1479				printf("\nhad some errors and may not have printed\n");
1480				break;
1481			}
1482			printf("\nhad the following errors and may not have printed:\n");
1483			while ((i = getc(fp)) != EOF)
1484				putchar(i);
1485			(void) fclose(fp);
1486			break;
1487		case ACCESS:
1488			cp = "ACCESS";
1489			printf("\nwas not printed because it was not linked to the original file\n");
1490		}
1491		fflush(stdout);
1492		(void) close(1);
1493	} else {
1494		syslog(LOG_WARNING, "unable to send mail to %s: %m", userid);
1495		return;
1496	}
1497	(void) close(p[0]);
1498	(void) close(p[1]);
1499	wait(NULL);
1500	syslog(LOG_INFO, "mail sent to user %s about job %s on printer %s (%s)",
1501	    userid, *jobname ? jobname : "<unknown>", pp->printer, cp);
1502}
1503
1504/*
1505 * dofork - fork with retries on failure
1506 */
1507static int
1508dofork(const struct printer *pp, int action)
1509{
1510	pid_t forkpid;
1511	int i, fail;
1512	struct passwd *pwd;
1513
1514	forkpid = -1;
1515	if (daemon_uname == NULL) {
1516		pwd = getpwuid(pp->daemon_user);
1517		if (pwd == NULL) {
1518			syslog(LOG_ERR, "%s: Can't lookup default daemon uid (%ld) in password file",
1519			    pp->printer, pp->daemon_user);
1520			goto error_ret;
1521		}
1522		daemon_uname = strdup(pwd->pw_name);
1523		daemon_defgid = pwd->pw_gid;
1524	}
1525
1526	for (i = 0; i < 20; i++) {
1527		forkpid = fork();
1528		if (forkpid < 0) {
1529			sleep((unsigned)(i*i));
1530			continue;
1531		}
1532		/*
1533		 * Child should run as daemon instead of root
1534		 */
1535		if (forkpid == 0) {
1536			errno = 0;
1537			fail = initgroups(daemon_uname, daemon_defgid);
1538			if (fail) {
1539				syslog(LOG_ERR, "%s: initgroups(%s,%u): %m",
1540				    pp->printer, daemon_uname, daemon_defgid);
1541				break;
1542			}
1543			fail = setgid(daemon_defgid);
1544			if (fail) {
1545				syslog(LOG_ERR, "%s: setgid(%u): %m",
1546				    pp->printer, daemon_defgid);
1547				break;
1548			}
1549			fail = setuid(pp->daemon_user);
1550			if (fail) {
1551				syslog(LOG_ERR, "%s: setuid(%ld): %m",
1552				    pp->printer, pp->daemon_user);
1553				break;
1554			}
1555		}
1556		return (forkpid);
1557	}
1558
1559	/*
1560	 * An error occurred.  If the error is in the child process, then
1561	 * this routine MUST always exit().  DORETURN only effects how
1562	 * errors should be handled in the parent process.
1563	 */
1564error_ret:
1565	if (forkpid == 0) {
1566		syslog(LOG_ERR, "%s: dofork(): aborting child process...",
1567		    pp->printer);
1568		exit(1);
1569	}
1570	syslog(LOG_ERR, "%s: dofork(): failure in fork", pp->printer);
1571
1572	sleep(1);		/* throttle errors, as a safety measure */
1573	switch (action) {
1574	case DORETURN:
1575		return (-1);
1576	default:
1577		syslog(LOG_ERR, "bad action (%d) to dofork", action);
1578		/* FALLTHROUGH */
1579	case DOABORT:
1580		exit(1);
1581	}
1582	/*NOTREACHED*/
1583}
1584
1585/*
1586 * Kill child processes to abort current job.
1587 */
1588static void
1589abortpr(int signo __unused)
1590{
1591
1592	(void) unlink(tempstderr);
1593	kill(0, SIGINT);
1594	if (of_pid > 0)
1595		kill(of_pid, SIGCONT);
1596	while (wait(NULL) > 0)
1597		;
1598	if (of_pid > 0 && tfd != -1)
1599		unlink(tfile);
1600	exit(0);
1601}
1602
1603static void
1604init(struct printer *pp)
1605{
1606	char *s;
1607
1608	sprintf(&width[2], "%ld", pp->page_width);
1609	sprintf(&length[2], "%ld", pp->page_length);
1610	sprintf(&pxwidth[2], "%ld", pp->page_pwidth);
1611	sprintf(&pxlength[2], "%ld", pp->page_plength);
1612	if ((s = checkremote(pp)) != 0) {
1613		syslog(LOG_WARNING, "%s", s);
1614		free(s);
1615	}
1616}
1617
1618void
1619startprinting(const char *printer)
1620{
1621	struct printer myprinter, *pp = &myprinter;
1622	int status;
1623
1624	init_printer(pp);
1625	status = getprintcap(printer, pp);
1626	switch(status) {
1627	case PCAPERR_OSERR:
1628		syslog(LOG_ERR, "can't open printer description file: %m");
1629		exit(1);
1630	case PCAPERR_NOTFOUND:
1631		syslog(LOG_ERR, "unknown printer: %s", printer);
1632		exit(1);
1633	case PCAPERR_TCLOOP:
1634		fatal(pp, "potential reference loop detected in printcap file");
1635	default:
1636		break;
1637	}
1638	printjob(pp);
1639}
1640
1641/*
1642 * Acquire line printer or remote connection.
1643 */
1644static void
1645openpr(const struct printer *pp)
1646{
1647	int p[2];
1648	char *cp;
1649
1650	if (pp->remote) {
1651		openrem(pp);
1652		/*
1653		 * Lpd does support the setting of 'of=' filters for
1654		 * jobs going to remote machines, but that does not
1655		 * have the same meaning as 'of=' does when handling
1656		 * local print queues.  For remote machines, all 'of='
1657		 * filter processing is handled in sendfile(), and that
1658		 * does not use these global "output filter" variables.
1659		 */
1660		ofd = -1;
1661		of_pid = 0;
1662		return;
1663	} else if (*pp->lp) {
1664		if ((cp = strchr(pp->lp, '@')) != NULL)
1665			opennet(pp);
1666		else
1667			opentty(pp);
1668	} else {
1669		syslog(LOG_ERR, "%s: no line printer device or host name",
1670		    pp->printer);
1671		exit(1);
1672	}
1673
1674	/*
1675	 * Start up an output filter, if needed.
1676	 */
1677	if (pp->filters[LPF_OUTPUT] && !pp->filters[LPF_INPUT] && !of_pid) {
1678		pipe(p);
1679		if (pp->remote) {
1680			strcpy(tfile, TFILENAME);
1681			tfd = mkstemp(tfile);
1682		}
1683		if ((of_pid = dofork(pp, DOABORT)) == 0) {	/* child */
1684			dup2(p[0], 0);		/* pipe is std in */
1685			/* tfile/printer is stdout */
1686			dup2(pp->remote ? tfd : pfd, 1);
1687			closelog();
1688			closeallfds(3);
1689			if ((cp = strrchr(pp->filters[LPF_OUTPUT], '/')) == NULL)
1690				cp = pp->filters[LPF_OUTPUT];
1691			else
1692				cp++;
1693			execl(pp->filters[LPF_OUTPUT], cp, width, length,
1694			      (char *)0);
1695			syslog(LOG_ERR, "%s: execl(%s): %m", pp->printer,
1696			    pp->filters[LPF_OUTPUT]);
1697			exit(1);
1698		}
1699		(void) close(p[0]);		/* close input side */
1700		ofd = p[1];			/* use pipe for output */
1701	} else {
1702		ofd = pfd;
1703		of_pid = 0;
1704	}
1705}
1706
1707/*
1708 * Printer connected directly to the network
1709 * or to a terminal server on the net
1710 */
1711static void
1712opennet(const struct printer *pp)
1713{
1714	register int i;
1715	int resp;
1716	u_long port;
1717	char *ep;
1718	void (*savealrm)(int);
1719
1720	port = strtoul(pp->lp, &ep, 0);
1721	if (*ep != '@' || port > 65535) {
1722		syslog(LOG_ERR, "%s: bad port number: %s", pp->printer,
1723		    pp->lp);
1724		exit(1);
1725	}
1726	ep++;
1727
1728	for (i = 1; ; i = i < 256 ? i << 1 : i) {
1729		resp = -1;
1730		savealrm = signal(SIGALRM, alarmhandler);
1731		alarm(pp->conn_timeout);
1732		pfd = getport(pp, ep, port);
1733		alarm(0);
1734		(void)signal(SIGALRM, savealrm);
1735		if (pfd < 0 && errno == ECONNREFUSED)
1736			resp = 1;
1737		else if (pfd >= 0) {
1738			/*
1739			 * need to delay a bit for rs232 lines
1740			 * to stabilize in case printer is
1741			 * connected via a terminal server
1742			 */
1743			delay(500);
1744			break;
1745		}
1746		if (i == 1) {
1747			if (resp < 0)
1748				pstatus(pp, "waiting for %s to come up",
1749					pp->lp);
1750			else
1751				pstatus(pp,
1752					"waiting for access to printer on %s",
1753					pp->lp);
1754		}
1755		sleep(i);
1756	}
1757	pstatus(pp, "sending to %s port %lu", ep, port);
1758}
1759
1760/*
1761 * Printer is connected to an RS232 port on this host
1762 */
1763static void
1764opentty(const struct printer *pp)
1765{
1766	register int i;
1767
1768	for (i = 1; ; i = i < 32 ? i << 1 : i) {
1769		pfd = open(pp->lp, pp->rw ? O_RDWR : O_WRONLY);
1770		if (pfd >= 0) {
1771			delay(500);
1772			break;
1773		}
1774		if (errno == ENOENT) {
1775			syslog(LOG_ERR, "%s: %m", pp->lp);
1776			exit(1);
1777		}
1778		if (i == 1)
1779			pstatus(pp,
1780				"waiting for %s to become ready (offline?)",
1781				pp->printer);
1782		sleep(i);
1783	}
1784	if (isatty(pfd))
1785		setty(pp);
1786	pstatus(pp, "%s is ready and printing", pp->printer);
1787}
1788
1789/*
1790 * Printer is on a remote host
1791 */
1792static void
1793openrem(const struct printer *pp)
1794{
1795	register int i;
1796	int resp;
1797	void (*savealrm)(int);
1798
1799	for (i = 1; ; i = i < 256 ? i << 1 : i) {
1800		resp = -1;
1801		savealrm = signal(SIGALRM, alarmhandler);
1802		alarm(pp->conn_timeout);
1803		pfd = getport(pp, pp->remote_host, 0);
1804		alarm(0);
1805		(void)signal(SIGALRM, savealrm);
1806		if (pfd >= 0) {
1807			if ((writel(pfd, "\2", pp->remote_queue, "\n",
1808				    (char *)0)
1809			     == 2 + strlen(pp->remote_queue))
1810			    && (resp = response(pp)) == 0)
1811				break;
1812			(void) close(pfd);
1813		}
1814		if (i == 1) {
1815			if (resp < 0)
1816				pstatus(pp, "waiting for %s to come up",
1817					pp->remote_host);
1818			else {
1819				pstatus(pp,
1820					"waiting for queue to be enabled on %s",
1821					pp->remote_host);
1822				i = 256;
1823			}
1824		}
1825		sleep(i);
1826	}
1827	pstatus(pp, "sending to %s", pp->remote_host);
1828}
1829
1830/*
1831 * setup tty lines.
1832 */
1833static void
1834setty(const struct printer *pp)
1835{
1836	struct termios ttybuf;
1837
1838	if (ioctl(pfd, TIOCEXCL, (char *)0) < 0) {
1839		syslog(LOG_ERR, "%s: ioctl(TIOCEXCL): %m", pp->printer);
1840		exit(1);
1841	}
1842	if (tcgetattr(pfd, &ttybuf) < 0) {
1843		syslog(LOG_ERR, "%s: tcgetattr: %m", pp->printer);
1844		exit(1);
1845	}
1846	if (pp->baud_rate > 0)
1847		cfsetspeed(&ttybuf, pp->baud_rate);
1848	if (pp->mode_set) {
1849		char *s = strdup(pp->mode_set), *tmp;
1850
1851		while ((tmp = strsep(&s, ",")) != NULL) {
1852			(void) msearch(tmp, &ttybuf);
1853		}
1854	}
1855	if (pp->mode_set != 0 || pp->baud_rate > 0) {
1856		if (tcsetattr(pfd, TCSAFLUSH, &ttybuf) == -1) {
1857			syslog(LOG_ERR, "%s: tcsetattr: %m", pp->printer);
1858		}
1859	}
1860}
1861
1862#include <stdarg.h>
1863
1864static void
1865pstatus(const struct printer *pp, const char *msg, ...)
1866{
1867	int fd;
1868	char *buf;
1869	va_list ap;
1870	va_start(ap, msg);
1871
1872	umask(0);
1873	fd = open(pp->status_file, O_WRONLY|O_CREAT|O_EXLOCK, STAT_FILE_MODE);
1874	if (fd < 0) {
1875		syslog(LOG_ERR, "%s: open(%s): %m", pp->printer,
1876		    pp->status_file);
1877		exit(1);
1878	}
1879	ftruncate(fd, 0);
1880	vasprintf(&buf, msg, ap);
1881	va_end(ap);
1882	writel(fd, buf, "\n", (char *)0);
1883	close(fd);
1884	free(buf);
1885}
1886
1887void
1888alarmhandler(int signo __unused)
1889{
1890	/* the signal is ignored */
1891	/* (the '__unused' is just to avoid a compile-time warning) */
1892}
1893