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