Deleted Added
sdiff udiff text old ( 216372 ) new ( 228664 )
full compact
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 * 4. Neither the name of the University nor the names of its contributors
15 * may be used to endorse or promote products derived from this software
16 * without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
19 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
22 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28 * SUCH DAMAGE.
29 */
30
31#ifndef lint
32static const char copyright[] =
33"@(#) Copyright (c) 1983, 1993\n\
34 The Regents of the University of California. All rights reserved.\n";
35#endif /* not lint */
36
37#if 0
38#ifndef lint
39static char sccsid[] = "@(#)printjob.c 8.7 (Berkeley) 5/10/95";
40#endif /* not lint */
41#endif
42
43#include "lp.cdefs.h" /* A cross-platform version of <sys/cdefs.h> */
44__FBSDID("$FreeBSD: head/usr.sbin/lpr/lpd/printjob.c 216372 2010-12-11 09:38:12Z joel $");
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 /* dofork should return "can't fork" error */
77#define DOABORT 1 /* dofork should just die if fork() fails */
78
79/*
80 * The buffer size to use when reading/writing spool files.
81 */
82#define SPL_BUFSIZ BUFSIZ
83
84/*
85 * Error tokens
86 */
87#define REPRINT -2
88#define ERROR -1
89#define OK 0
90#define FATALERR 1
91#define NOACCT 2
92#define FILTERERR 3
93#define ACCESS 4
94
95static dev_t fdev; /* device of file pointed to by symlink */
96static ino_t fino; /* inode of file pointed to by symlink */
97static FILE *cfp; /* control file */
98static pid_t of_pid; /* process id of output filter, if any */
99static int child; /* id of any filters */
100static int job_dfcnt; /* count of datafiles in current user job */
101static int lfd; /* lock file descriptor */
102static int ofd; /* output filter file descriptor */
103static int tfd = -1; /* output filter temp file output */
104static int pfd; /* prstatic inter file descriptor */
105static int prchild; /* id of pr process */
106static char title[80]; /* ``pr'' title */
107static char locale[80]; /* ``pr'' locale */
108
109/* these two are set from pp->daemon_user, but only if they are needed */
110static char *daemon_uname; /* set from pwd->pw_name */
111static int daemon_defgid;
112
113static char class[32]; /* classification field */
114static char origin_host[MAXHOSTNAMELEN]; /* user's host machine */
115 /* indentation size in static characters */
116static char indent[10] = "-i0";
117static char jobname[100]; /* job or file name */
118static char length[10] = "-l"; /* page length in lines */
119static char logname[32]; /* user's login name */
120static char pxlength[10] = "-y"; /* page length in pixels */
121static char pxwidth[10] = "-x"; /* page width in pixels */
122/* tempstderr is the filename used to catch stderr from exec-ing filters */
123static char tempstderr[] = "errs.XXXXXXX";
124static char width[10] = "-w"; /* page width in static characters */
125#define TFILENAME "fltXXXXXX"
126static char tfile[] = TFILENAME; /* file name for filter output */
127
128static void abortpr(int _signo);
129static void alarmhandler(int _signo);
130static void banner(struct printer *_pp, char *_name1, char *_name2);
131static int dofork(const struct printer *_pp, int _action);
132static int dropit(int _c);
133static int execfilter(struct printer *_pp, char *_f_cmd, char **_f_av,
134 int _infd, int _outfd);
135static void init(struct printer *_pp);
136static void openpr(const struct printer *_pp);
137static void opennet(const struct printer *_pp);
138static void opentty(const struct printer *_pp);
139static void openrem(const struct printer *pp);
140static int print(struct printer *_pp, int _format, char *_file);
141static int printit(struct printer *_pp, char *_file);
142static void pstatus(const struct printer *_pp, const char *_msg, ...)
143 __printflike(2, 3);
144static char response(const struct printer *_pp);
145static void scan_out(struct printer *_pp, int _scfd, char *_scsp,
146 int _dlm);
147static char *scnline(int _key, char *_p, int _c);
148static int sendfile(struct printer *_pp, int _type, char *_file,
149 char _format, int _copyreq);
150static int sendit(struct printer *_pp, char *_file);
151static void sendmail(struct printer *_pp, char *_userid, int _bombed);
152static void setty(const struct printer *_pp);
153static void wait4data(struct printer *_pp, const char *_dfile);
154
155void
156printjob(struct printer *pp)
157{
158 struct stat stb;
159 register struct jobqueue *q, **qp;
160 struct jobqueue **queue;
161 register int i, nitems;
162 off_t pidoff;
163 pid_t printpid;
164 int errcnt, jobcount, statok, tempfd;
165
166 jobcount = 0;
167 init(pp); /* set up capabilities */
168 (void) write(STDOUT_FILENO, "", 1); /* ack that daemon is started */
169 (void) close(STDERR_FILENO); /* set up log file */
170 if (open(pp->log_file, O_WRONLY|O_APPEND, LOG_FILE_MODE) < 0) {
171 syslog(LOG_ERR, "%s: open(%s): %m", pp->printer,
172 pp->log_file);
173 (void) open(_PATH_DEVNULL, O_WRONLY);
174 }
175 setgid(getegid());
176 printpid = getpid(); /* for use with lprm */
177 setpgrp(0, printpid);
178
179 /*
180 * At initial lpd startup, printjob may be called with various
181 * signal handlers in effect. After that initial startup, any
182 * calls to printjob will have a *different* set of signal-handlers
183 * in effect. Make sure all handlers are the ones we want.
184 */
185 signal(SIGCHLD, SIG_DFL);
186 signal(SIGHUP, abortpr);
187 signal(SIGINT, abortpr);
188 signal(SIGQUIT, abortpr);
189 signal(SIGTERM, abortpr);
190
191 /*
192 * uses short form file names
193 */
194 if (chdir(pp->spool_dir) < 0) {
195 syslog(LOG_ERR, "%s: chdir(%s): %m", pp->printer,
196 pp->spool_dir);
197 exit(1);
198 }
199 statok = stat(pp->lock_file, &stb);
200 if (statok == 0 && (stb.st_mode & LFM_PRINT_DIS))
201 exit(0); /* printing disabled */
202 umask(S_IWOTH);
203 lfd = open(pp->lock_file, O_WRONLY|O_CREAT|O_EXLOCK|O_NONBLOCK,
204 LOCK_FILE_MODE);
205 if (lfd < 0) {
206 if (errno == EWOULDBLOCK) /* active daemon present */
207 exit(0);
208 syslog(LOG_ERR, "%s: open(%s): %m", pp->printer,
209 pp->lock_file);
210 exit(1);
211 }
212 /*
213 * If the initial call to stat() failed, then lock_file will have
214 * been created by open(). Update &stb to match that new file.
215 */
216 if (statok != 0)
217 statok = stat(pp->lock_file, &stb);
218 /* turn off non-blocking mode (was turned on for lock effects only) */
219 if (fcntl(lfd, F_SETFL, 0) < 0) {
220 syslog(LOG_ERR, "%s: fcntl(%s): %m", pp->printer,
221 pp->lock_file);
222 exit(1);
223 }
224 ftruncate(lfd, 0);
225 /*
226 * write process id for others to know
227 */
228 sprintf(line, "%u\n", printpid);
229 pidoff = i = strlen(line);
230 if (write(lfd, line, i) != i) {
231 syslog(LOG_ERR, "%s: write(%s): %m", pp->printer,
232 pp->lock_file);
233 exit(1);
234 }
235 /*
236 * search the spool directory for work and sort by queue order.
237 */
238 if ((nitems = getq(pp, &queue)) < 0) {
239 syslog(LOG_ERR, "%s: can't scan %s", pp->printer,
240 pp->spool_dir);
241 exit(1);
242 }
243 if (nitems == 0) /* no work to do */
244 exit(0);
245 if (stb.st_mode & LFM_RESET_QUE) { /* reset queue flag */
246 if (fchmod(lfd, stb.st_mode & ~LFM_RESET_QUE) < 0)
247 syslog(LOG_ERR, "%s: fchmod(%s): %m", pp->printer,
248 pp->lock_file);
249 }
250
251 /* create a file which will be used to hold stderr from filters */
252 if ((tempfd = mkstemp(tempstderr)) == -1) {
253 syslog(LOG_ERR, "%s: mkstemp(%s): %m", pp->printer,
254 tempstderr);
255 exit(1);
256 }
257 if ((i = fchmod(tempfd, 0664)) == -1) {
258 syslog(LOG_ERR, "%s: fchmod(%s): %m", pp->printer,
259 tempstderr);
260 exit(1);
261 }
262 /* lpd doesn't need it to be open, it just needs it to exist */
263 close(tempfd);
264
265 openpr(pp); /* open printer or remote */
266again:
267 /*
268 * we found something to do now do it --
269 * write the name of the current control file into the lock file
270 * so the spool queue program can tell what we're working on
271 */
272 for (qp = queue; nitems--; free((char *) q)) {
273 q = *qp++;
274 if (stat(q->job_cfname, &stb) < 0)
275 continue;
276 errcnt = 0;
277 restart:
278 (void) lseek(lfd, pidoff, 0);
279 (void) snprintf(line, sizeof(line), "%s\n", q->job_cfname);
280 i = strlen(line);
281 if (write(lfd, line, i) != i)
282 syslog(LOG_ERR, "%s: write(%s): %m", pp->printer,
283 pp->lock_file);
284 if (!pp->remote)
285 i = printit(pp, q->job_cfname);
286 else
287 i = sendit(pp, q->job_cfname);
288 /*
289 * Check to see if we are supposed to stop printing or
290 * if we are to rebuild the queue.
291 */
292 if (fstat(lfd, &stb) == 0) {
293 /* stop printing before starting next job? */
294 if (stb.st_mode & LFM_PRINT_DIS)
295 goto done;
296 /* rebuild queue (after lpc topq) */
297 if (stb.st_mode & LFM_RESET_QUE) {
298 for (free(q); nitems--; free(q))
299 q = *qp++;
300 if (fchmod(lfd, stb.st_mode & ~LFM_RESET_QUE)
301 < 0)
302 syslog(LOG_WARNING,
303 "%s: fchmod(%s): %m",
304 pp->printer, pp->lock_file);
305 break;
306 }
307 }
308 if (i == OK) /* all files of this job printed */
309 jobcount++;
310 else if (i == REPRINT && ++errcnt < 5) {
311 /* try reprinting the job */
312 syslog(LOG_INFO, "restarting %s", pp->printer);
313 if (of_pid > 0) {
314 kill(of_pid, SIGCONT); /* to be sure */
315 (void) close(ofd);
316 while ((i = wait(NULL)) > 0 && i != of_pid)
317 ;
318 if (i < 0)
319 syslog(LOG_WARNING, "%s: after kill(of=%d), wait() returned: %m",
320 pp->printer, of_pid);
321 of_pid = 0;
322 }
323 (void) close(pfd); /* close printer */
324 if (ftruncate(lfd, pidoff) < 0)
325 syslog(LOG_WARNING, "%s: ftruncate(%s): %m",
326 pp->printer, pp->lock_file);
327 openpr(pp); /* try to reopen printer */
328 goto restart;
329 } else {
330 syslog(LOG_WARNING, "%s: job could not be %s (%s)",
331 pp->printer,
332 pp->remote ? "sent to remote host" : "printed",
333 q->job_cfname);
334 if (i == REPRINT) {
335 /* ensure we don't attempt this job again */
336 (void) unlink(q->job_cfname);
337 q->job_cfname[0] = 'd';
338 (void) unlink(q->job_cfname);
339 if (logname[0])
340 sendmail(pp, logname, FATALERR);
341 }
342 }
343 }
344 free(queue);
345 /*
346 * search the spool directory for more work.
347 */
348 if ((nitems = getq(pp, &queue)) < 0) {
349 syslog(LOG_ERR, "%s: can't scan %s", pp->printer,
350 pp->spool_dir);
351 exit(1);
352 }
353 if (nitems == 0) { /* no more work to do */
354 done:
355 if (jobcount > 0) { /* jobs actually printed */
356 if (!pp->no_formfeed && !pp->tof)
357 (void) write(ofd, pp->form_feed,
358 strlen(pp->form_feed));
359 if (pp->trailer != NULL) /* output trailer */
360 (void) write(ofd, pp->trailer,
361 strlen(pp->trailer));
362 }
363 (void) close(ofd);
364 (void) wait(NULL);
365 (void) unlink(tempstderr);
366 exit(0);
367 }
368 goto again;
369}
370
371char fonts[4][50]; /* fonts for troff */
372
373char ifonts[4][40] = {
374 _PATH_VFONTR,
375 _PATH_VFONTI,
376 _PATH_VFONTB,
377 _PATH_VFONTS,
378};
379
380/*
381 * The remaining part is the reading of the control file (cf)
382 * and performing the various actions.
383 */
384static int
385printit(struct printer *pp, char *file)
386{
387 register int i;
388 char *cp;
389 int bombed, didignorehdr;
390
391 bombed = OK;
392 didignorehdr = 0;
393 /*
394 * open control file; ignore if no longer there.
395 */
396 if ((cfp = fopen(file, "r")) == NULL) {
397 syslog(LOG_INFO, "%s: fopen(%s): %m", pp->printer, file);
398 return (OK);
399 }
400 /*
401 * Reset troff fonts.
402 */
403 for (i = 0; i < 4; i++)
404 strcpy(fonts[i], ifonts[i]);
405 sprintf(&width[2], "%ld", pp->page_width);
406 strcpy(indent+2, "0");
407
408 /* initialize job-specific count of datafiles processed */
409 job_dfcnt = 0;
410
411 /*
412 * read the control file for work to do
413 *
414 * file format -- first character in the line is a command
415 * rest of the line is the argument.
416 * valid commands are:
417 *
418 * S -- "stat info" for symbolic link protection
419 * J -- "job name" on banner page
420 * C -- "class name" on banner page
421 * L -- "literal" user's name to print on banner
422 * T -- "title" for pr
423 * H -- "host name" of machine where lpr was done
424 * P -- "person" user's login name
425 * I -- "indent" amount to indent output
426 * R -- laser dpi "resolution"
427 * f -- "file name" name of text file to print
428 * l -- "file name" text file with control chars
429 * o -- "file name" postscript file, according to
430 * the RFC. Here it is treated like an 'f'.
431 * p -- "file name" text file to print with pr(1)
432 * t -- "file name" troff(1) file to print
433 * n -- "file name" ditroff(1) file to print
434 * d -- "file name" dvi file to print
435 * g -- "file name" plot(1G) file to print
436 * v -- "file name" plain raster file to print
437 * c -- "file name" cifplot file to print
438 * 1 -- "R font file" for troff
439 * 2 -- "I font file" for troff
440 * 3 -- "B font file" for troff
441 * 4 -- "S font file" for troff
442 * N -- "name" of file (used by lpq)
443 * U -- "unlink" name of file to remove
444 * (after we print it. (Pass 2 only)).
445 * M -- "mail" to user when done printing
446 * Z -- "locale" for pr
447 *
448 * getline reads a line and expands tabs to blanks
449 */
450
451 /* pass 1 */
452
453 while (getline(cfp))
454 switch (line[0]) {
455 case 'H':
456 strlcpy(origin_host, line + 1, sizeof(origin_host));
457 if (class[0] == '\0') {
458 strlcpy(class, line+1, sizeof(class));
459 }
460 continue;
461
462 case 'P':
463 strlcpy(logname, line + 1, sizeof(logname));
464 if (pp->restricted) { /* restricted */
465 if (getpwnam(logname) == NULL) {
466 bombed = NOACCT;
467 sendmail(pp, line+1, bombed);
468 goto pass2;
469 }
470 }
471 continue;
472
473 case 'S':
474 cp = line+1;
475 i = 0;
476 while (*cp >= '0' && *cp <= '9')
477 i = i * 10 + (*cp++ - '0');
478 fdev = i;
479 cp++;
480 i = 0;
481 while (*cp >= '0' && *cp <= '9')
482 i = i * 10 + (*cp++ - '0');
483 fino = i;
484 continue;
485
486 case 'J':
487 if (line[1] != '\0') {
488 strlcpy(jobname, line + 1, sizeof(jobname));
489 } else
490 strcpy(jobname, " ");
491 continue;
492
493 case 'C':
494 if (line[1] != '\0')
495 strlcpy(class, line + 1, sizeof(class));
496 else if (class[0] == '\0') {
497 /* XXX - why call gethostname instead of
498 * just strlcpy'ing local_host? */
499 gethostname(class, sizeof(class));
500 class[sizeof(class) - 1] = '\0';
501 }
502 continue;
503
504 case 'T': /* header title for pr */
505 strlcpy(title, line + 1, sizeof(title));
506 continue;
507
508 case 'L': /* identification line */
509 if (!pp->no_header && !pp->header_last)
510 banner(pp, line+1, jobname);
511 continue;
512
513 case '1': /* troff fonts */
514 case '2':
515 case '3':
516 case '4':
517 if (line[1] != '\0') {
518 strlcpy(fonts[line[0]-'1'], line + 1,
519 (size_t)50);
520 }
521 continue;
522
523 case 'W': /* page width */
524 strlcpy(width+2, line + 1, sizeof(width) - 2);
525 continue;
526
527 case 'I': /* indent amount */
528 strlcpy(indent+2, line + 1, sizeof(indent) - 2);
529 continue;
530
531 case 'Z': /* locale for pr */
532 strlcpy(locale, line + 1, sizeof(locale));
533 continue;
534
535 default: /* some file to print */
536 /* only lowercase cmd-codes include a file-to-print */
537 if ((line[0] < 'a') || (line[0] > 'z')) {
538 /* ignore any other lines */
539 if (lflag <= 1)
540 continue;
541 if (!didignorehdr) {
542 syslog(LOG_INFO, "%s: in %s :",
543 pp->printer, file);
544 didignorehdr = 1;
545 }
546 syslog(LOG_INFO, "%s: ignoring line: '%c' %s",
547 pp->printer, line[0], &line[1]);
548 continue;
549 }
550 i = print(pp, line[0], line+1);
551 switch (i) {
552 case ERROR:
553 if (bombed == OK)
554 bombed = FATALERR;
555 break;
556 case REPRINT:
557 (void) fclose(cfp);
558 return (REPRINT);
559 case FILTERERR:
560 case ACCESS:
561 bombed = i;
562 sendmail(pp, logname, bombed);
563 }
564 title[0] = '\0';
565 continue;
566
567 case 'N':
568 case 'U':
569 case 'M':
570 case 'R':
571 continue;
572 }
573
574 /* pass 2 */
575
576pass2:
577 fseek(cfp, 0L, 0);
578 while (getline(cfp))
579 switch (line[0]) {
580 case 'L': /* identification line */
581 if (!pp->no_header && pp->header_last)
582 banner(pp, line+1, jobname);
583 continue;
584
585 case 'M':
586 if (bombed < NOACCT) /* already sent if >= NOACCT */
587 sendmail(pp, line+1, bombed);
588 continue;
589
590 case 'U':
591 if (strchr(line+1, '/'))
592 continue;
593 (void) unlink(line+1);
594 }
595 /*
596 * clean-up in case another control file exists
597 */
598 (void) fclose(cfp);
599 (void) unlink(file);
600 return (bombed == OK ? OK : ERROR);
601}
602
603/*
604 * Print a file.
605 * Set up the chain [ PR [ | {IF, OF} ] ] or {IF, RF, TF, NF, DF, CF, VF}.
606 * Return -1 if a non-recoverable error occured,
607 * 2 if the filter detected some errors (but printed the job anyway),
608 * 1 if we should try to reprint this job and
609 * 0 if all is well.
610 * Note: all filters take stdin as the file, stdout as the printer,
611 * stderr as the log file, and must not ignore SIGINT.
612 */
613static int
614print(struct printer *pp, int format, char *file)
615{
616 register int n, i;
617 register char *prog;
618 int fi, fo;
619 FILE *fp;
620 char *av[15], buf[SPL_BUFSIZ];
621 pid_t wpid;
622 int p[2], retcode, stopped, wstatus, wstatus_set;
623 struct stat stb;
624
625 /* Make sure the entire data file has arrived. */
626 wait4data(pp, file);
627
628 if (lstat(file, &stb) < 0 || (fi = open(file, O_RDONLY)) < 0) {
629 syslog(LOG_INFO, "%s: unable to open %s ('%c' line)",
630 pp->printer, file, format);
631 return (ERROR);
632 }
633 /*
634 * Check to see if data file is a symbolic link. If so, it should
635 * still point to the same file or someone is trying to print
636 * something he shouldn't.
637 */
638 if ((stb.st_mode & S_IFMT) == S_IFLNK && fstat(fi, &stb) == 0 &&
639 (stb.st_dev != fdev || stb.st_ino != fino))
640 return (ACCESS);
641
642 job_dfcnt++; /* increment datafile counter for this job */
643 stopped = 0; /* output filter is not stopped */
644
645 /* everything seems OK, start it up */
646 if (!pp->no_formfeed && !pp->tof) { /* start on a fresh page */
647 (void) write(ofd, pp->form_feed, strlen(pp->form_feed));
648 pp->tof = 1;
649 }
650 if (pp->filters[LPF_INPUT] == NULL
651 && (format == 'f' || format == 'l' || format == 'o')) {
652 pp->tof = 0;
653 while ((n = read(fi, buf, SPL_BUFSIZ)) > 0)
654 if (write(ofd, buf, n) != n) {
655 (void) close(fi);
656 return (REPRINT);
657 }
658 (void) close(fi);
659 return (OK);
660 }
661 switch (format) {
662 case 'p': /* print file using 'pr' */
663 if (pp->filters[LPF_INPUT] == NULL) { /* use output filter */
664 prog = _PATH_PR;
665 i = 0;
666 av[i++] = "pr";
667 av[i++] = width;
668 av[i++] = length;
669 av[i++] = "-h";
670 av[i++] = *title ? title : " ";
671 av[i++] = "-L";
672 av[i++] = *locale ? locale : "C";
673 av[i++] = "-F";
674 av[i] = 0;
675 fo = ofd;
676 goto start;
677 }
678 pipe(p);
679 if ((prchild = dofork(pp, DORETURN)) == 0) { /* child */
680 dup2(fi, STDIN_FILENO); /* file is stdin */
681 dup2(p[1], STDOUT_FILENO); /* pipe is stdout */
682 closelog();
683 closeallfds(3);
684 execl(_PATH_PR, "pr", width, length,
685 "-h", *title ? title : " ",
686 "-L", *locale ? locale : "C",
687 "-F", (char *)0);
688 syslog(LOG_ERR, "cannot execl %s", _PATH_PR);
689 exit(2);
690 }
691 (void) close(p[1]); /* close output side */
692 (void) close(fi);
693 if (prchild < 0) {
694 prchild = 0;
695 (void) close(p[0]);
696 return (ERROR);
697 }
698 fi = p[0]; /* use pipe for input */
699 case 'f': /* print plain text file */
700 prog = pp->filters[LPF_INPUT];
701 av[1] = width;
702 av[2] = length;
703 av[3] = indent;
704 n = 4;
705 break;
706 case 'o': /* print postscript file */
707 /*
708 * Treat this as a "plain file with control characters", and
709 * assume the standard LPF_INPUT filter will recognize that
710 * the data is postscript and know what to do with it. These
711 * 'o'-file requests could come from MacOS 10.1 systems.
712 * (later versions of MacOS 10 will explicitly use 'l')
713 * A postscript file can contain binary data, which is why 'l'
714 * is somewhat more appropriate than 'f'.
715 */
716 /* FALLTHROUGH */
717 case 'l': /* like 'f' but pass control characters */
718 prog = pp->filters[LPF_INPUT];
719 av[1] = "-c";
720 av[2] = width;
721 av[3] = length;
722 av[4] = indent;
723 n = 5;
724 break;
725 case 'r': /* print a fortran text file */
726 prog = pp->filters[LPF_FORTRAN];
727 av[1] = width;
728 av[2] = length;
729 n = 3;
730 break;
731 case 't': /* print troff output */
732 case 'n': /* print ditroff output */
733 case 'd': /* print tex output */
734 (void) unlink(".railmag");
735 if ((fo = creat(".railmag", FILMOD)) < 0) {
736 syslog(LOG_ERR, "%s: cannot create .railmag",
737 pp->printer);
738 (void) unlink(".railmag");
739 } else {
740 for (n = 0; n < 4; n++) {
741 if (fonts[n][0] != '/')
742 (void) write(fo, _PATH_VFONT,
743 sizeof(_PATH_VFONT) - 1);
744 (void) write(fo, fonts[n], strlen(fonts[n]));
745 (void) write(fo, "\n", 1);
746 }
747 (void) close(fo);
748 }
749 prog = (format == 't') ? pp->filters[LPF_TROFF]
750 : ((format == 'n') ? pp->filters[LPF_DITROFF]
751 : pp->filters[LPF_DVI]);
752 av[1] = pxwidth;
753 av[2] = pxlength;
754 n = 3;
755 break;
756 case 'c': /* print cifplot output */
757 prog = pp->filters[LPF_CIFPLOT];
758 av[1] = pxwidth;
759 av[2] = pxlength;
760 n = 3;
761 break;
762 case 'g': /* print plot(1G) output */
763 prog = pp->filters[LPF_GRAPH];
764 av[1] = pxwidth;
765 av[2] = pxlength;
766 n = 3;
767 break;
768 case 'v': /* print raster output */
769 prog = pp->filters[LPF_RASTER];
770 av[1] = pxwidth;
771 av[2] = pxlength;
772 n = 3;
773 break;
774 default:
775 (void) close(fi);
776 syslog(LOG_ERR, "%s: illegal format character '%c'",
777 pp->printer, format);
778 return (ERROR);
779 }
780 if (prog == NULL) {
781 (void) close(fi);
782 syslog(LOG_ERR,
783 "%s: no filter found in printcap for format character '%c'",
784 pp->printer, format);
785 return (ERROR);
786 }
787 if ((av[0] = strrchr(prog, '/')) != NULL)
788 av[0]++;
789 else
790 av[0] = prog;
791 av[n++] = "-n";
792 av[n++] = logname;
793 av[n++] = "-h";
794 av[n++] = origin_host;
795 av[n++] = pp->acct_file;
796 av[n] = 0;
797 fo = pfd;
798 if (of_pid > 0) { /* stop output filter */
799 write(ofd, "\031\1", 2);
800 while ((wpid =
801 wait3(&wstatus, WUNTRACED, 0)) > 0 && wpid != of_pid)
802 ;
803 if (wpid < 0)
804 syslog(LOG_WARNING,
805 "%s: after stopping 'of', wait3() returned: %m",
806 pp->printer);
807 else if (!WIFSTOPPED(wstatus)) {
808 (void) close(fi);
809 syslog(LOG_WARNING, "%s: output filter died "
810 "(pid=%d retcode=%d termsig=%d)",
811 pp->printer, of_pid, WEXITSTATUS(wstatus),
812 WTERMSIG(wstatus));
813 return (REPRINT);
814 }
815 stopped++;
816 }
817start:
818 if ((child = dofork(pp, DORETURN)) == 0) { /* child */
819 dup2(fi, STDIN_FILENO);
820 dup2(fo, STDOUT_FILENO);
821 /* setup stderr for the filter (child process)
822 * so it goes to our temporary errors file */
823 n = open(tempstderr, O_WRONLY|O_TRUNC, 0664);
824 if (n >= 0)
825 dup2(n, STDERR_FILENO);
826 closelog();
827 closeallfds(3);
828 execv(prog, av);
829 syslog(LOG_ERR, "%s: cannot execv(%s): %m", pp->printer,
830 prog);
831 exit(2);
832 }
833 (void) close(fi);
834 wstatus_set = 0;
835 if (child < 0)
836 retcode = 100;
837 else {
838 while ((wpid = wait(&wstatus)) > 0 && wpid != child)
839 ;
840 if (wpid < 0) {
841 retcode = 100;
842 syslog(LOG_WARNING,
843 "%s: after execv(%s), wait() returned: %m",
844 pp->printer, prog);
845 } else {
846 wstatus_set = 1;
847 retcode = WEXITSTATUS(wstatus);
848 }
849 }
850 child = 0;
851 prchild = 0;
852 if (stopped) { /* restart output filter */
853 if (kill(of_pid, SIGCONT) < 0) {
854 syslog(LOG_ERR, "cannot restart output filter");
855 exit(1);
856 }
857 }
858 pp->tof = 0;
859
860 /* Copy the filter's output to "lf" logfile */
861 if ((fp = fopen(tempstderr, "r"))) {
862 while (fgets(buf, sizeof(buf), fp))
863 fputs(buf, stderr);
864 fclose(fp);
865 }
866
867 if (wstatus_set && !WIFEXITED(wstatus)) {
868 syslog(LOG_WARNING, "%s: filter '%c' terminated (termsig=%d)",
869 pp->printer, format, WTERMSIG(wstatus));
870 return (ERROR);
871 }
872 switch (retcode) {
873 case 0:
874 pp->tof = 1;
875 return (OK);
876 case 1:
877 return (REPRINT);
878 case 2:
879 return (ERROR);
880 default:
881 syslog(LOG_WARNING, "%s: filter '%c' exited (retcode=%d)",
882 pp->printer, format, retcode);
883 return (FILTERERR);
884 }
885}
886
887/*
888 * Send the daemon control file (cf) and any data files.
889 * Return -1 if a non-recoverable error occured, 1 if a recoverable error and
890 * 0 if all is well.
891 */
892static int
893sendit(struct printer *pp, char *file)
894{
895 int dfcopies, err, i;
896 char *cp, last[sizeof(line)];
897
898 /*
899 * open control file
900 */
901 if ((cfp = fopen(file, "r")) == NULL)
902 return (OK);
903
904 /* initialize job-specific count of datafiles processed */
905 job_dfcnt = 0;
906
907 /*
908 * read the control file for work to do
909 *
910 * file format -- first character in the line is a command
911 * rest of the line is the argument.
912 * commands of interest are:
913 *
914 * a-z -- "file name" name of file to print
915 * U -- "unlink" name of file to remove
916 * (after we print it. (Pass 2 only)).
917 */
918
919 /*
920 * pass 1
921 */
922 err = OK;
923 while (getline(cfp)) {
924 again:
925 if (line[0] == 'S') {
926 cp = line+1;
927 i = 0;
928 while (*cp >= '0' && *cp <= '9')
929 i = i * 10 + (*cp++ - '0');
930 fdev = i;
931 cp++;
932 i = 0;
933 while (*cp >= '0' && *cp <= '9')
934 i = i * 10 + (*cp++ - '0');
935 fino = i;
936 } else if (line[0] == 'H') {
937 strlcpy(origin_host, line + 1, sizeof(origin_host));
938 if (class[0] == '\0') {
939 strlcpy(class, line + 1, sizeof(class));
940 }
941 } else if (line[0] == 'P') {
942 strlcpy(logname, line + 1, sizeof(logname));
943 if (pp->restricted) { /* restricted */
944 if (getpwnam(logname) == NULL) {
945 sendmail(pp, line+1, NOACCT);
946 err = ERROR;
947 break;
948 }
949 }
950 } else if (line[0] == 'I') {
951 strlcpy(indent+2, line + 1, sizeof(indent) - 2);
952 } else if (line[0] >= 'a' && line[0] <= 'z') {
953 dfcopies = 1;
954 strcpy(last, line);
955 while ((i = getline(cfp)) != 0) {
956 if (strcmp(last, line) != 0)
957 break;
958 dfcopies++;
959 }
960 switch (sendfile(pp, '\3', last+1, *last, dfcopies)) {
961 case OK:
962 if (i)
963 goto again;
964 break;
965 case REPRINT:
966 (void) fclose(cfp);
967 return (REPRINT);
968 case ACCESS:
969 sendmail(pp, logname, ACCESS);
970 case ERROR:
971 err = ERROR;
972 }
973 break;
974 }
975 }
976 if (err == OK && sendfile(pp, '\2', file, '\0', 1) > 0) {
977 (void) fclose(cfp);
978 return (REPRINT);
979 }
980 /*
981 * pass 2
982 */
983 fseek(cfp, 0L, 0);
984 while (getline(cfp))
985 if (line[0] == 'U' && !strchr(line+1, '/'))
986 (void) unlink(line+1);
987 /*
988 * clean-up in case another control file exists
989 */
990 (void) fclose(cfp);
991 (void) unlink(file);
992 return (err);
993}
994
995/*
996 * Send a data file to the remote machine and spool it.
997 * Return positive if we should try resending.
998 */
999static int
1000sendfile(struct printer *pp, int type, char *file, char format, int copyreq)
1001{
1002 int i, amt;
1003 struct stat stb;
1004 char *av[15], *filtcmd;
1005 char buf[SPL_BUFSIZ], opt_c[4], opt_h[4], opt_n[4];
1006 int copycnt, filtstat, narg, resp, sfd, sfres, sizerr, statrc;
1007
1008 /* Make sure the entire data file has arrived. */
1009 wait4data(pp, file);
1010
1011 statrc = lstat(file, &stb);
1012 if (statrc < 0) {
1013 syslog(LOG_ERR, "%s: error from lstat(%s): %m",
1014 pp->printer, file);
1015 return (ERROR);
1016 }
1017 sfd = open(file, O_RDONLY);
1018 if (sfd < 0) {
1019 syslog(LOG_ERR, "%s: error from open(%s,O_RDONLY): %m",
1020 pp->printer, file);
1021 return (ERROR);
1022 }
1023 /*
1024 * Check to see if data file is a symbolic link. If so, it should
1025 * still point to the same file or someone is trying to print something
1026 * he shouldn't.
1027 */
1028 if ((stb.st_mode & S_IFMT) == S_IFLNK && fstat(sfd, &stb) == 0 &&
1029 (stb.st_dev != fdev || stb.st_ino != fino)) {
1030 close(sfd);
1031 return (ACCESS);
1032 }
1033
1034 /* Everything seems OK for reading the file, now to send it */
1035 filtcmd = NULL;
1036 sizerr = 0;
1037 tfd = -1;
1038 if (type == '\3') {
1039 /*
1040 * Type == 3 means this is a datafile, not a control file.
1041 * Increment the counter of data-files in this job, and
1042 * then check for input or output filters (which are only
1043 * applied to datafiles, not control files).
1044 */
1045 job_dfcnt++;
1046
1047 /*
1048 * Note that here we are filtering datafiles, one at a time,
1049 * as they are sent to the remote machine. Here, the *only*
1050 * difference between an input filter (`if=') and an output
1051 * filter (`of=') is the argument list that the filter is
1052 * started up with. Here, the output filter is executed
1053 * for each individual file as it is sent. This is not the
1054 * same as local print queues, where the output filter is
1055 * started up once, and then all jobs are passed thru that
1056 * single invocation of the output filter.
1057 *
1058 * Also note that a queue for a remote-machine can have an
1059 * input filter or an output filter, but not both.
1060 */
1061 if (pp->filters[LPF_INPUT]) {
1062 filtcmd = pp->filters[LPF_INPUT];
1063 av[0] = filtcmd;
1064 narg = 0;
1065 strcpy(opt_c, "-c");
1066 strcpy(opt_h, "-h");
1067 strcpy(opt_n, "-n");
1068 if (format == 'l')
1069 av[++narg] = opt_c;
1070 av[++narg] = width;
1071 av[++narg] = length;
1072 av[++narg] = indent;
1073 av[++narg] = opt_n;
1074 av[++narg] = logname;
1075 av[++narg] = opt_h;
1076 av[++narg] = origin_host;
1077 av[++narg] = pp->acct_file;
1078 av[++narg] = NULL;
1079 } else if (pp->filters[LPF_OUTPUT]) {
1080 filtcmd = pp->filters[LPF_OUTPUT];
1081 av[0] = filtcmd;
1082 narg = 0;
1083 av[++narg] = width;
1084 av[++narg] = length;
1085 av[++narg] = NULL;
1086 }
1087 }
1088 if (filtcmd) {
1089 /*
1090 * If there is an input or output filter, we have to run
1091 * the datafile thru that filter and store the result as
1092 * a temporary spool file, because the protocol requires
1093 * that we send the remote host the file-size before we
1094 * start to send any of the data.
1095 */
1096 strcpy(tfile, TFILENAME);
1097 tfd = mkstemp(tfile);
1098 if (tfd == -1) {
1099 syslog(LOG_ERR, "%s: mkstemp(%s): %m", pp->printer,
1100 TFILENAME);
1101 sfres = ERROR;
1102 goto return_sfres;
1103 }
1104 filtstat = execfilter(pp, filtcmd, av, sfd, tfd);
1105
1106 /* process the return-code from the filter */
1107 switch (filtstat) {
1108 case 0:
1109 break;
1110 case 1:
1111 sfres = REPRINT;
1112 goto return_sfres;
1113 case 2:
1114 sfres = ERROR;
1115 goto return_sfres;
1116 default:
1117 syslog(LOG_WARNING,
1118 "%s: filter '%c' exited (retcode=%d)",
1119 pp->printer, format, filtstat);
1120 sfres = FILTERERR;
1121 goto return_sfres;
1122 }
1123 statrc = fstat(tfd, &stb); /* to find size of tfile */
1124 if (statrc < 0) {
1125 syslog(LOG_ERR,
1126 "%s: error processing 'if', fstat(%s): %m",
1127 pp->printer, tfile);
1128 sfres = ERROR;
1129 goto return_sfres;
1130 }
1131 close(sfd);
1132 sfd = tfd;
1133 lseek(sfd, 0, SEEK_SET);
1134 }
1135
1136 copycnt = 0;
1137sendagain:
1138 copycnt++;
1139
1140 if (copycnt < 2)
1141 (void) sprintf(buf, "%c%qd %s\n", type, stb.st_size, file);
1142 else
1143 (void) sprintf(buf, "%c%qd %s_c%d\n", type, stb.st_size,
1144 file, copycnt);
1145 amt = strlen(buf);
1146 for (i = 0; ; i++) {
1147 if (write(pfd, buf, amt) != amt ||
1148 (resp = response(pp)) < 0 || resp == '\1') {
1149 sfres = REPRINT;
1150 goto return_sfres;
1151 } else if (resp == '\0')
1152 break;
1153 if (i == 0)
1154 pstatus(pp,
1155 "no space on remote; waiting for queue to drain");
1156 if (i == 10)
1157 syslog(LOG_ALERT, "%s: can't send to %s; queue full",
1158 pp->printer, pp->remote_host);
1159 sleep(5 * 60);
1160 }
1161 if (i)
1162 pstatus(pp, "sending to %s", pp->remote_host);
1163 /*
1164 * XXX - we should change trstat_init()/trstat_write() to include
1165 * the copycnt in the statistics record it may write.
1166 */
1167 if (type == '\3')
1168 trstat_init(pp, file, job_dfcnt);
1169 for (i = 0; i < stb.st_size; i += SPL_BUFSIZ) {
1170 amt = SPL_BUFSIZ;
1171 if (i + amt > stb.st_size)
1172 amt = stb.st_size - i;
1173 if (sizerr == 0 && read(sfd, buf, amt) != amt)
1174 sizerr = 1;
1175 if (write(pfd, buf, amt) != amt) {
1176 sfres = REPRINT;
1177 goto return_sfres;
1178 }
1179 }
1180
1181 if (sizerr) {
1182 syslog(LOG_INFO, "%s: %s: changed size", pp->printer, file);
1183 /* tell recvjob to ignore this file */
1184 (void) write(pfd, "\1", 1);
1185 sfres = ERROR;
1186 goto return_sfres;
1187 }
1188 if (write(pfd, "", 1) != 1 || response(pp)) {
1189 sfres = REPRINT;
1190 goto return_sfres;
1191 }
1192 if (type == '\3') {
1193 trstat_write(pp, TR_SENDING, stb.st_size, logname,
1194 pp->remote_host, origin_host);
1195 /*
1196 * Usually we only need to send one copy of a datafile,
1197 * because the control-file will simply print the same
1198 * file multiple times. However, some printers ignore
1199 * the control file, and simply print each data file as
1200 * it arrives. For such "remote hosts", we need to
1201 * transfer the same data file multiple times. Such a
1202 * a host is indicated by adding 'rc' to the printcap
1203 * entry.
1204 * XXX - Right now this ONLY works for remote hosts which
1205 * do ignore the name of the data file, because
1206 * this sends the file multiple times with slight
1207 * changes to the filename. To do this right would
1208 * require that we also rewrite the control file
1209 * to match those filenames.
1210 */
1211 if (pp->resend_copies && (copycnt < copyreq)) {
1212 lseek(sfd, 0, SEEK_SET);
1213 goto sendagain;
1214 }
1215 }
1216 sfres = OK;
1217
1218return_sfres:
1219 (void)close(sfd);
1220 if (tfd != -1) {
1221 /*
1222 * If tfd is set, then it is the same value as sfd, and
1223 * therefore it is already closed at this point. All
1224 * we need to do is remove the temporary file.
1225 */
1226 tfd = -1;
1227 unlink(tfile);
1228 }
1229 return (sfres);
1230}
1231
1232/*
1233 * Some print servers send the control-file first, and then start sending the
1234 * matching data file(s). That is not the correct order. If some queue is
1235 * already printing an active job, then when that job is finished the queue
1236 * may proceed to the control file of any incoming print job. This turns
1237 * into a race between the process which is receiving the data file, and the
1238 * process which is actively printing the very same file. When the remote
1239 * server sends files in the wrong order, it is even possible that a queue
1240 * will start to print a data file before the file has been created!
1241 *
1242 * So before we start to print() or send() a data file, we call this routine
1243 * to make sure the data file is not still changing in size. Note that this
1244 * problem will only happen for jobs arriving from a remote host, and that
1245 * the process which has decided to print this job (and is thus making this
1246 * check) is *not* the process which is receiving the job.
1247 *
1248 * A second benefit of this is that any incoming job is guaranteed to appear
1249 * in a queue listing for at least a few seconds after it has arrived. Some
1250 * lpr implementations get confused if they send a job and it disappears
1251 * from the queue before they can check on it.
1252 */
1253#define MAXWAIT_ARRIVE 16 /* max to wait for the file to *exist* */
1254#define MAXWAIT_4DATA (20*60) /* max to wait for it to stop changing */
1255#define MINWAIT_4DATA 4 /* This value must be >= 1 */
1256#define DEBUG_MINWAIT 1
1257static void
1258wait4data(struct printer *pp, const char *dfile)
1259{
1260 const char *cp;
1261 int statres;
1262 u_int sleepreq;
1263 size_t dlen, hlen;
1264 time_t amtslept, cur_time, prev_mtime;
1265 struct stat statdf;
1266
1267 /* Skip these checks if the print job is from the local host. */
1268 dlen = strlen(dfile);
1269 hlen = strlen(local_host);
1270 if (dlen > hlen) {
1271 cp = dfile + dlen - hlen;
1272 if (strcmp(cp, local_host) == 0)
1273 return;
1274 }
1275
1276 /*
1277 * If this data file does not exist, then wait up to MAXWAIT_ARRIVE
1278 * seconds for it to arrive.
1279 */
1280 amtslept = 0;
1281 statres = stat(dfile, &statdf);
1282 while (statres < 0 && amtslept < MAXWAIT_ARRIVE) {
1283 if (amtslept == 0)
1284 pstatus(pp, "Waiting for data file from remote host");
1285 amtslept += MINWAIT_4DATA - sleep(MINWAIT_4DATA);
1286 statres = stat(dfile, &statdf);
1287 }
1288 if (statres < 0) {
1289 /* The file still does not exist, so just give up on it. */
1290 syslog(LOG_WARNING, "%s: wait4data() abandoned wait for %s",
1291 pp->printer, dfile);
1292 return;
1293 }
1294
1295 /*
1296 * The file exists, so keep waiting until the data file has not
1297 * changed for some reasonable amount of time. Extra care is
1298 * taken when computing wait-times, just in case there are data
1299 * files with a last-modify time in the future. While that is
1300 * very unlikely to happen, it can happen when the system has
1301 * a flakey time-of-day clock.
1302 */
1303 prev_mtime = statdf.st_mtime;
1304 cur_time = time(NULL);
1305 if (statdf.st_mtime >= cur_time - MINWAIT_4DATA) {
1306 if (statdf.st_mtime >= cur_time) /* some TOD oddity */
1307 sleepreq = MINWAIT_4DATA;
1308 else
1309 sleepreq = cur_time - statdf.st_mtime;
1310 if (amtslept == 0)
1311 pstatus(pp, "Waiting for data file from remote host");
1312 amtslept += sleepreq - sleep(sleepreq);
1313 statres = stat(dfile, &statdf);
1314 }
1315 sleepreq = MINWAIT_4DATA;
1316 while (statres == 0 && amtslept < MAXWAIT_4DATA) {
1317 if (statdf.st_mtime == prev_mtime)
1318 break;
1319 prev_mtime = statdf.st_mtime;
1320 amtslept += sleepreq - sleep(sleepreq);
1321 statres = stat(dfile, &statdf);
1322 }
1323
1324 if (statres != 0)
1325 syslog(LOG_WARNING, "%s: %s disappeared during wait4data()",
1326 pp->printer, dfile);
1327 else if (amtslept > MAXWAIT_4DATA)
1328 syslog(LOG_WARNING,
1329 "%s: %s still changing after %lu secs in wait4data()",
1330 pp->printer, dfile, (unsigned long)amtslept);
1331#if DEBUG_MINWAIT
1332 else if (amtslept > MINWAIT_4DATA)
1333 syslog(LOG_INFO, "%s: slept %lu secs in wait4data(%s)",
1334 pp->printer, (unsigned long)amtslept, dfile);
1335#endif
1336}
1337#undef MAXWAIT_ARRIVE
1338#undef MAXWAIT_4DATA
1339#undef MINWAIT_4DATA
1340
1341/*
1342 * This routine is called to execute one of the filters as was
1343 * specified in a printcap entry. While the child-process will read
1344 * all of 'infd', it is up to the caller to close that file descriptor
1345 * in the parent process.
1346 */
1347static int
1348execfilter(struct printer *pp, char *f_cmd, char *f_av[], int infd, int outfd)
1349{
1350 pid_t fpid, wpid;
1351 int errfd, retcode, wstatus;
1352 FILE *errfp;
1353 char buf[BUFSIZ], *slash;
1354
1355 fpid = dofork(pp, DORETURN);
1356 if (fpid != 0) {
1357 /*
1358 * This is the parent process, which just waits for the child
1359 * to complete and then returns the result. Note that it is
1360 * the child process which reads the input stream.
1361 */
1362 if (fpid < 0)
1363 retcode = 100;
1364 else {
1365 while ((wpid = wait(&wstatus)) > 0 &&
1366 wpid != fpid)
1367 ;
1368 if (wpid < 0) {
1369 retcode = 100;
1370 syslog(LOG_WARNING,
1371 "%s: after execv(%s), wait() returned: %m",
1372 pp->printer, f_cmd);
1373 } else
1374 retcode = WEXITSTATUS(wstatus);
1375 }
1376
1377 /*
1378 * Copy everything the filter wrote to stderr from our
1379 * temporary errors file to the "lf=" logfile.
1380 */
1381 errfp = fopen(tempstderr, "r");
1382 if (errfp) {
1383 while (fgets(buf, sizeof(buf), errfp))
1384 fputs(buf, stderr);
1385 fclose(errfp);
1386 }
1387
1388 return (retcode);
1389 }
1390
1391 /*
1392 * This is the child process, which is the one that executes the
1393 * given filter.
1394 */
1395 /*
1396 * If the first parameter has any slashes in it, then change it
1397 * to point to the first character after the last slash.
1398 */
1399 slash = strrchr(f_av[0], '/');
1400 if (slash != NULL)
1401 f_av[0] = slash + 1;
1402 /*
1403 * XXX - in the future, this should setup an explicit list of
1404 * environment variables and use execve()!
1405 */
1406
1407 /*
1408 * Setup stdin, stdout, and stderr as we want them when the filter
1409 * is running. Stderr is setup so it points to a temporary errors
1410 * file, and the parent process will copy that temporary file to
1411 * the real logfile after the filter completes.
1412 */
1413 dup2(infd, STDIN_FILENO);
1414 dup2(outfd, STDOUT_FILENO);
1415 errfd = open(tempstderr, O_WRONLY|O_TRUNC, 0664);
1416 if (errfd >= 0)
1417 dup2(errfd, STDERR_FILENO);
1418 closelog();
1419 closeallfds(3);
1420 execv(f_cmd, f_av);
1421 syslog(LOG_ERR, "%s: cannot execv(%s): %m", pp->printer, f_cmd);
1422 exit(2);
1423 /* NOTREACHED */
1424}
1425
1426/*
1427 * Check to make sure there have been no errors and that both programs
1428 * are in sync with eachother.
1429 * Return non-zero if the connection was lost.
1430 */
1431static char
1432response(const struct printer *pp)
1433{
1434 char resp;
1435
1436 if (read(pfd, &resp, 1) != 1) {
1437 syslog(LOG_INFO, "%s: lost connection", pp->printer);
1438 return (-1);
1439 }
1440 return (resp);
1441}
1442
1443/*
1444 * Banner printing stuff
1445 */
1446static void
1447banner(struct printer *pp, char *name1, char *name2)
1448{
1449 time_t tvec;
1450
1451 time(&tvec);
1452 if (!pp->no_formfeed && !pp->tof)
1453 (void) write(ofd, pp->form_feed, strlen(pp->form_feed));
1454 if (pp->short_banner) { /* short banner only */
1455 if (class[0]) {
1456 (void) write(ofd, class, strlen(class));
1457 (void) write(ofd, ":", 1);
1458 }
1459 (void) write(ofd, name1, strlen(name1));
1460 (void) write(ofd, " Job: ", 7);
1461 (void) write(ofd, name2, strlen(name2));
1462 (void) write(ofd, " Date: ", 8);
1463 (void) write(ofd, ctime(&tvec), 24);
1464 (void) write(ofd, "\n", 1);
1465 } else { /* normal banner */
1466 (void) write(ofd, "\n\n\n", 3);
1467 scan_out(pp, ofd, name1, '\0');
1468 (void) write(ofd, "\n\n", 2);
1469 scan_out(pp, ofd, name2, '\0');
1470 if (class[0]) {
1471 (void) write(ofd,"\n\n\n",3);
1472 scan_out(pp, ofd, class, '\0');
1473 }
1474 (void) write(ofd, "\n\n\n\n\t\t\t\t\tJob: ", 15);
1475 (void) write(ofd, name2, strlen(name2));
1476 (void) write(ofd, "\n\t\t\t\t\tDate: ", 12);
1477 (void) write(ofd, ctime(&tvec), 24);
1478 (void) write(ofd, "\n", 1);
1479 }
1480 if (!pp->no_formfeed)
1481 (void) write(ofd, pp->form_feed, strlen(pp->form_feed));
1482 pp->tof = 1;
1483}
1484
1485static char *
1486scnline(int key, char *p, int c)
1487{
1488 register int scnwidth;
1489
1490 for (scnwidth = WIDTH; --scnwidth;) {
1491 key <<= 1;
1492 *p++ = key & 0200 ? c : BACKGND;
1493 }
1494 return (p);
1495}
1496
1497#define TRC(q) (((q)-' ')&0177)
1498
1499static void
1500scan_out(struct printer *pp, int scfd, char *scsp, int dlm)
1501{
1502 register char *strp;
1503 register int nchrs, j;
1504 char outbuf[LINELEN+1], *sp, c, cc;
1505 int d, scnhgt;
1506
1507 for (scnhgt = 0; scnhgt++ < HEIGHT+DROP; ) {
1508 strp = &outbuf[0];
1509 sp = scsp;
1510 for (nchrs = 0; ; ) {
1511 d = dropit(c = TRC(cc = *sp++));
1512 if ((!d && scnhgt > HEIGHT) || (scnhgt <= DROP && d))
1513 for (j = WIDTH; --j;)
1514 *strp++ = BACKGND;
1515 else
1516 strp = scnline(scnkey[(int)c][scnhgt-1-d], strp, cc);
1517 if (*sp == dlm || *sp == '\0' ||
1518 nchrs++ >= pp->page_width/(WIDTH+1)-1)
1519 break;
1520 *strp++ = BACKGND;
1521 *strp++ = BACKGND;
1522 }
1523 while (*--strp == BACKGND && strp >= outbuf)
1524 ;
1525 strp++;
1526 *strp++ = '\n';
1527 (void) write(scfd, outbuf, strp-outbuf);
1528 }
1529}
1530
1531static int
1532dropit(int c)
1533{
1534 switch(c) {
1535
1536 case TRC('_'):
1537 case TRC(';'):
1538 case TRC(','):
1539 case TRC('g'):
1540 case TRC('j'):
1541 case TRC('p'):
1542 case TRC('q'):
1543 case TRC('y'):
1544 return (DROP);
1545
1546 default:
1547 return (0);
1548 }
1549}
1550
1551/*
1552 * sendmail ---
1553 * tell people about job completion
1554 */
1555static void
1556sendmail(struct printer *pp, char *userid, int bombed)
1557{
1558 register int i;
1559 int p[2], s;
1560 register const char *cp;
1561 struct stat stb;
1562 FILE *fp;
1563
1564 pipe(p);
1565 if ((s = dofork(pp, DORETURN)) == 0) { /* child */
1566 dup2(p[0], STDIN_FILENO);
1567 closelog();
1568 closeallfds(3);
1569 if ((cp = strrchr(_PATH_SENDMAIL, '/')) != NULL)
1570 cp++;
1571 else
1572 cp = _PATH_SENDMAIL;
1573 execl(_PATH_SENDMAIL, cp, "-t", (char *)0);
1574 _exit(0);
1575 } else if (s > 0) { /* parent */
1576 dup2(p[1], STDOUT_FILENO);
1577 printf("To: %s@%s\n", userid, origin_host);
1578 printf("Subject: %s printer job \"%s\"\n", pp->printer,
1579 *jobname ? jobname : "<unknown>");
1580 printf("Reply-To: root@%s\n\n", local_host);
1581 printf("Your printer job ");
1582 if (*jobname)
1583 printf("(%s) ", jobname);
1584
1585 switch (bombed) {
1586 case OK:
1587 cp = "OK";
1588 printf("\ncompleted successfully\n");
1589 break;
1590 default:
1591 case FATALERR:
1592 cp = "FATALERR";
1593 printf("\ncould not be printed\n");
1594 break;
1595 case NOACCT:
1596 cp = "NOACCT";
1597 printf("\ncould not be printed without an account on %s\n",
1598 local_host);
1599 break;
1600 case FILTERERR:
1601 cp = "FILTERERR";
1602 if (stat(tempstderr, &stb) < 0 || stb.st_size == 0
1603 || (fp = fopen(tempstderr, "r")) == NULL) {
1604 printf("\nhad some errors and may not have printed\n");
1605 break;
1606 }
1607 printf("\nhad the following errors and may not have printed:\n");
1608 while ((i = getc(fp)) != EOF)
1609 putchar(i);
1610 (void) fclose(fp);
1611 break;
1612 case ACCESS:
1613 cp = "ACCESS";
1614 printf("\nwas not printed because it was not linked to the original file\n");
1615 }
1616 fflush(stdout);
1617 (void) close(STDOUT_FILENO);
1618 } else {
1619 syslog(LOG_WARNING, "unable to send mail to %s: %m", userid);
1620 return;
1621 }
1622 (void) close(p[0]);
1623 (void) close(p[1]);
1624 wait(NULL);
1625 syslog(LOG_INFO, "mail sent to user %s about job %s on printer %s (%s)",
1626 userid, *jobname ? jobname : "<unknown>", pp->printer, cp);
1627}
1628
1629/*
1630 * dofork - fork with retries on failure
1631 */
1632static int
1633dofork(const struct printer *pp, int action)
1634{
1635 pid_t forkpid;
1636 int i, fail;
1637 struct passwd *pwd;
1638
1639 forkpid = -1;
1640 if (daemon_uname == NULL) {
1641 pwd = getpwuid(pp->daemon_user);
1642 if (pwd == NULL) {
1643 syslog(LOG_ERR, "%s: Can't lookup default daemon uid (%ld) in password file",
1644 pp->printer, pp->daemon_user);
1645 goto error_ret;
1646 }
1647 daemon_uname = strdup(pwd->pw_name);
1648 daemon_defgid = pwd->pw_gid;
1649 }
1650
1651 for (i = 0; i < 20; i++) {
1652 forkpid = fork();
1653 if (forkpid < 0) {
1654 sleep((unsigned)(i*i));
1655 continue;
1656 }
1657 /*
1658 * Child should run as daemon instead of root
1659 */
1660 if (forkpid == 0) {
1661 errno = 0;
1662 fail = initgroups(daemon_uname, daemon_defgid);
1663 if (fail) {
1664 syslog(LOG_ERR, "%s: initgroups(%s,%u): %m",
1665 pp->printer, daemon_uname, daemon_defgid);
1666 break;
1667 }
1668 fail = setgid(daemon_defgid);
1669 if (fail) {
1670 syslog(LOG_ERR, "%s: setgid(%u): %m",
1671 pp->printer, daemon_defgid);
1672 break;
1673 }
1674 fail = setuid(pp->daemon_user);
1675 if (fail) {
1676 syslog(LOG_ERR, "%s: setuid(%ld): %m",
1677 pp->printer, pp->daemon_user);
1678 break;
1679 }
1680 }
1681 return (forkpid);
1682 }
1683
1684 /*
1685 * An error occurred. If the error is in the child process, then
1686 * this routine MUST always exit(). DORETURN only effects how
1687 * errors should be handled in the parent process.
1688 */
1689error_ret:
1690 if (forkpid == 0) {
1691 syslog(LOG_ERR, "%s: dofork(): aborting child process...",
1692 pp->printer);
1693 exit(1);
1694 }
1695 syslog(LOG_ERR, "%s: dofork(): failure in fork", pp->printer);
1696
1697 sleep(1); /* throttle errors, as a safety measure */
1698 switch (action) {
1699 case DORETURN:
1700 return (-1);
1701 default:
1702 syslog(LOG_ERR, "bad action (%d) to dofork", action);
1703 /* FALLTHROUGH */
1704 case DOABORT:
1705 exit(1);
1706 }
1707 /*NOTREACHED*/
1708}
1709
1710/*
1711 * Kill child processes to abort current job.
1712 */
1713static void
1714abortpr(int signo __unused)
1715{
1716
1717 (void) unlink(tempstderr);
1718 kill(0, SIGINT);
1719 if (of_pid > 0)
1720 kill(of_pid, SIGCONT);
1721 while (wait(NULL) > 0)
1722 ;
1723 if (of_pid > 0 && tfd != -1)
1724 unlink(tfile);
1725 exit(0);
1726}
1727
1728static void
1729init(struct printer *pp)
1730{
1731 char *s;
1732
1733 sprintf(&width[2], "%ld", pp->page_width);
1734 sprintf(&length[2], "%ld", pp->page_length);
1735 sprintf(&pxwidth[2], "%ld", pp->page_pwidth);
1736 sprintf(&pxlength[2], "%ld", pp->page_plength);
1737 if ((s = checkremote(pp)) != 0) {
1738 syslog(LOG_WARNING, "%s", s);
1739 free(s);
1740 }
1741}
1742
1743void
1744startprinting(const char *printer)
1745{
1746 struct printer myprinter, *pp = &myprinter;
1747 int status;
1748
1749 init_printer(pp);
1750 status = getprintcap(printer, pp);
1751 switch(status) {
1752 case PCAPERR_OSERR:
1753 syslog(LOG_ERR, "can't open printer description file: %m");
1754 exit(1);
1755 case PCAPERR_NOTFOUND:
1756 syslog(LOG_ERR, "unknown printer: %s", printer);
1757 exit(1);
1758 case PCAPERR_TCLOOP:
1759 fatal(pp, "potential reference loop detected in printcap file");
1760 default:
1761 break;
1762 }
1763 printjob(pp);
1764}
1765
1766/*
1767 * Acquire line printer or remote connection.
1768 */
1769static void
1770openpr(const struct printer *pp)
1771{
1772 int p[2];
1773 char *cp;
1774
1775 if (pp->remote) {
1776 openrem(pp);
1777 /*
1778 * Lpd does support the setting of 'of=' filters for
1779 * jobs going to remote machines, but that does not
1780 * have the same meaning as 'of=' does when handling
1781 * local print queues. For remote machines, all 'of='
1782 * filter processing is handled in sendfile(), and that
1783 * does not use these global "output filter" variables.
1784 */
1785 ofd = -1;
1786 of_pid = 0;
1787 return;
1788 } else if (*pp->lp) {
1789 if ((cp = strchr(pp->lp, '@')) != NULL)
1790 opennet(pp);
1791 else
1792 opentty(pp);
1793 } else {
1794 syslog(LOG_ERR, "%s: no line printer device or host name",
1795 pp->printer);
1796 exit(1);
1797 }
1798
1799 /*
1800 * Start up an output filter, if needed.
1801 */
1802 if (pp->filters[LPF_OUTPUT] && !pp->filters[LPF_INPUT] && !of_pid) {
1803 pipe(p);
1804 if (pp->remote) {
1805 strcpy(tfile, TFILENAME);
1806 tfd = mkstemp(tfile);
1807 }
1808 if ((of_pid = dofork(pp, DOABORT)) == 0) { /* child */
1809 dup2(p[0], STDIN_FILENO); /* pipe is std in */
1810 /* tfile/printer is stdout */
1811 dup2(pp->remote ? tfd : pfd, STDOUT_FILENO);
1812 closelog();
1813 closeallfds(3);
1814 if ((cp = strrchr(pp->filters[LPF_OUTPUT], '/')) == NULL)
1815 cp = pp->filters[LPF_OUTPUT];
1816 else
1817 cp++;
1818 execl(pp->filters[LPF_OUTPUT], cp, width, length,
1819 (char *)0);
1820 syslog(LOG_ERR, "%s: execl(%s): %m", pp->printer,
1821 pp->filters[LPF_OUTPUT]);
1822 exit(1);
1823 }
1824 (void) close(p[0]); /* close input side */
1825 ofd = p[1]; /* use pipe for output */
1826 } else {
1827 ofd = pfd;
1828 of_pid = 0;
1829 }
1830}
1831
1832/*
1833 * Printer connected directly to the network
1834 * or to a terminal server on the net
1835 */
1836static void
1837opennet(const struct printer *pp)
1838{
1839 register int i;
1840 int resp;
1841 u_long port;
1842 char *ep;
1843 void (*savealrm)(int);
1844
1845 port = strtoul(pp->lp, &ep, 0);
1846 if (*ep != '@' || port > 65535) {
1847 syslog(LOG_ERR, "%s: bad port number: %s", pp->printer,
1848 pp->lp);
1849 exit(1);
1850 }
1851 ep++;
1852
1853 for (i = 1; ; i = i < 256 ? i << 1 : i) {
1854 resp = -1;
1855 savealrm = signal(SIGALRM, alarmhandler);
1856 alarm(pp->conn_timeout);
1857 pfd = getport(pp, ep, port);
1858 alarm(0);
1859 (void)signal(SIGALRM, savealrm);
1860 if (pfd < 0 && errno == ECONNREFUSED)
1861 resp = 1;
1862 else if (pfd >= 0) {
1863 /*
1864 * need to delay a bit for rs232 lines
1865 * to stabilize in case printer is
1866 * connected via a terminal server
1867 */
1868 delay(500);
1869 break;
1870 }
1871 if (i == 1) {
1872 if (resp < 0)
1873 pstatus(pp, "waiting for %s to come up",
1874 pp->lp);
1875 else
1876 pstatus(pp,
1877 "waiting for access to printer on %s",
1878 pp->lp);
1879 }
1880 sleep(i);
1881 }
1882 pstatus(pp, "sending to %s port %lu", ep, port);
1883}
1884
1885/*
1886 * Printer is connected to an RS232 port on this host
1887 */
1888static void
1889opentty(const struct printer *pp)
1890{
1891 register int i;
1892
1893 for (i = 1; ; i = i < 32 ? i << 1 : i) {
1894 pfd = open(pp->lp, pp->rw ? O_RDWR : O_WRONLY);
1895 if (pfd >= 0) {
1896 delay(500);
1897 break;
1898 }
1899 if (errno == ENOENT) {
1900 syslog(LOG_ERR, "%s: %m", pp->lp);
1901 exit(1);
1902 }
1903 if (i == 1)
1904 pstatus(pp,
1905 "waiting for %s to become ready (offline?)",
1906 pp->printer);
1907 sleep(i);
1908 }
1909 if (isatty(pfd))
1910 setty(pp);
1911 pstatus(pp, "%s is ready and printing", pp->printer);
1912}
1913
1914/*
1915 * Printer is on a remote host
1916 */
1917static void
1918openrem(const struct printer *pp)
1919{
1920 register int i;
1921 int resp;
1922 void (*savealrm)(int);
1923
1924 for (i = 1; ; i = i < 256 ? i << 1 : i) {
1925 resp = -1;
1926 savealrm = signal(SIGALRM, alarmhandler);
1927 alarm(pp->conn_timeout);
1928 pfd = getport(pp, pp->remote_host, 0);
1929 alarm(0);
1930 (void)signal(SIGALRM, savealrm);
1931 if (pfd >= 0) {
1932 if ((writel(pfd, "\2", pp->remote_queue, "\n",
1933 (char *)0)
1934 == 2 + strlen(pp->remote_queue))
1935 && (resp = response(pp)) == 0)
1936 break;
1937 (void) close(pfd);
1938 }
1939 if (i == 1) {
1940 if (resp < 0)
1941 pstatus(pp, "waiting for %s to come up",
1942 pp->remote_host);
1943 else {
1944 pstatus(pp,
1945 "waiting for queue to be enabled on %s",
1946 pp->remote_host);
1947 i = 256;
1948 }
1949 }
1950 sleep(i);
1951 }
1952 pstatus(pp, "sending to %s", pp->remote_host);
1953}
1954
1955/*
1956 * setup tty lines.
1957 */
1958static void
1959setty(const struct printer *pp)
1960{
1961 struct termios ttybuf;
1962
1963 if (ioctl(pfd, TIOCEXCL, (char *)0) < 0) {
1964 syslog(LOG_ERR, "%s: ioctl(TIOCEXCL): %m", pp->printer);
1965 exit(1);
1966 }
1967 if (tcgetattr(pfd, &ttybuf) < 0) {
1968 syslog(LOG_ERR, "%s: tcgetattr: %m", pp->printer);
1969 exit(1);
1970 }
1971 if (pp->baud_rate > 0)
1972 cfsetspeed(&ttybuf, pp->baud_rate);
1973 if (pp->mode_set) {
1974 char *s = strdup(pp->mode_set), *tmp;
1975
1976 while ((tmp = strsep(&s, ",")) != NULL) {
1977 (void) msearch(tmp, &ttybuf);
1978 }
1979 }
1980 if (pp->mode_set != 0 || pp->baud_rate > 0) {
1981 if (tcsetattr(pfd, TCSAFLUSH, &ttybuf) == -1) {
1982 syslog(LOG_ERR, "%s: tcsetattr: %m", pp->printer);
1983 }
1984 }
1985}
1986
1987#include <stdarg.h>
1988
1989static void
1990pstatus(const struct printer *pp, const char *msg, ...)
1991{
1992 int fd;
1993 char *buf;
1994 va_list ap;
1995 va_start(ap, msg);
1996
1997 umask(S_IWOTH);
1998 fd = open(pp->status_file, O_WRONLY|O_CREAT|O_EXLOCK, STAT_FILE_MODE);
1999 if (fd < 0) {
2000 syslog(LOG_ERR, "%s: open(%s): %m", pp->printer,
2001 pp->status_file);
2002 exit(1);
2003 }
2004 ftruncate(fd, 0);
2005 vasprintf(&buf, msg, ap);
2006 va_end(ap);
2007 writel(fd, buf, "\n", (char *)0);
2008 close(fd);
2009 free(buf);
2010}
2011
2012void
2013alarmhandler(int signo __unused)
2014{
2015 /* the signal is ignored */
2016 /* (the '__unused' is just to avoid a compile-time warning) */
2017}