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