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