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