GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: usr.sbin/lpr/lpd/printjob.c Lines: 0 824 0.0 %
Date: 2017-11-13 Branches: 0 535 0.0 %

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