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