printjob.c revision 27748
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	char buf[100];
1201	struct stat stb;
1202	FILE *fp;
1203
1204	pipe(p);
1205	if ((s = dofork(DORETURN)) == 0) {		/* child */
1206		dup2(p[0], 0);
1207		closelog();
1208		for (i = 3, dtablesize = getdtablesize(); i < dtablesize; i++)
1209			(void) close(i);
1210		if ((cp = strrchr(_PATH_SENDMAIL, '/')) != NULL)
1211			cp++;
1212	else
1213			cp = _PATH_SENDMAIL;
1214		sprintf(buf, "%s@%s", user, fromhost);
1215		execl(_PATH_SENDMAIL, cp, buf, 0);
1216		exit(0);
1217	} else if (s > 0) {				/* parent */
1218		dup2(p[1], 1);
1219		printf("To: %s@%s\n", user, fromhost);
1220		printf("Subject: %s printer job \"%s\"\n", printer,
1221			*jobname ? jobname : "<unknown>");
1222		printf("Reply-To: root@%s\n\n", host);
1223		printf("Your printer job ");
1224		if (*jobname)
1225			printf("(%s) ", jobname);
1226		switch (bombed) {
1227		case OK:
1228			printf("\ncompleted successfully\n");
1229			cp = "OK";
1230			break;
1231		default:
1232		case FATALERR:
1233			printf("\ncould not be printed\n");
1234			cp = "FATALERR";
1235			break;
1236		case NOACCT:
1237			printf("\ncould not be printed without an account on %s\n", host);
1238			cp = "NOACCT";
1239			break;
1240		case FILTERERR:
1241			if (stat(tempfile, &stb) < 0 || stb.st_size == 0 ||
1242			    (fp = fopen(tempfile, "r")) == NULL) {
1243				printf("\nhad some errors and may not have printed\n");
1244				break;
1245			}
1246			printf("\nhad the following errors and may not have printed:\n");
1247			while ((i = getc(fp)) != EOF)
1248				putchar(i);
1249			(void) fclose(fp);
1250			cp = "FILTERERR";
1251			break;
1252		case ACCESS:
1253			printf("\nwas not printed because it was not linked to the original file\n");
1254			cp = "ACCESS";
1255		}
1256		fflush(stdout);
1257		(void) close(1);
1258	}
1259	(void) close(p[0]);
1260	(void) close(p[1]);
1261	wait(NULL);
1262	syslog(LOG_INFO, "mail sent to user %s about job %s on printer %s (%s)",
1263		user, *jobname ? jobname : "<unknown>", printer, cp);
1264}
1265
1266/*
1267 * dofork - fork with retries on failure
1268 */
1269static int
1270dofork(action)
1271	int action;
1272{
1273	register int i, pid;
1274
1275	for (i = 0; i < 20; i++) {
1276		if ((pid = fork()) < 0) {
1277			sleep((unsigned)(i*i));
1278			continue;
1279		}
1280		/*
1281		 * Child should run as daemon instead of root
1282		 */
1283		if (pid == 0)
1284			setuid(DU);
1285		return(pid);
1286	}
1287	syslog(LOG_ERR, "can't fork");
1288
1289	switch (action) {
1290	case DORETURN:
1291		return (-1);
1292	default:
1293		syslog(LOG_ERR, "bad action (%d) to dofork", action);
1294		/*FALL THRU*/
1295	case DOABORT:
1296		exit(1);
1297	}
1298	/*NOTREACHED*/
1299}
1300
1301/*
1302 * Kill child processes to abort current job.
1303 */
1304static void
1305abortpr(signo)
1306	int signo;
1307{
1308	(void) unlink(tempfile);
1309	kill(0, SIGINT);
1310	if (ofilter > 0)
1311		kill(ofilter, SIGCONT);
1312	while (wait(NULL) > 0)
1313		;
1314	if (ofilter > 0 && tfd != -1)
1315		unlink(tfile);
1316	exit(0);
1317}
1318
1319static void
1320init()
1321{
1322	int status;
1323	char *s;
1324
1325	if ((status = cgetent(&bp, printcapdb, printer)) == -2) {
1326		syslog(LOG_ERR, "can't open printer description file");
1327		exit(1);
1328	} else if (status == -1) {
1329		syslog(LOG_ERR, "unknown printer: %s", printer);
1330		exit(1);
1331	} else if (status == -3)
1332		fatal("potential reference loop detected in printcap file");
1333
1334	if (cgetstr(bp, "lp", &LP) == -1)
1335		LP = _PATH_DEFDEVLP;
1336	if (cgetstr(bp, "rp", &RP) == -1)
1337		RP = DEFLP;
1338	if (cgetstr(bp, "lo", &LO) == -1)
1339		LO = DEFLOCK;
1340	if (cgetstr(bp, "st", &ST) == -1)
1341		ST = DEFSTAT;
1342	if (cgetstr(bp, "lf", &LF) == -1)
1343		LF = _PATH_CONSOLE;
1344	if (cgetstr(bp, "sd", &SD) == -1)
1345		SD = _PATH_DEFSPOOL;
1346	if (cgetnum(bp, "du", &DU) < 0)
1347		DU = DEFUID;
1348	if (cgetstr(bp,"ff", &FF) == -1)
1349		FF = DEFFF;
1350	if (cgetnum(bp, "pw", &PW) < 0)
1351		PW = DEFWIDTH;
1352	sprintf(&width[2], "%ld", PW);
1353	if (cgetnum(bp, "pl", &PL) < 0)
1354		PL = DEFLENGTH;
1355	sprintf(&length[2], "%ld", PL);
1356	if (cgetnum(bp,"px", &PX) < 0)
1357		PX = 0;
1358	sprintf(&pxwidth[2], "%ld", PX);
1359	if (cgetnum(bp, "py", &PY) < 0)
1360		PY = 0;
1361	sprintf(&pxlength[2], "%ld", PY);
1362	cgetstr(bp, "rm", &RM);
1363	if ((s = checkremote()))
1364		syslog(LOG_WARNING, s);
1365
1366	cgetstr(bp, "af", &AF);
1367	cgetstr(bp, "of", &OF);
1368	cgetstr(bp, "if", &IF);
1369	cgetstr(bp, "rf", &RF);
1370	cgetstr(bp, "tf", &TF);
1371	cgetstr(bp, "nf", &NF);
1372	cgetstr(bp, "df", &DF);
1373	cgetstr(bp, "gf", &GF);
1374	cgetstr(bp, "vf", &VF);
1375	cgetstr(bp, "cf", &CF);
1376	cgetstr(bp, "tr", &TR);
1377	cgetstr(bp, "ms", &MS);
1378
1379	RS = (cgetcap(bp, "rs", ':') != NULL);
1380	SF = (cgetcap(bp, "sf", ':') != NULL);
1381	SH = (cgetcap(bp, "sh", ':') != NULL);
1382	SB = (cgetcap(bp, "sb", ':') != NULL);
1383	HL = (cgetcap(bp, "hl", ':') != NULL);
1384	RW = (cgetcap(bp, "rw", ':') != NULL);
1385
1386	cgetnum(bp, "br", &BR);
1387
1388	tof = (cgetcap(bp, "fo", ':') == NULL);
1389}
1390
1391/*
1392 * Acquire line printer or remote connection.
1393 */
1394static void
1395openpr()
1396{
1397	register int i;
1398	int dtablesize;
1399	char *cp;
1400
1401	if (!remote && *LP) {
1402		if (cp = strchr(LP, '@'))
1403			opennet(cp);
1404		else
1405			opentty();
1406	} else if (remote) {
1407		openrem();
1408	} else {
1409		syslog(LOG_ERR, "%s: no line printer device or host name",
1410			printer);
1411		exit(1);
1412	}
1413
1414	/*
1415	 * Start up an output filter, if needed.
1416	 */
1417	if (OF && !IF && !ofilter) {
1418		int p[2];
1419
1420		pipe(p);
1421		if (remote) {
1422			strcpy(tfile,TFILENAME);
1423			tfd = mkstemp(tfile);
1424		}
1425		if ((ofilter = dofork(DOABORT)) == 0) {	/* child */
1426			dup2(p[0], 0);		/* pipe is std in */
1427			/* tfile/printer is stdout */
1428			dup2(remote ? tfd : pfd, 1);
1429			closelog();
1430			for (i = 3, dtablesize = getdtablesize();
1431			     i < dtablesize; i++)
1432				(void) close(i);
1433			if ((cp = strrchr(OF, '/')) == NULL)
1434				cp = OF;
1435			else
1436				cp++;
1437			execl(OF, cp, width, length, 0);
1438			syslog(LOG_ERR, "%s: %s: %m", printer, OF);
1439			exit(1);
1440		}
1441		(void) close(p[0]);		/* close input side */
1442		ofd = p[1];			/* use pipe for output */
1443	} else {
1444		ofd = pfd;
1445		ofilter = 0;
1446	}
1447}
1448
1449/*
1450 * Printer connected directly to the network
1451 * or to a terminal server on the net
1452 */
1453static void
1454opennet(cp)
1455	char *cp;
1456{
1457	register int i;
1458	int resp, port;
1459	char save_ch;
1460
1461	save_ch = *cp;
1462	*cp = '\0';
1463	port = atoi(LP);
1464	if (port <= 0) {
1465		syslog(LOG_ERR, "%s: bad port number: %s", printer, LP);
1466		exit(1);
1467	}
1468	*cp++ = save_ch;
1469
1470	for (i = 1; ; i = i < 256 ? i << 1 : i) {
1471		resp = -1;
1472		pfd = getport(cp, port);
1473		if (pfd < 0 && errno == ECONNREFUSED)
1474			resp = 1;
1475		else if (pfd >= 0) {
1476			/*
1477			 * need to delay a bit for rs232 lines
1478			 * to stabilize in case printer is
1479			 * connected via a terminal server
1480			 */
1481			delay(500);
1482			break;
1483		}
1484		if (i == 1) {
1485		   if (resp < 0)
1486			pstatus("waiting for %s to come up", LP);
1487		   else
1488			pstatus("waiting for access to printer on %s", LP);
1489		}
1490		sleep(i);
1491	}
1492	pstatus("sending to %s port %d", cp, port);
1493}
1494
1495/*
1496 * Printer is connected to an RS232 port on this host
1497 */
1498static void
1499opentty()
1500{
1501	register int i;
1502	int resp, port;
1503
1504	for (i = 1; ; i = i < 32 ? i << 1 : i) {
1505		pfd = open(LP, RW ? O_RDWR : O_WRONLY);
1506		if (pfd >= 0) {
1507			delay(500);
1508			break;
1509		}
1510		if (errno == ENOENT) {
1511			syslog(LOG_ERR, "%s: %m", LP);
1512			exit(1);
1513		}
1514		if (i == 1)
1515			pstatus("waiting for %s to become ready (offline ?)",
1516				printer);
1517		sleep(i);
1518	}
1519	if (isatty(pfd))
1520		setty();
1521	pstatus("%s is ready and printing", printer);
1522}
1523
1524/*
1525 * Printer is on a remote host
1526 */
1527static void
1528openrem()
1529{
1530	register int i, n;
1531	int resp;
1532
1533	for (i = 1; ; i = i < 256 ? i << 1 : i) {
1534		resp = -1;
1535		pfd = getport(RM, 0);
1536		if (pfd >= 0) {
1537			(void) snprintf(line, sizeof(line), "\2%s\n", RP);
1538			n = strlen(line);
1539			if (write(pfd, line, n) == n &&
1540			    (resp = response()) == '\0')
1541				break;
1542			(void) close(pfd);
1543		}
1544		if (i == 1) {
1545			if (resp < 0)
1546				pstatus("waiting for %s to come up", RM);
1547			else {
1548				pstatus("waiting for queue to be enabled on %s",
1549					RM);
1550				i = 256;
1551			}
1552		}
1553		sleep(i);
1554	}
1555	pstatus("sending to %s", RM);
1556}
1557
1558struct bauds {
1559	int	baud;
1560	int	speed;
1561} bauds[] = {
1562	50,	B50,
1563	75,	B75,
1564	110,	B110,
1565	134,	B134,
1566	150,	B150,
1567	200,	B200,
1568	300,	B300,
1569	600,	B600,
1570	1200,	B1200,
1571	1800,	B1800,
1572	2400,	B2400,
1573	4800,	B4800,
1574	9600,	B9600,
1575	19200,	EXTA,
1576	38400,	EXTB,
1577	57600,	B57600,
1578	115200,	B115200,
1579	0,	0
1580};
1581
1582/*
1583 * setup tty lines.
1584 */
1585static void
1586setty()
1587{
1588	struct termios ttybuf;
1589	struct bauds *bp;
1590
1591	if (ioctl(pfd, TIOCEXCL, (char *)0) < 0) {
1592		syslog(LOG_ERR, "%s: ioctl(TIOCEXCL): %m", printer);
1593		exit(1);
1594	}
1595	if (tcgetattr(pfd, &ttybuf) < 0) {
1596		syslog(LOG_ERR, "%s: tcgetattr: %m", printer);
1597		exit(1);
1598	}
1599	if (BR > 0) {
1600		for (bp = bauds; bp->baud; bp++)
1601			if (BR == bp->baud)
1602				break;
1603		if (!bp->baud) {
1604			syslog(LOG_ERR, "%s: illegal baud rate %d", printer, BR);
1605			exit(1);
1606		}
1607		cfsetspeed(&ttybuf, bp->speed);
1608	}
1609	if (MS) {
1610		char *s = strdup(MS), *tmp;
1611
1612		while (tmp = strsep (&s, ",")) {
1613			msearch(tmp, &ttybuf);
1614		}
1615	}
1616	if (MS || (BR > 0)) {
1617		if (tcsetattr(pfd, TCSAFLUSH, &ttybuf) == -1) {
1618			syslog(LOG_ERR, "%s: tcsetattr: %m", printer);
1619		}
1620	}
1621}
1622
1623#if __STDC__
1624#include <stdarg.h>
1625#else
1626#include <varargs.h>
1627#endif
1628
1629static void
1630#if __STDC__
1631pstatus(const char *msg, ...)
1632#else
1633pstatus(msg, va_alist)
1634	char *msg;
1635        va_dcl
1636#endif
1637{
1638	register int fd;
1639	char buf[BUFSIZ];
1640	va_list ap;
1641#if __STDC__
1642	va_start(ap, msg);
1643#else
1644	va_start(ap);
1645#endif
1646
1647	umask(0);
1648	fd = open(ST, O_WRONLY|O_CREAT, 0664);
1649	if (fd < 0 || flock(fd, LOCK_EX) < 0) {
1650		syslog(LOG_ERR, "%s: %s: %m", printer, ST);
1651		exit(1);
1652	}
1653	ftruncate(fd, 0);
1654	(void)vsnprintf(buf, sizeof(buf), msg, ap);
1655	va_end(ap);
1656	strcat(buf, "\n");
1657	(void) write(fd, buf, strlen(buf));
1658	(void) close(fd);
1659}
1660