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