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