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