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