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