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