printjob.c revision 24831
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) sprintf(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				/* insure 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], "%d", 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			strcpy(fromhost, line+1);
381			if (class[0] == '\0')
382				strncpy(class, line+1, sizeof(class)-1);
383			continue;
384
385		case 'P':
386			strncpy(logname, line+1, sizeof(logname)-1);
387			if (RS) {			/* restricted */
388				if (getpwnam(logname) == NULL) {
389					bombed = NOACCT;
390					sendmail(line+1, bombed);
391					goto pass2;
392				}
393			}
394			continue;
395
396		case 'S':
397			cp = line+1;
398			i = 0;
399			while (*cp >= '0' && *cp <= '9')
400				i = i * 10 + (*cp++ - '0');
401			fdev = i;
402			cp++;
403			i = 0;
404			while (*cp >= '0' && *cp <= '9')
405				i = i * 10 + (*cp++ - '0');
406			fino = i;
407			continue;
408
409		case 'J':
410			if (line[1] != '\0')
411				strncpy(jobname, line+1, sizeof(jobname)-1);
412			else
413				strcpy(jobname, " ");
414			continue;
415
416		case 'C':
417			if (line[1] != '\0')
418				strncpy(class, line+1, sizeof(class)-1);
419			else if (class[0] == '\0')
420				gethostname(class, sizeof(class));
421			continue;
422
423		case 'T':	/* header title for pr */
424			strncpy(title, line+1, sizeof(title)-1);
425			continue;
426
427		case 'L':	/* identification line */
428			if (!SH && !HL)
429				banner(line+1, jobname);
430			continue;
431
432		case '1':	/* troff fonts */
433		case '2':
434		case '3':
435		case '4':
436			if (line[1] != '\0')
437				strcpy(fonts[line[0]-'1'], line+1);
438			continue;
439
440		case 'W':	/* page width */
441			strncpy(width+2, line+1, sizeof(width)-3);
442			continue;
443
444		case 'I':	/* indent amount */
445			strncpy(indent+2, line+1, sizeof(indent)-3);
446			continue;
447
448		default:	/* some file to print */
449			switch (i = print(line[0], line+1)) {
450			case ERROR:
451				if (bombed == OK)
452					bombed = FATALERR;
453				break;
454			case REPRINT:
455				(void) fclose(cfp);
456				return(REPRINT);
457			case FILTERERR:
458			case ACCESS:
459				bombed = i;
460				sendmail(logname, bombed);
461			}
462			title[0] = '\0';
463			continue;
464
465		case 'N':
466		case 'U':
467		case 'M':
468		case 'R':
469			continue;
470		}
471
472	/* pass 2 */
473
474pass2:
475	fseek(cfp, 0L, 0);
476	while (getline(cfp))
477		switch (line[0]) {
478		case 'L':	/* identification line */
479			if (!SH && HL)
480				banner(line+1, jobname);
481			continue;
482
483		case 'M':
484			if (bombed < NOACCT)	/* already sent if >= NOACCT */
485				sendmail(line+1, bombed);
486			continue;
487
488		case 'U':
489			(void) unlink(line+1);
490		}
491	/*
492	 * clean-up in case another control file exists
493	 */
494	(void) fclose(cfp);
495	(void) unlink(file);
496	return(bombed == OK ? OK : ERROR);
497}
498
499/*
500 * Print a file.
501 * Set up the chain [ PR [ | {IF, OF} ] ] or {IF, RF, TF, NF, DF, CF, VF}.
502 * Return -1 if a non-recoverable error occured,
503 * 2 if the filter detected some errors (but printed the job anyway),
504 * 1 if we should try to reprint this job and
505 * 0 if all is well.
506 * Note: all filters take stdin as the file, stdout as the printer,
507 * stderr as the log file, and must not ignore SIGINT.
508 */
509static int
510print(format, file)
511	int format;
512	char *file;
513{
514	register int n;
515	register char *prog;
516	int dtablesize, fi, fo;
517	FILE *fp;
518	char *av[15], buf[BUFSIZ];
519	int pid, p[2], stopped = 0;
520	union wait status;
521	struct stat stb;
522
523	if (lstat(file, &stb) < 0 || (fi = open(file, O_RDONLY)) < 0)
524		return(ERROR);
525	/*
526	 * Check to see if data file is a symbolic link. If so, it should
527	 * still point to the same file or someone is trying to print
528	 * something he shouldn't.
529	 */
530	if ((stb.st_mode & S_IFMT) == S_IFLNK && fstat(fi, &stb) == 0 &&
531	    (stb.st_dev != fdev || stb.st_ino != fino))
532		return(ACCESS);
533	if (!SF && !tof) {		/* start on a fresh page */
534		(void) write(ofd, FF, strlen(FF));
535		tof = 1;
536	}
537	if (IF == NULL && (format == 'f' || format == 'l')) {
538		tof = 0;
539		while ((n = read(fi, buf, BUFSIZ)) > 0)
540			if (write(ofd, buf, n) != n) {
541				(void) close(fi);
542				return(REPRINT);
543			}
544		(void) close(fi);
545		return(OK);
546	}
547	switch (format) {
548	case 'p':	/* print file using 'pr' */
549		if (IF == NULL) {	/* use output filter */
550			prog = _PATH_PR;
551			av[0] = "pr";
552			av[1] = width;
553			av[2] = length;
554			av[3] = "-h";
555			av[4] = *title ? title : " ";
556			av[5] = "-F";
557			av[6] = 0;
558			fo = ofd;
559			goto start;
560		}
561		pipe(p);
562		if ((prchild = dofork(DORETURN)) == 0) {	/* child */
563			dup2(fi, 0);		/* file is stdin */
564			dup2(p[1], 1);		/* pipe is stdout */
565			closelog();
566			for (n = 3, dtablesize = getdtablesize();
567			     n < dtablesize; n++)
568				(void) close(n);
569			execl(_PATH_PR, "pr", width, length,
570			    "-h", *title ? title : " ", "-F", 0);
571			syslog(LOG_ERR, "cannot execl %s", _PATH_PR);
572			exit(2);
573		}
574		(void) close(p[1]);		/* close output side */
575		(void) close(fi);
576		if (prchild < 0) {
577			prchild = 0;
578			(void) close(p[0]);
579			return(ERROR);
580		}
581		fi = p[0];			/* use pipe for input */
582	case 'f':	/* print plain text file */
583		prog = IF;
584		av[1] = width;
585		av[2] = length;
586		av[3] = indent;
587		n = 4;
588		break;
589	case 'l':	/* like 'f' but pass control characters */
590		prog = IF;
591		av[1] = "-c";
592		av[2] = width;
593		av[3] = length;
594		av[4] = indent;
595		n = 5;
596		break;
597	case 'r':	/* print a fortran text file */
598		prog = RF;
599		av[1] = width;
600		av[2] = length;
601		n = 3;
602		break;
603	case 't':	/* print troff output */
604	case 'n':	/* print ditroff output */
605	case 'd':	/* print tex output */
606		(void) unlink(".railmag");
607		if ((fo = creat(".railmag", FILMOD)) < 0) {
608			syslog(LOG_ERR, "%s: cannot create .railmag", printer);
609			(void) unlink(".railmag");
610		} else {
611			for (n = 0; n < 4; n++) {
612				if (fonts[n][0] != '/')
613					(void) write(fo, _PATH_VFONT,
614					    sizeof(_PATH_VFONT) - 1);
615				(void) write(fo, fonts[n], strlen(fonts[n]));
616				(void) write(fo, "\n", 1);
617			}
618			(void) close(fo);
619		}
620		prog = (format == 't') ? TF : (format == 'n') ? NF : DF;
621		av[1] = pxwidth;
622		av[2] = pxlength;
623		n = 3;
624		break;
625	case 'c':	/* print cifplot output */
626		prog = CF;
627		av[1] = pxwidth;
628		av[2] = pxlength;
629		n = 3;
630		break;
631	case 'g':	/* print plot(1G) output */
632		prog = GF;
633		av[1] = pxwidth;
634		av[2] = pxlength;
635		n = 3;
636		break;
637	case 'v':	/* print raster output */
638		prog = VF;
639		av[1] = pxwidth;
640		av[2] = pxlength;
641		n = 3;
642		break;
643	default:
644		(void) close(fi);
645		syslog(LOG_ERR, "%s: illegal format character '%c'",
646			printer, format);
647		return(ERROR);
648	}
649	if (prog == NULL) {
650		(void) close(fi);
651		syslog(LOG_ERR,
652		   "%s: no filter found in printcap for format character '%c'",
653		   printer, format);
654		return(ERROR);
655	}
656	if ((av[0] = rindex(prog, '/')) != NULL)
657		av[0]++;
658	else
659		av[0] = prog;
660	av[n++] = "-n";
661	av[n++] = logname;
662	av[n++] = "-h";
663	av[n++] = fromhost;
664	av[n++] = AF;
665	av[n] = 0;
666	fo = pfd;
667	if (ofilter > 0) {		/* stop output filter */
668		write(ofd, "\031\1", 2);
669		while ((pid =
670		    wait3((int *)&status, WUNTRACED, 0)) > 0 && pid != ofilter)
671			;
672		if (status.w_stopval != WSTOPPED) {
673			(void) close(fi);
674			syslog(LOG_WARNING,
675				"%s: output filter died (retcode=%d termsig=%d)",
676				printer, status.w_retcode, status.w_termsig);
677			return(REPRINT);
678		}
679		stopped++;
680	}
681start:
682	if ((child = dofork(DORETURN)) == 0) {	/* child */
683		dup2(fi, 0);
684		dup2(fo, 1);
685		n = open(tempfile, O_WRONLY|O_CREAT|O_TRUNC, 0664);
686		if (n >= 0)
687			dup2(n, 2);
688		closelog();
689		for (n = 3, dtablesize = getdtablesize(); n < dtablesize; n++)
690			(void) close(n);
691		execv(prog, av);
692		syslog(LOG_ERR, "cannot execv %s", prog);
693		exit(2);
694	}
695	(void) close(fi);
696	if (child < 0)
697		status.w_retcode = 100;
698	else
699		while ((pid = wait((int *)&status)) > 0 && pid != child)
700			;
701	child = 0;
702	prchild = 0;
703	if (stopped) {		/* restart output filter */
704		if (kill(ofilter, SIGCONT) < 0) {
705			syslog(LOG_ERR, "cannot restart output filter");
706			exit(1);
707		}
708	}
709	tof = 0;
710
711	/* Copy filter output to "lf" logfile */
712	if (fp = fopen(tempfile, "r")) {
713		while (fgets(buf, sizeof(buf), fp))
714			fputs(buf, stderr);
715		fclose(fp);
716	}
717
718	if (!WIFEXITED(status)) {
719		syslog(LOG_WARNING, "%s: filter '%c' terminated (termsig=%d)",
720			printer, format, status.w_termsig);
721		return(ERROR);
722	}
723	switch (status.w_retcode) {
724	case 0:
725		tof = 1;
726		return(OK);
727	case 1:
728		return(REPRINT);
729	case 2:
730		return(ERROR);
731	default:
732		syslog(LOG_WARNING, "%s: filter '%c' exited (retcode=%d)",
733			printer, format, status.w_retcode);
734		return(FILTERERR);
735	}
736}
737
738/*
739 * Send the daemon control file (cf) and any data files.
740 * Return -1 if a non-recoverable error occured, 1 if a recoverable error and
741 * 0 if all is well.
742 */
743static int
744sendit(file)
745	char *file;
746{
747	register int i, err = OK;
748	char *cp, last[BUFSIZ];
749
750	/*
751	 * open control file
752	 */
753	if ((cfp = fopen(file, "r")) == NULL)
754		return(OK);
755	/*
756	 *      read the control file for work to do
757	 *
758	 *      file format -- first character in the line is a command
759	 *      rest of the line is the argument.
760	 *      commands of interest are:
761	 *
762	 *            a-z -- "file name" name of file to print
763	 *              U -- "unlink" name of file to remove
764	 *                    (after we print it. (Pass 2 only)).
765	 */
766
767	/*
768	 * pass 1
769	 */
770	while (getline(cfp)) {
771	again:
772		if (line[0] == 'S') {
773			cp = line+1;
774			i = 0;
775			while (*cp >= '0' && *cp <= '9')
776				i = i * 10 + (*cp++ - '0');
777			fdev = i;
778			cp++;
779			i = 0;
780			while (*cp >= '0' && *cp <= '9')
781				i = i * 10 + (*cp++ - '0');
782			fino = i;
783		} else if (line[0] == 'H') {
784			strcpy(fromhost, line+1);
785			if (class[0] == '\0')
786				strncpy(class, line+1, sizeof(class)-1);
787		} else if (line[0] == 'P') {
788			strncpy(logname, line+1, sizeof(logname)-1);
789			if (RS) {			/* restricted */
790				if (getpwnam(logname) == NULL) {
791					sendmail(line+1, NOACCT);
792					err = ERROR;
793					break;
794				}
795			}
796		} else if (line[0] == 'I') {
797			strncpy(indent+2, line+1, sizeof(indent)-3);
798		} else if (line[0] >= 'a' && line[0] <= 'z') {
799			strcpy(last, line);
800			while (i = getline(cfp))
801				if (strcmp(last, line))
802					break;
803			switch (sendfile('\3', last+1, *last)) {
804			case OK:
805				if (i)
806					goto again;
807				break;
808			case REPRINT:
809				(void) fclose(cfp);
810				return(REPRINT);
811			case ACCESS:
812				sendmail(logname, ACCESS);
813			case ERROR:
814				err = ERROR;
815			}
816			break;
817		}
818	}
819	if (err == OK && sendfile('\2', file, '\0') > 0) {
820		(void) fclose(cfp);
821		return(REPRINT);
822	}
823	/*
824	 * pass 2
825	 */
826	fseek(cfp, 0L, 0);
827	while (getline(cfp))
828		if (line[0] == 'U')
829			(void) unlink(line+1);
830	/*
831	 * clean-up in case another control file exists
832	 */
833	(void) fclose(cfp);
834	(void) unlink(file);
835	return(err);
836}
837
838/*
839 * Send a data file to the remote machine and spool it.
840 * Return positive if we should try resending.
841 */
842static int
843sendfile(type, file, format)
844	int type;
845	char *file;
846	char format;
847{
848	register int f, i, amt;
849	struct stat stb;
850	char buf[BUFSIZ];
851	int sizerr, resp, closedpr;
852
853	if (lstat(file, &stb) < 0 || (f = open(file, O_RDONLY)) < 0)
854		return(ERROR);
855	/*
856	 * Check to see if data file is a symbolic link. If so, it should
857	 * still point to the same file or someone is trying to print something
858	 * he shouldn't.
859	 */
860	if ((stb.st_mode & S_IFMT) == S_IFLNK && fstat(f, &stb) == 0 &&
861	    (stb.st_dev != fdev || stb.st_ino != fino))
862		return(ACCESS);
863
864	sizerr = 0;
865	closedpr = 0;
866	if (type == '\3') {
867		if (IF) {
868			/*
869			 * We're sending something with an ifilter, we have to
870			 * run the ifilter and store the output as a
871			 * temporary file (tfile)... the protocol requires us
872			 * to send the file size
873			 */
874			char *av[15];
875			int n;
876			int nfd;
877			int ifilter;
878			union wait status;
879
880			strcpy(tfile,TFILENAME);
881			if ((tfd = mkstemp(tfile)) == -1) {
882				syslog(LOG_ERR, "mkstemp: %m");
883				return(ERROR);
884			}
885			if ((av[0] = rindex(IF, '/')) == NULL)
886				av[0] = IF;
887			else
888				av[0]++;
889			if (format == 'l')
890				av[n=1] = "-c";
891			else
892				n = 0;
893			av[++n] = width;
894			av[++n] = length;
895			av[++n] = indent;
896			av[++n] = "-n";
897			av[++n] = logname;
898			av[++n] = "-h";
899			av[++n] = fromhost;
900			av[++n] = AF;
901			av[++n] = 0;
902			if ((ifilter = dofork(DORETURN)) == 0) {  /* child */
903				dup2(f, 0);
904				dup2(tfd, 1);
905				n = open(tempfile, O_WRONLY|O_CREAT|O_TRUNC, 0664);
906				if (n >= 0)
907					dup2(n, 2);
908				closelog();
909				for (n = 3, nfd = getdtablesize(); n < nfd; n++)
910					(void) close(n);
911				execv(IF, av);
912				syslog(LOG_ERR, "cannot execv %s", IF);
913				exit(2);
914			}
915			(void) close(f);
916			if (ifilter < 0)
917				status.w_retcode = 100;
918			else
919				while ((pid = wait((int *)&status)) > 0 &&
920					pid != ifilter)
921					;
922			switch (status.w_retcode) {
923			case 0:
924				break;
925			case 1:
926				unlink(tfile);
927				return(REPRINT);
928			case 2:
929				unlink(tfile);
930				return(ERROR);
931			default:
932				syslog(LOG_WARNING, "%s: filter '%c' exited"
933					" (retcode=%d)",
934					printer, format, status.w_retcode);
935				unlink(tfile);
936				return(FILTERERR);
937			}
938			if (fstat(tfd, &stb) < 0)	/* the size of tfile */
939				return(ERROR);
940			f = tfd;
941			lseek(f,0,SEEK_SET);
942		} else if (ofilter) {
943			/*
944			 * We're sending something with an ofilter, we have to
945			 * store the output as a temporary file (tfile)... the
946			 * protocol requires us to send the file size
947			 */
948			int i;
949			for (i = 0; i < stb.st_size; i += BUFSIZ) {
950				amt = BUFSIZ;
951				if (i + amt > stb.st_size)
952					amt = stb.st_size - i;
953				if (sizerr == 0 && read(f, buf, amt) != amt) {
954					sizerr = 1;
955					break;
956				}
957				if (write(ofd, buf, amt) != amt) {
958					(void) close(f);
959					return(REPRINT);
960				}
961			}
962			close(ofd);
963			close(f);
964			while ((i = wait(NULL)) > 0 && i != ofilter)
965				;
966			ofilter = 0;
967			if (fstat(tfd, &stb) < 0) {	/* the size of tfile */
968				openpr();
969				return(ERROR);
970			}
971			f = tfd;
972			lseek(f,0,SEEK_SET);
973			closedpr = 1;
974		}
975	}
976
977	(void) sprintf(buf, "%c%qd %s\n", type, stb.st_size, file);
978	amt = strlen(buf);
979	for (i = 0;  ; i++) {
980		if (write(pfd, buf, amt) != amt ||
981		    (resp = response()) < 0 || resp == '\1') {
982			(void) close(f);
983			if (tfd != -1 && type == '\3') {
984				tfd = -1;
985				unlink(tfile);
986				if (closedpr)
987					openpr();
988			}
989			return(REPRINT);
990		} else if (resp == '\0')
991			break;
992		if (i == 0)
993			pstatus("no space on remote; waiting for queue to drain");
994		if (i == 10)
995			syslog(LOG_ALERT, "%s: can't send to %s; queue full",
996				printer, RM);
997		sleep(5 * 60);
998	}
999	if (i)
1000		pstatus("sending to %s", RM);
1001	for (i = 0; i < stb.st_size; i += BUFSIZ) {
1002		amt = BUFSIZ;
1003		if (i + amt > stb.st_size)
1004			amt = stb.st_size - i;
1005		if (sizerr == 0 && read(f, buf, amt) != amt)
1006			sizerr = 1;
1007		if (write(pfd, buf, amt) != amt) {
1008			(void) close(f);
1009			if (tfd != -1 && type == '\3') {
1010				tfd = -1;
1011				unlink(tfile);
1012				if (closedpr)
1013					openpr();
1014			}
1015			return(REPRINT);
1016		}
1017	}
1018
1019	(void) close(f);
1020	if (tfd != -1 && type == '\3') {
1021		tfd = -1;
1022		unlink(tfile);
1023	}
1024	if (sizerr) {
1025		syslog(LOG_INFO, "%s: %s: changed size", printer, file);
1026		/* tell recvjob to ignore this file */
1027		(void) write(pfd, "\1", 1);
1028		if (closedpr)
1029			openpr();
1030		return(ERROR);
1031	}
1032	if (write(pfd, "", 1) != 1 || response()) {
1033		if (closedpr)
1034			openpr();
1035		return(REPRINT);
1036	}
1037	if (closedpr)
1038		openpr();
1039	return(OK);
1040}
1041
1042/*
1043 * Check to make sure there have been no errors and that both programs
1044 * are in sync with eachother.
1045 * Return non-zero if the connection was lost.
1046 */
1047static char
1048response()
1049{
1050	char resp;
1051
1052	if (read(pfd, &resp, 1) != 1) {
1053		syslog(LOG_INFO, "%s: lost connection", printer);
1054		return(-1);
1055	}
1056	return(resp);
1057}
1058
1059/*
1060 * Banner printing stuff
1061 */
1062static void
1063banner(name1, name2)
1064	char *name1, *name2;
1065{
1066	time_t tvec;
1067
1068	time(&tvec);
1069	if (!SF && !tof)
1070		(void) write(ofd, FF, strlen(FF));
1071	if (SB) {	/* short banner only */
1072		if (class[0]) {
1073			(void) write(ofd, class, strlen(class));
1074			(void) write(ofd, ":", 1);
1075		}
1076		(void) write(ofd, name1, strlen(name1));
1077		(void) write(ofd, "  Job: ", 7);
1078		(void) write(ofd, name2, strlen(name2));
1079		(void) write(ofd, "  Date: ", 8);
1080		(void) write(ofd, ctime(&tvec), 24);
1081		(void) write(ofd, "\n", 1);
1082	} else {	/* normal banner */
1083		(void) write(ofd, "\n\n\n", 3);
1084		scan_out(ofd, name1, '\0');
1085		(void) write(ofd, "\n\n", 2);
1086		scan_out(ofd, name2, '\0');
1087		if (class[0]) {
1088			(void) write(ofd,"\n\n\n",3);
1089			scan_out(ofd, class, '\0');
1090		}
1091		(void) write(ofd, "\n\n\n\n\t\t\t\t\tJob:  ", 15);
1092		(void) write(ofd, name2, strlen(name2));
1093		(void) write(ofd, "\n\t\t\t\t\tDate: ", 12);
1094		(void) write(ofd, ctime(&tvec), 24);
1095		(void) write(ofd, "\n", 1);
1096	}
1097	if (!SF)
1098		(void) write(ofd, FF, strlen(FF));
1099	tof = 1;
1100}
1101
1102static char *
1103scnline(key, p, c)
1104	register int key;
1105	register char *p;
1106	int c;
1107{
1108	register scnwidth;
1109
1110	for (scnwidth = WIDTH; --scnwidth;) {
1111		key <<= 1;
1112		*p++ = key & 0200 ? c : BACKGND;
1113	}
1114	return (p);
1115}
1116
1117#define TRC(q)	(((q)-' ')&0177)
1118
1119static void
1120scan_out(scfd, scsp, dlm)
1121	int scfd, dlm;
1122	char *scsp;
1123{
1124	register char *strp;
1125	register nchrs, j;
1126	char outbuf[LINELEN+1], *sp, c, cc;
1127	int d, scnhgt;
1128
1129	for (scnhgt = 0; scnhgt++ < HEIGHT+DROP; ) {
1130		strp = &outbuf[0];
1131		sp = scsp;
1132		for (nchrs = 0; ; ) {
1133			d = dropit(c = TRC(cc = *sp++));
1134			if ((!d && scnhgt > HEIGHT) || (scnhgt <= DROP && d))
1135				for (j = WIDTH; --j;)
1136					*strp++ = BACKGND;
1137			else
1138				strp = scnline(scnkey[c][scnhgt-1-d], strp, cc);
1139			if (*sp == dlm || *sp == '\0' || nchrs++ >= PW/(WIDTH+1)-1)
1140				break;
1141			*strp++ = BACKGND;
1142			*strp++ = BACKGND;
1143		}
1144		while (*--strp == BACKGND && strp >= outbuf)
1145			;
1146		strp++;
1147		*strp++ = '\n';
1148		(void) write(scfd, outbuf, strp-outbuf);
1149	}
1150}
1151
1152static int
1153dropit(c)
1154	int c;
1155{
1156	switch(c) {
1157
1158	case TRC('_'):
1159	case TRC(';'):
1160	case TRC(','):
1161	case TRC('g'):
1162	case TRC('j'):
1163	case TRC('p'):
1164	case TRC('q'):
1165	case TRC('y'):
1166		return (DROP);
1167
1168	default:
1169		return (0);
1170	}
1171}
1172
1173/*
1174 * sendmail ---
1175 *   tell people about job completion
1176 */
1177static void
1178sendmail(user, bombed)
1179	char *user;
1180	int bombed;
1181{
1182	register int i;
1183	int dtablesize;
1184	int p[2], s;
1185	register char *cp;
1186	char buf[100];
1187	struct stat stb;
1188	FILE *fp;
1189
1190	pipe(p);
1191	if ((s = dofork(DORETURN)) == 0) {		/* child */
1192		dup2(p[0], 0);
1193		closelog();
1194		for (i = 3, dtablesize = getdtablesize(); i < dtablesize; i++)
1195			(void) close(i);
1196		if ((cp = rindex(_PATH_SENDMAIL, '/')) != NULL)
1197			cp++;
1198	else
1199			cp = _PATH_SENDMAIL;
1200		sprintf(buf, "%s@%s", user, fromhost);
1201		execl(_PATH_SENDMAIL, cp, buf, 0);
1202		exit(0);
1203	} else if (s > 0) {				/* parent */
1204		dup2(p[1], 1);
1205		printf("To: %s@%s\n", user, fromhost);
1206		printf("Subject: %s printer job \"%s\"\n", printer,
1207			*jobname ? jobname : "<unknown>");
1208		printf("Reply-To: root@%s\n\n", host);
1209		printf("Your printer job ");
1210		if (*jobname)
1211			printf("(%s) ", jobname);
1212		switch (bombed) {
1213		case OK:
1214			printf("\ncompleted successfully\n");
1215			cp = "OK";
1216			break;
1217		default:
1218		case FATALERR:
1219			printf("\ncould not be printed\n");
1220			cp = "FATALERR";
1221			break;
1222		case NOACCT:
1223			printf("\ncould not be printed without an account on %s\n", host);
1224			cp = "NOACCT";
1225			break;
1226		case FILTERERR:
1227			if (stat(tempfile, &stb) < 0 || stb.st_size == 0 ||
1228			    (fp = fopen(tempfile, "r")) == NULL) {
1229				printf("\nhad some errors and may not have printed\n");
1230				break;
1231			}
1232			printf("\nhad the following errors and may not have printed:\n");
1233			while ((i = getc(fp)) != EOF)
1234				putchar(i);
1235			(void) fclose(fp);
1236			cp = "FILTERERR";
1237			break;
1238		case ACCESS:
1239			printf("\nwas not printed because it was not linked to the original file\n");
1240			cp = "ACCESS";
1241		}
1242		fflush(stdout);
1243		(void) close(1);
1244	}
1245	(void) close(p[0]);
1246	(void) close(p[1]);
1247	wait(NULL);
1248	syslog(LOG_INFO, "mail sent to user %s about job %s on printer %s (%s)",
1249		user, *jobname ? jobname : "<unknown>", printer, cp);
1250}
1251
1252/*
1253 * dofork - fork with retries on failure
1254 */
1255static int
1256dofork(action)
1257	int action;
1258{
1259	register int i, pid;
1260
1261	for (i = 0; i < 20; i++) {
1262		if ((pid = fork()) < 0) {
1263			sleep((unsigned)(i*i));
1264			continue;
1265		}
1266		/*
1267		 * Child should run as daemon instead of root
1268		 */
1269		if (pid == 0)
1270			setuid(DU);
1271		return(pid);
1272	}
1273	syslog(LOG_ERR, "can't fork");
1274
1275	switch (action) {
1276	case DORETURN:
1277		return (-1);
1278	default:
1279		syslog(LOG_ERR, "bad action (%d) to dofork", action);
1280		/*FALL THRU*/
1281	case DOABORT:
1282		exit(1);
1283	}
1284	/*NOTREACHED*/
1285}
1286
1287/*
1288 * Kill child processes to abort current job.
1289 */
1290static void
1291abortpr(signo)
1292	int signo;
1293{
1294	(void) unlink(tempfile);
1295	kill(0, SIGINT);
1296	if (ofilter > 0)
1297		kill(ofilter, SIGCONT);
1298	while (wait(NULL) > 0)
1299		;
1300	if (ofilter > 0 && tfd != -1)
1301		unlink(tfile);
1302	exit(0);
1303}
1304
1305static void
1306init()
1307{
1308	int status;
1309	char *s;
1310
1311	if ((status = cgetent(&bp, printcapdb, printer)) == -2) {
1312		syslog(LOG_ERR, "can't open printer description file");
1313		exit(1);
1314	} else if (status == -1) {
1315		syslog(LOG_ERR, "unknown printer: %s", printer);
1316		exit(1);
1317	} else if (status == -3)
1318		fatal("potential reference loop detected in printcap file");
1319
1320	if (cgetstr(bp, "lp", &LP) == -1)
1321		LP = _PATH_DEFDEVLP;
1322	if (cgetstr(bp, "rp", &RP) == -1)
1323		RP = DEFLP;
1324	if (cgetstr(bp, "lo", &LO) == -1)
1325		LO = DEFLOCK;
1326	if (cgetstr(bp, "st", &ST) == -1)
1327		ST = DEFSTAT;
1328	if (cgetstr(bp, "lf", &LF) == -1)
1329		LF = _PATH_CONSOLE;
1330	if (cgetstr(bp, "sd", &SD) == -1)
1331		SD = _PATH_DEFSPOOL;
1332	if (cgetnum(bp, "du", &DU) < 0)
1333		DU = DEFUID;
1334	if (cgetstr(bp,"ff", &FF) == -1)
1335		FF = DEFFF;
1336	if (cgetnum(bp, "pw", &PW) < 0)
1337		PW = DEFWIDTH;
1338	sprintf(&width[2], "%d", PW);
1339	if (cgetnum(bp, "pl", &PL) < 0)
1340		PL = DEFLENGTH;
1341	sprintf(&length[2], "%d", PL);
1342	if (cgetnum(bp,"px", &PX) < 0)
1343		PX = 0;
1344	sprintf(&pxwidth[2], "%d", PX);
1345	if (cgetnum(bp, "py", &PY) < 0)
1346		PY = 0;
1347	sprintf(&pxlength[2], "%d", PY);
1348	cgetstr(bp, "rm", &RM);
1349	if (s = checkremote())
1350		syslog(LOG_WARNING, s);
1351
1352	cgetstr(bp, "af", &AF);
1353	cgetstr(bp, "of", &OF);
1354	cgetstr(bp, "if", &IF);
1355	cgetstr(bp, "rf", &RF);
1356	cgetstr(bp, "tf", &TF);
1357	cgetstr(bp, "nf", &NF);
1358	cgetstr(bp, "df", &DF);
1359	cgetstr(bp, "gf", &GF);
1360	cgetstr(bp, "vf", &VF);
1361	cgetstr(bp, "cf", &CF);
1362	cgetstr(bp, "tr", &TR);
1363	cgetstr(bp, "ms", &MS);
1364
1365	RS = (cgetcap(bp, "rs", ':') != NULL);
1366	SF = (cgetcap(bp, "sf", ':') != NULL);
1367	SH = (cgetcap(bp, "sh", ':') != NULL);
1368	SB = (cgetcap(bp, "sb", ':') != NULL);
1369	HL = (cgetcap(bp, "hl", ':') != NULL);
1370	RW = (cgetcap(bp, "rw", ':') != NULL);
1371
1372	cgetnum(bp, "br", &BR);
1373
1374	tof = (cgetcap(bp, "fo", ':') == NULL);
1375}
1376
1377/*
1378 * Acquire line printer or remote connection.
1379 */
1380static void
1381openpr()
1382{
1383	register int i;
1384	int dtablesize;
1385	char *cp;
1386
1387	if (!remote && *LP) {
1388		if (cp = index(LP, '@'))
1389			opennet(cp);
1390		else
1391			opentty();
1392	} else if (remote) {
1393		openrem();
1394	} else {
1395		syslog(LOG_ERR, "%s: no line printer device or host name",
1396			printer);
1397		exit(1);
1398	}
1399
1400	/*
1401	 * Start up an output filter, if needed.
1402	 */
1403	if (OF && !IF && !ofilter) {
1404		int p[2];
1405
1406		pipe(p);
1407		if (remote) {
1408			strcpy(tfile,TFILENAME);
1409			tfd = mkstemp(tfile);
1410		}
1411		if ((ofilter = dofork(DOABORT)) == 0) {	/* child */
1412			dup2(p[0], 0);		/* pipe is std in */
1413			/* tfile/printer is stdout */
1414			dup2(remote ? tfd : pfd, 1);
1415			closelog();
1416			for (i = 3, dtablesize = getdtablesize();
1417			     i < dtablesize; i++)
1418				(void) close(i);
1419			if ((cp = rindex(OF, '/')) == NULL)
1420				cp = OF;
1421			else
1422				cp++;
1423			execl(OF, cp, width, length, 0);
1424			syslog(LOG_ERR, "%s: %s: %m", printer, OF);
1425			exit(1);
1426		}
1427		(void) close(p[0]);		/* close input side */
1428		ofd = p[1];			/* use pipe for output */
1429	} else {
1430		ofd = pfd;
1431		ofilter = 0;
1432	}
1433}
1434
1435/*
1436 * Printer connected directly to the network
1437 * or to a terminal server on the net
1438 */
1439static void
1440opennet(cp)
1441	char *cp;
1442{
1443	register int i;
1444	int resp, port;
1445	char save_ch;
1446
1447	save_ch = *cp;
1448	*cp = '\0';
1449	port = atoi(LP);
1450	if (port <= 0) {
1451		syslog(LOG_ERR, "%s: bad port number: %s", printer, LP);
1452		exit(1);
1453	}
1454	*cp++ = save_ch;
1455
1456	for (i = 1; ; i = i < 256 ? i << 1 : i) {
1457		resp = -1;
1458		pfd = getport(cp, port);
1459		if (pfd < 0 && errno == ECONNREFUSED)
1460			resp = 1;
1461		else if (pfd >= 0) {
1462			/*
1463			 * need to delay a bit for rs232 lines
1464			 * to stabilize in case printer is
1465			 * connected via a terminal server
1466			 */
1467			delay(500);
1468			break;
1469		}
1470		if (i == 1) {
1471		   if (resp < 0)
1472			pstatus("waiting for %s to come up", LP);
1473		   else
1474			pstatus("waiting for access to printer on %s", LP);
1475		}
1476		sleep(i);
1477	}
1478	pstatus("sending to %s port %d", cp, port);
1479}
1480
1481/*
1482 * Printer is connected to an RS232 port on this host
1483 */
1484static void
1485opentty()
1486{
1487	register int i;
1488	int resp, port;
1489
1490	for (i = 1; ; i = i < 32 ? i << 1 : i) {
1491		pfd = open(LP, RW ? O_RDWR : O_WRONLY);
1492		if (pfd >= 0) {
1493			delay(500);
1494			break;
1495		}
1496		if (errno == ENOENT) {
1497			syslog(LOG_ERR, "%s: %m", LP);
1498			exit(1);
1499		}
1500		if (i == 1)
1501			pstatus("waiting for %s to become ready (offline ?)",
1502				printer);
1503		sleep(i);
1504	}
1505	if (isatty(pfd))
1506		setty();
1507	pstatus("%s is ready and printing", printer);
1508}
1509
1510/*
1511 * Printer is on a remote host
1512 */
1513static void
1514openrem()
1515{
1516	register int i, n;
1517	int resp, port;
1518
1519	for (i = 1; ; i = i < 256 ? i << 1 : i) {
1520		resp = -1;
1521		pfd = getport(RM, 0);
1522		if (pfd >= 0) {
1523			(void) sprintf(line, "\2%s\n", RP);
1524			n = strlen(line);
1525			if (write(pfd, line, n) == n &&
1526			    (resp = response()) == '\0')
1527				break;
1528			(void) close(pfd);
1529		}
1530		if (i == 1) {
1531			if (resp < 0)
1532				pstatus("waiting for %s to come up", RM);
1533			else {
1534				pstatus("waiting for queue to be enabled on %s",
1535					RM);
1536				i = 256;
1537			}
1538		}
1539		sleep(i);
1540	}
1541	pstatus("sending to %s", RM);
1542}
1543
1544struct bauds {
1545	int	baud;
1546	int	speed;
1547} bauds[] = {
1548	50,	B50,
1549	75,	B75,
1550	110,	B110,
1551	134,	B134,
1552	150,	B150,
1553	200,	B200,
1554	300,	B300,
1555	600,	B600,
1556	1200,	B1200,
1557	1800,	B1800,
1558	2400,	B2400,
1559	4800,	B4800,
1560	9600,	B9600,
1561	19200,	EXTA,
1562	38400,	EXTB,
1563	57600,	B57600,
1564	115200,	B115200,
1565	0,	0
1566};
1567
1568/*
1569 * setup tty lines.
1570 */
1571static void
1572setty()
1573{
1574	struct termios ttybuf;
1575	struct bauds *bp;
1576
1577	if (ioctl(pfd, TIOCEXCL, (char *)0) < 0) {
1578		syslog(LOG_ERR, "%s: ioctl(TIOCEXCL): %m", printer);
1579		exit(1);
1580	}
1581	if (tcgetattr(pfd, &ttybuf) < 0) {
1582		syslog(LOG_ERR, "%s: tcgetattr: %m", printer);
1583		exit(1);
1584	}
1585	if (BR > 0) {
1586		for (bp = bauds; bp->baud; bp++)
1587			if (BR == bp->baud)
1588				break;
1589		if (!bp->baud) {
1590			syslog(LOG_ERR, "%s: illegal baud rate %d", printer, BR);
1591			exit(1);
1592		}
1593		cfsetspeed(&ttybuf, bp->speed);
1594	}
1595	if (MS) {
1596		char *s = strdup(MS), *tmp;
1597
1598		while (tmp = strsep (&s, ",")) {
1599			msearch(tmp, &ttybuf);
1600		}
1601	}
1602	if (MS || (BR > 0)) {
1603		if (tcsetattr(pfd, TCSAFLUSH, &ttybuf) == -1) {
1604			syslog(LOG_ERR, "%s: tcsetattr: %m", printer);
1605		}
1606	}
1607}
1608
1609#if __STDC__
1610#include <stdarg.h>
1611#else
1612#include <varargs.h>
1613#endif
1614
1615static void
1616#if __STDC__
1617pstatus(const char *msg, ...)
1618#else
1619pstatus(msg, va_alist)
1620	char *msg;
1621        va_dcl
1622#endif
1623{
1624	register int fd;
1625	char buf[BUFSIZ];
1626	va_list ap;
1627#if __STDC__
1628	va_start(ap, msg);
1629#else
1630	va_start(ap);
1631#endif
1632
1633	umask(0);
1634	fd = open(ST, O_WRONLY|O_CREAT, 0664);
1635	if (fd < 0 || flock(fd, LOCK_EX) < 0) {
1636		syslog(LOG_ERR, "%s: %s: %m", printer, ST);
1637		exit(1);
1638	}
1639	ftruncate(fd, 0);
1640	(void)vsnprintf(buf, sizeof(buf), msg, ap);
1641	va_end(ap);
1642	strcat(buf, "\n");
1643	(void) write(fd, buf, strlen(buf));
1644	(void) close(fd);
1645}
1646