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