BSD 4_4_Lite2 release
[unix-history] / usr / src / usr.sbin / lpr / lpd / printjob.c
index 7f0f623..2d17619 100644 (file)
@@ -1,4 +1,48 @@
-/*     printjob.c      4.7     83/06/15        */
+/*
+ * Copyright (c) 1983, 1993
+ *     The Regents of the University of California.  All rights reserved.
+ *
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+static char copyright[] =
+"@(#) Copyright (c) 1983, 1993\n\
+       The Regents of the University of California.  All rights reserved.\n";
+#endif /* not lint */
+
+#ifndef lint
+static char sccsid[] = "@(#)printjob.c 8.7 (Berkeley) 5/10/95";
+#endif /* not lint */
+
+
 /*
  * printjob -- print jobs in the queue.
  *
 /*
  * printjob -- print jobs in the queue.
  *
  *     it does not need to be removed because file locks are dynamic.
  */
 
  *     it does not need to be removed because file locks are dynamic.
  */
 
+#include <sys/param.h>
+#include <sys/wait.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/file.h>
+
+#include <pwd.h>
+#include <unistd.h>
+#include <signal.h>
+#include <sgtty.h>
+#include <syslog.h>
+#include <fcntl.h>
+#include <dirent.h>
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
 #include "lp.h"
 #include "lp.h"
+#include "lp.local.h"
+#include "pathnames.h"
+#include "extern.h"
 
 
-#define DORETURN       0               /* absorb fork error */
-#define DOABORT                1               /* abort if dofork fails */
-
-static char    title[80];              /* ``pr'' title */
-static FILE    *cfp;                   /* control file */
-static int     pfd;                    /* printer file descriptor */
-static int     ofd;                    /* output filter file descriptor */
-static int     lfd;                    /* lock file descriptor */
-static int     pid;                    /* pid of lpd process */
-static int     prchild;                /* id of pr process */
-static int     child;                  /* id of any filters */
-static int     ofilter;                /* id of output filter, if any */
-static int     tof;                    /* true if at top of form */
-static int     remote;                 /* true if sending files to remote */
+#define DORETURN       0       /* absorb fork error */
+#define DOABORT                1       /* abort if dofork fails */
+
+/*
+ * Error tokens
+ */
+#define REPRINT                -2
+#define ERROR          -1
+#define        OK              0
+#define        FATALERR        1
+#define        NOACCT          2
+#define        FILTERERR       3
+#define        ACCESS          4
+
+static dev_t    fdev;          /* device of file pointed to by symlink */
+static ino_t    fino;          /* inode of file pointed to by symlink */
+static FILE    *cfp;           /* control file */
+static int      child;         /* id of any filters */
+static int      lfd;           /* lock file descriptor */
+static int      ofd;           /* output filter file descriptor */
+static int      ofilter;       /* id of output filter, if any */
+static int      pfd;           /* prstatic inter file descriptor */
+static int      pid;           /* pid of lpd process */
+static int      prchild;       /* id of pr process */
+static char     title[80];     /* ``pr'' title */
+static int      tof;           /* true if at top of form */
 
 
-static char    logname[32];            /* user's login name */
-static char    jobname[32];            /* job or file name */
 static char    class[32];              /* classification field */
 static char    class[32];              /* classification field */
-static char    width[10] = "-w";       /* page width in characters */
+static char    fromhost[32];           /* user's host machine */
+                               /* indentation size in static characters */
+static char    indent[10] = "-i0"; 
+static char    jobname[100];           /* job or file name */
 static char    length[10] = "-l";      /* page length in lines */
 static char    length[10] = "-l";      /* page length in lines */
-static char    pxwidth[10] = "-x";     /* page width in pixels */
+static char    logname[32];            /* user's login name */
 static char    pxlength[10] = "-y";    /* page length in pixels */
 static char    pxlength[10] = "-y";    /* page length in pixels */
-static char    indent[10] = "-i0";     /* indentation size in characters */
+static char    pxwidth[10] = "-x";     /* page width in pixels */
+static char    tempfile[] = "errsXXXXXX"; /* file name for filter output */
+static char    width[10] = "-w";       /* page width in static characters */
+
+static void       abortpr __P((int));
+static void       banner __P((char *, char *));
+static int        dofork __P((int));
+static int        dropit __P((int));
+static void       init __P((void));
+static void       openpr __P((void));
+static void       opennet __P((char *));
+static void       opentty __P((void));
+static void       openrem __P((void));
+static int        print __P((int, char *));
+static int        printit __P((char *));
+static void       pstatus __P((const char *, ...));
+static char       response __P((void));
+static void       scan_out __P((int, char *, int));
+static char      *scnline __P((int, char *, int));
+static int        sendfile __P((int, char *));
+static int        sendit __P((char *));
+static void       sendmail __P((char *, int));
+static void       setty __P((void));
 
 
+void
 printjob()
 {
        struct stat stb;
        register struct queue *q, **qp;
        struct queue **queue;
        register int i, nitems;
 printjob()
 {
        struct stat stb;
        register struct queue *q, **qp;
        struct queue **queue;
        register int i, nitems;
-       long pidoff;
-       extern int onintr();
+       off_t pidoff;
+       int errcnt, count = 0;
 
        init();                                 /* set up capabilities */
 
        init();                                 /* set up capabilities */
-       (void) close(1);                        /* set up log file */
-       (void) close(2);
-       if (open(LF, O_WRONLY|O_APPEND) < 0)
-               (void) open("/dev/null", O_WRONLY);
-       dup(1);
+       (void) write(1, "", 1);                 /* ack that daemon is started */
+       (void) close(2);                        /* set up log file */
+       if (open(LF, O_WRONLY|O_APPEND, 0664) < 0) {
+               syslog(LOG_ERR, "%s: %m", LF);
+               (void) open(_PATH_DEVNULL, O_WRONLY);
+       }
+       setgid(getegid());
        pid = getpid();                         /* for use with lprm */
        setpgrp(0, pid);
        pid = getpid();                         /* for use with lprm */
        setpgrp(0, pid);
-       signal(SIGINT, onintr);
+       signal(SIGHUP, abortpr);
+       signal(SIGINT, abortpr);
+       signal(SIGQUIT, abortpr);
+       signal(SIGTERM, abortpr);
+
+       (void) mktemp(tempfile);
 
        /*
         * uses short form file names
         */
        if (chdir(SD) < 0) {
 
        /*
         * uses short form file names
         */
        if (chdir(SD) < 0) {
-               log("cannot chdir to %s", SD);
+               syslog(LOG_ERR, "%s: %m", SD);
                exit(1);
        }
        if (stat(LO, &stb) == 0 && (stb.st_mode & 0100))
                exit(0);                /* printing disabled */
                exit(1);
        }
        if (stat(LO, &stb) == 0 && (stb.st_mode & 0100))
                exit(0);                /* printing disabled */
-       lfd = open(LO, O_WRONLY|O_CREAT, 0664);
-       if (lfd < 0 || flock(lfd, LOCK_EX|LOCK_NB) < 0) {
+       lfd = open(LO, O_WRONLY|O_CREAT, 0644);
+       if (lfd < 0) {
+               syslog(LOG_ERR, "%s: %s: %m", printer, LO);
+               exit(1);
+       }
+       if (flock(lfd, LOCK_EX|LOCK_NB) < 0) {
                if (errno == EWOULDBLOCK)       /* active deamon present */
                        exit(0);
                if (errno == EWOULDBLOCK)       /* active deamon present */
                        exit(0);
-               log("cannot create %s", LO);
+               syslog(LOG_ERR, "%s: %s: %m", printer, LO);
                exit(1);
        }
        ftruncate(lfd, 0);
                exit(1);
        }
        ftruncate(lfd, 0);
@@ -74,18 +185,22 @@ printjob()
        sprintf(line, "%u\n", pid);
        pidoff = i = strlen(line);
        if (write(lfd, line, i) != i) {
        sprintf(line, "%u\n", pid);
        pidoff = i = strlen(line);
        if (write(lfd, line, i) != i) {
-               log("cannot write daemon pid");
+               syslog(LOG_ERR, "%s: %s: %m", printer, LO);
                exit(1);
        }
        /*
         * search the spool directory for work and sort by queue order.
         */
        if ((nitems = getq(&queue)) < 0) {
                exit(1);
        }
        /*
         * search the spool directory for work and sort by queue order.
         */
        if ((nitems = getq(&queue)) < 0) {
-               log("can't scan spool directory %s", SD);
+               syslog(LOG_ERR, "%s: can't scan %s", printer, SD);
                exit(1);
        }
        if (nitems == 0)                /* no work to do */
                exit(0);
                exit(1);
        }
        if (nitems == 0)                /* no work to do */
                exit(0);
+       if (stb.st_mode & 01) {         /* reset queue flag */
+               if (fchmod(lfd, stb.st_mode & 0776) < 0)
+                       syslog(LOG_ERR, "%s: %s: %m", printer, LO);
+       }
        openpr();                       /* open printer or remote */
 again:
        /*
        openpr();                       /* open printer or remote */
 again:
        /*
@@ -97,39 +212,63 @@ again:
                q = *qp++;
                if (stat(q->q_name, &stb) < 0)
                        continue;
                q = *qp++;
                if (stat(q->q_name, &stb) < 0)
                        continue;
+               errcnt = 0;
        restart:
                (void) lseek(lfd, pidoff, 0);
                (void) sprintf(line, "%s\n", q->q_name);
                i = strlen(line);
                if (write(lfd, line, i) != i)
        restart:
                (void) lseek(lfd, pidoff, 0);
                (void) sprintf(line, "%s\n", q->q_name);
                i = strlen(line);
                if (write(lfd, line, i) != i)
-                       log("can't write (%d) control file name", errno);
+                       syslog(LOG_ERR, "%s: %s: %m", printer, LO);
                if (!remote)
                        i = printit(q->q_name);
                else
                        i = sendit(q->q_name);
                /*
                if (!remote)
                        i = printit(q->q_name);
                else
                        i = sendit(q->q_name);
                /*
-                * Check to see if we are supposed to stop printing.
+                * Check to see if we are supposed to stop printing or
+                * if we are to rebuild the queue.
                 */
                 */
-               if (stat(LO, &stb) == 0 && (stb.st_mode & 0100))
-                       goto done;
-               /*
-                * Check to see if we should try reprinting the job.
-                */
-               if (i > 0) {
-                       log("restarting");
+               if (fstat(lfd, &stb) == 0) {
+                       /* stop printing before starting next job? */
+                       if (stb.st_mode & 0100)
+                               goto done;
+                       /* rebuild queue (after lpc topq) */
+                       if (stb.st_mode & 01) {
+                               for (free((char *) q); nitems--; free((char *) q))
+                                       q = *qp++;
+                               if (fchmod(lfd, stb.st_mode & 0776) < 0)
+                                       syslog(LOG_WARNING, "%s: %s: %m",
+                                               printer, LO);
+                               break;
+                       }
+               }
+               if (i == OK)            /* file ok and printed */
+                       count++;
+               else if (i == REPRINT && ++errcnt < 5) {
+                       /* try reprinting the job */
+                       syslog(LOG_INFO, "restarting %s", printer);
                        if (ofilter > 0) {
                                kill(ofilter, SIGCONT); /* to be sure */
                                (void) close(ofd);
                        if (ofilter > 0) {
                                kill(ofilter, SIGCONT); /* to be sure */
                                (void) close(ofd);
-                               while ((i = wait(0)) > 0 && i != ofilter)
+                               while ((i = wait(NULL)) > 0 && i != ofilter)
                                        ;
                                ofilter = 0;
                        }
                        (void) close(pfd);      /* close printer */
                                        ;
                                ofilter = 0;
                        }
                        (void) close(pfd);      /* close printer */
-                       (void) lseek(lfd, pidoff, 0);
-                       if (write(lfd, "\n", 1) != 1)
-                               log("can't write (%d) control file name", errno);
+                       if (ftruncate(lfd, pidoff) < 0)
+                               syslog(LOG_WARNING, "%s: %s: %m", printer, LO);
                        openpr();               /* try to reopen printer */
                        goto restart;
                        openpr();               /* try to reopen printer */
                        goto restart;
+               } else {
+                       syslog(LOG_WARNING, "%s: job could not be %s (%s)", printer,
+                               remote ? "sent to remote host" : "printed", q->q_name);
+                       if (i == REPRINT) {
+                               /* insure we don't attempt this job again */
+                               (void) unlink(q->q_name);
+                               q->q_name[0] = 'd';
+                               (void) unlink(q->q_name);
+                               if (logname[0])
+                                       sendmail(logname, FATALERR);
+                       }
                }
        }
        free((char *) queue);
                }
        }
        free((char *) queue);
@@ -137,15 +276,18 @@ again:
         * search the spool directory for more work.
         */
        if ((nitems = getq(&queue)) < 0) {
         * search the spool directory for more work.
         */
        if ((nitems = getq(&queue)) < 0) {
-               log("can't scan spool directory %s", SD);
+               syslog(LOG_ERR, "%s: can't scan %s", printer, SD);
                exit(1);
        }
        if (nitems == 0) {              /* no more work to do */
        done:
                exit(1);
        }
        if (nitems == 0) {              /* no more work to do */
        done:
-               if (!SF && !tof)
-                       (void) write(ofd, FF, strlen(FF));
-               if (TR != NULL)         /* output trailer */
-                       (void) write(ofd, TR, strlen(TR));
+               if (count > 0) {        /* Files actually printed */
+                       if (!SF && !tof)
+                               (void) write(ofd, FF, strlen(FF));
+                       if (TR != NULL)         /* output trailer */
+                               (void) write(ofd, TR, strlen(TR));
+               }
+               (void) unlink(tempfile);
                exit(0);
        }
        goto again;
                exit(0);
        }
        goto again;
@@ -153,38 +295,39 @@ again:
 
 char   fonts[4][50];   /* fonts for troff */
 
 
 char   fonts[4][50];   /* fonts for troff */
 
-static char ifonts[4][18] = {
-       "/usr/lib/vfont/R",
-       "/usr/lib/vfont/I",
-       "/usr/lib/vfont/B",
-       "/usr/lib/vfont/S"
+char ifonts[4][40] = {
+       _PATH_VFONTR,
+       _PATH_VFONTI,
+       _PATH_VFONTB,
+       _PATH_VFONTS,
 };
 
 /*
  * The remaining part is the reading of the control file (cf)
  * and performing the various actions.
 };
 
 /*
  * The remaining part is the reading of the control file (cf)
  * and performing the various actions.
- * Returns 0 if everthing was OK, 1 if we should try to reprint the job and
- * -1 if a non-recoverable error occured.
  */
  */
-static
+static int
 printit(file)
        char *file;
 {
        register int i;
 printit(file)
        char *file;
 {
        register int i;
-       int bombed = 0;
+       char *cp;
+       int bombed = OK;
 
        /*
 
        /*
-        * open control file
+        * open control file; ignore if no longer there.
         */
        if ((cfp = fopen(file, "r")) == NULL) {
         */
        if ((cfp = fopen(file, "r")) == NULL) {
-               log("control file (%s) open failure <errno = %d>", file, errno);
-               return(0);
+               syslog(LOG_INFO, "%s: %s: %m", printer, file);
+               return(OK);
        }
        /*
         * Reset troff fonts.
         */
        for (i = 0; i < 4; i++)
                strcpy(fonts[i], ifonts[i]);
        }
        /*
         * Reset troff fonts.
         */
        for (i = 0; i < 4; i++)
                strcpy(fonts[i], ifonts[i]);
+       sprintf(&width[2], "%d", PW);
+       strcpy(indent+2, "0");
 
        /*
         *      read the control file for work to do
 
        /*
         *      read the control file for work to do
@@ -193,6 +336,7 @@ printit(file)
         *      rest of the line is the argument.
         *      valid commands are:
         *
         *      rest of the line is the argument.
         *      valid commands are:
         *
+        *              S -- "stat info" for symbolic link protection
         *              J -- "job name" on banner page
         *              C -- "class name" on banner page
         *              L -- "literal" user's name to print on banner
         *              J -- "job name" on banner page
         *              C -- "class name" on banner page
         *              L -- "literal" user's name to print on banner
@@ -200,10 +344,12 @@ printit(file)
         *              H -- "host name" of machine where lpr was done
         *              P -- "person" user's login name
         *              I -- "indent" amount to indent output
         *              H -- "host name" of machine where lpr was done
         *              P -- "person" user's login name
         *              I -- "indent" amount to indent output
+        *              R -- laser dpi "resolution"
         *              f -- "file name" name of text file to print
         *              l -- "file name" text file with control chars
         *              p -- "file name" text file to print with pr(1)
         *              t -- "file name" troff(1) file to print
         *              f -- "file name" name of text file to print
         *              l -- "file name" text file with control chars
         *              p -- "file name" text file to print with pr(1)
         *              t -- "file name" troff(1) file to print
+        *              n -- "file name" ditroff(1) file to print
         *              d -- "file name" dvi file to print
         *              g -- "file name" plot(1G) file to print
         *              v -- "file name" plain raster file to print
         *              d -- "file name" dvi file to print
         *              g -- "file name" plot(1G) file to print
         *              v -- "file name" plain raster file to print
@@ -225,42 +371,55 @@ printit(file)
        while (getline(cfp))
                switch (line[0]) {
                case 'H':
        while (getline(cfp))
                switch (line[0]) {
                case 'H':
-                       strcpy(host, line+1);
+                       strcpy(fromhost, line+1);
                        if (class[0] == '\0')
                        if (class[0] == '\0')
-                               strcpy(class, line+1);
+                               strncpy(class, line+1, sizeof(class)-1);
                        continue;
 
                case 'P':
                        continue;
 
                case 'P':
-                       strcpy(logname, line+1);
+                       strncpy(logname, line+1, sizeof(logname)-1);
                        if (RS) {                       /* restricted */
                        if (RS) {                       /* restricted */
-                               if (getpwnam(logname) == (struct passwd *)0) {
-                                       bombed = 2;
-                                       sendmail(bombed);
+                               if (getpwnam(logname) == NULL) {
+                                       bombed = NOACCT;
+                                       sendmail(line+1, bombed);
                                        goto pass2;
                                }
                        }
                        continue;
 
                                        goto pass2;
                                }
                        }
                        continue;
 
+               case 'S':
+                       cp = line+1;
+                       i = 0;
+                       while (*cp >= '0' && *cp <= '9')
+                               i = i * 10 + (*cp++ - '0');
+                       fdev = i;
+                       cp++;
+                       i = 0;
+                       while (*cp >= '0' && *cp <= '9')
+                               i = i * 10 + (*cp++ - '0');
+                       fino = i;
+                       continue;
+
                case 'J':
                        if (line[1] != '\0')
                case 'J':
                        if (line[1] != '\0')
-                               strcpy(jobname, line+1);
+                               strncpy(jobname, line+1, sizeof(jobname)-1);
                        else
                                strcpy(jobname, " ");
                        continue;
 
                case 'C':
                        if (line[1] != '\0')
                        else
                                strcpy(jobname, " ");
                        continue;
 
                case 'C':
                        if (line[1] != '\0')
-                               strcpy(class, line+1);
+                               strncpy(class, line+1, sizeof(class)-1);
                        else if (class[0] == '\0')
                        else if (class[0] == '\0')
-                               gethostname(class, sizeof (class));
+                               gethostname(class, sizeof(class));
                        continue;
 
                case 'T':       /* header title for pr */
                        continue;
 
                case 'T':       /* header title for pr */
-                       strcpy(title, line+1);
+                       strncpy(title, line+1, sizeof(title)-1);
                        continue;
 
                case 'L':       /* identification line */
                        continue;
 
                case 'L':       /* identification line */
-                       if (!SH)
+                       if (!SH && !HL)
                                banner(line+1, jobname);
                        continue;
 
                                banner(line+1, jobname);
                        continue;
 
@@ -273,25 +432,34 @@ printit(file)
                        continue;
 
                case 'W':       /* page width */
                        continue;
 
                case 'W':       /* page width */
-                       strcpy(width+2, line+1);
+                       strncpy(width+2, line+1, sizeof(width)-3);
                        continue;
 
                case 'I':       /* indent amount */
                        continue;
 
                case 'I':       /* indent amount */
-                       strcpy(indent+2, line+1);
+                       strncpy(indent+2, line+1, sizeof(indent)-3);
                        continue;
 
                default:        /* some file to print */
                        continue;
 
                default:        /* some file to print */
-                       if ((i = print(line[0], line+1)) > 0) {
+                       switch (i = print(line[0], line+1)) {
+                       case ERROR:
+                               if (bombed == OK)
+                                       bombed = FATALERR;
+                               break;
+                       case REPRINT:
                                (void) fclose(cfp);
                                (void) fclose(cfp);
-                               return(1);
-                       } else if (i < 0)
-                               bombed = 1;
+                               return(REPRINT);
+                       case FILTERERR:
+                       case ACCESS:
+                               bombed = i;
+                               sendmail(logname, bombed);
+                       }
                        title[0] = '\0';
                        continue;
 
                case 'N':
                case 'U':
                case 'M':
                        title[0] = '\0';
                        continue;
 
                case 'N':
                case 'U':
                case 'M':
+               case 'R':
                        continue;
                }
 
                        continue;
                }
 
@@ -301,45 +469,61 @@ pass2:
        fseek(cfp, 0L, 0);
        while (getline(cfp))
                switch (line[0]) {
        fseek(cfp, 0L, 0);
        while (getline(cfp))
                switch (line[0]) {
+               case 'L':       /* identification line */
+                       if (!SH && HL)
+                               banner(line+1, jobname);
+                       continue;
+
                case 'M':
                case 'M':
-                       if (bombed != 2)                /* already sent if 2 */
-                               sendmail(bombed);
+                       if (bombed < NOACCT)    /* already sent if >= NOACCT */
+                               sendmail(line+1, bombed);
                        continue;
 
                case 'U':
                        (void) unlink(line+1);
                }
        /*
                        continue;
 
                case 'U':
                        (void) unlink(line+1);
                }
        /*
-        * clean-up incase another control file exists
+        * clean-up in case another control file exists
         */
        (void) fclose(cfp);
        (void) unlink(file);
         */
        (void) fclose(cfp);
        (void) unlink(file);
-       return(0);
+       return(bombed == OK ? OK : ERROR);
 }
 
 /*
  * Print a file.
 }
 
 /*
  * Print a file.
- * Set up the chain [ PR [ | {IF, OF} ] ] or {IF, TF, CF, VF}.
- * Return -1 if a non-recoverable error occured, 1 if a recoverable error and
+ * Set up the chain [ PR [ | {IF, OF} ] ] or {IF, RF, TF, NF, DF, CF, VF}.
+ * Return -1 if a non-recoverable error occured,
+ * 2 if the filter detected some errors (but printed the job anyway),
+ * 1 if we should try to reprint this job and
  * 0 if all is well.
  * Note: all filters take stdin as the file, stdout as the printer,
  * stderr as the log file, and must not ignore SIGINT.
  */
  * 0 if all is well.
  * Note: all filters take stdin as the file, stdout as the printer,
  * stderr as the log file, and must not ignore SIGINT.
  */
-static
+static int
 print(format, file)
        int format;
        char *file;
 {
 print(format, file)
        int format;
        char *file;
 {
-       register int n, fi, fo;
+       register int n;
        register char *prog;
        register char *prog;
+       int fi, fo;
+       FILE *fp;
        char *av[15], buf[BUFSIZ];
        int pid, p[2], stopped = 0;
        union wait status;
        char *av[15], buf[BUFSIZ];
        int pid, p[2], stopped = 0;
        union wait status;
+       struct stat stb;
 
 
-       if ((fi = open(file, O_RDONLY)) < 0) {
-               log("%s: open failure <errno = %d>", file, errno);
-               return(-1);
-       }
+       if (lstat(file, &stb) < 0 || (fi = open(file, O_RDONLY)) < 0)
+               return(ERROR);
+       /*
+        * Check to see if data file is a symbolic link. If so, it should
+        * still point to the same file or someone is trying to print
+        * something he shouldn't.
+        */
+       if ((stb.st_mode & S_IFMT) == S_IFLNK && fstat(fi, &stb) == 0 &&
+           (stb.st_dev != fdev || stb.st_ino != fino))
+               return(ACCESS);
        if (!SF && !tof) {              /* start on a fresh page */
                (void) write(ofd, FF, strlen(FF));
                tof = 1;
        if (!SF && !tof) {              /* start on a fresh page */
                (void) write(ofd, FF, strlen(FF));
                tof = 1;
@@ -349,15 +533,15 @@ print(format, file)
                while ((n = read(fi, buf, BUFSIZ)) > 0)
                        if (write(ofd, buf, n) != n) {
                                (void) close(fi);
                while ((n = read(fi, buf, BUFSIZ)) > 0)
                        if (write(ofd, buf, n) != n) {
                                (void) close(fi);
-                               return(1);
+                               return(REPRINT);
                        }
                (void) close(fi);
                        }
                (void) close(fi);
-               return(0);
+               return(OK);
        }
        switch (format) {
        case 'p':       /* print file using 'pr' */
                if (IF == NULL) {       /* use output filter */
        }
        switch (format) {
        case 'p':       /* print file using 'pr' */
                if (IF == NULL) {       /* use output filter */
-                       prog = PR;
+                       prog = _PATH_PR;
                        av[0] = "pr";
                        av[1] = width;
                        av[2] = length;
                        av[0] = "pr";
                        av[1] = width;
                        av[2] = length;
@@ -371,10 +555,12 @@ print(format, file)
                if ((prchild = dofork(DORETURN)) == 0) {        /* child */
                        dup2(fi, 0);            /* file is stdin */
                        dup2(p[1], 1);          /* pipe is stdout */
                if ((prchild = dofork(DORETURN)) == 0) {        /* child */
                        dup2(fi, 0);            /* file is stdin */
                        dup2(p[1], 1);          /* pipe is stdout */
+                       closelog();
                        for (n = 3; n < NOFILE; n++)
                                (void) close(n);
                        for (n = 3; n < NOFILE; n++)
                                (void) close(n);
-                       execl(PR, "pr", width, length, "-h", *title ? title : " ", 0);
-                       log("cannot execl %s", PR);
+                       execl(_PATH_PR, "pr", width, length,
+                           "-h", *title ? title : " ", 0);
+                       syslog(LOG_ERR, "cannot execl %s", _PATH_PR);
                        exit(2);
                }
                (void) close(p[1]);             /* close output side */
                        exit(2);
                }
                (void) close(p[1]);             /* close output side */
@@ -382,7 +568,7 @@ print(format, file)
                if (prchild < 0) {
                        prchild = 0;
                        (void) close(p[0]);
                if (prchild < 0) {
                        prchild = 0;
                        (void) close(p[0]);
-                       return(-1);
+                       return(ERROR);
                }
                fi = p[0];                      /* use pipe for input */
        case 'f':       /* print plain text file */
                }
                fi = p[0];                      /* use pipe for input */
        case 'f':       /* print plain text file */
@@ -394,7 +580,7 @@ print(format, file)
                break;
        case 'l':       /* like 'f' but pass control characters */
                prog = IF;
                break;
        case 'l':       /* like 'f' but pass control characters */
                prog = IF;
-               av[1] = "-l";
+               av[1] = "-c";
                av[2] = width;
                av[3] = length;
                av[4] = indent;
                av[2] = width;
                av[3] = length;
                av[4] = indent;
@@ -407,21 +593,23 @@ print(format, file)
                n = 3;
                break;
        case 't':       /* print troff output */
                n = 3;
                break;
        case 't':       /* print troff output */
+       case 'n':       /* print ditroff output */
        case 'd':       /* print tex output */
                (void) unlink(".railmag");
                if ((fo = creat(".railmag", FILMOD)) < 0) {
        case 'd':       /* print tex output */
                (void) unlink(".railmag");
                if ((fo = creat(".railmag", FILMOD)) < 0) {
-                       log("cannot create .railmag");
+                       syslog(LOG_ERR, "%s: cannot create .railmag", printer);
                        (void) unlink(".railmag");
                } else {
                        for (n = 0; n < 4; n++) {
                                if (fonts[n][0] != '/')
                        (void) unlink(".railmag");
                } else {
                        for (n = 0; n < 4; n++) {
                                if (fonts[n][0] != '/')
-                                       (void) write(fo, "/usr/lib/vfont/", 15);
+                                       (void) write(fo, _PATH_VFONT,
+                                           sizeof(_PATH_VFONT) - 1);
                                (void) write(fo, fonts[n], strlen(fonts[n]));
                                (void) write(fo, "\n", 1);
                        }
                        (void) close(fo);
                }
                                (void) write(fo, fonts[n], strlen(fonts[n]));
                                (void) write(fo, "\n", 1);
                        }
                        (void) close(fo);
                }
-               prog = (format == 't') ? TF : DF;
+               prog = (format == 't') ? TF : (format == 'n') ? NF : DF;
                av[1] = pxwidth;
                av[2] = pxlength;
                n = 3;
                av[1] = pxwidth;
                av[2] = pxlength;
                n = 3;
@@ -446,8 +634,16 @@ print(format, file)
                break;
        default:
                (void) close(fi);
                break;
        default:
                (void) close(fi);
-               log("illegal format character '%c'", format);
-               return(-1);
+               syslog(LOG_ERR, "%s: illegal format character '%c'",
+                       printer, format);
+               return(ERROR);
+       }
+       if (prog == NULL) {
+               (void) close(fi);
+               syslog(LOG_ERR,
+                  "%s: no filter found in printcap for format character '%c'",
+                  printer, format);
+               return(ERROR);
        }
        if ((av[0] = rindex(prog, '/')) != NULL)
                av[0]++;
        }
        if ((av[0] = rindex(prog, '/')) != NULL)
                av[0]++;
@@ -456,18 +652,21 @@ print(format, file)
        av[n++] = "-n";
        av[n++] = logname;
        av[n++] = "-h";
        av[n++] = "-n";
        av[n++] = logname;
        av[n++] = "-h";
-       av[n++] = host;
+       av[n++] = fromhost;
        av[n++] = AF;
        av[n] = 0;
        fo = pfd;
        if (ofilter > 0) {              /* stop output filter */
                write(ofd, "\031\1", 2);
        av[n++] = AF;
        av[n] = 0;
        fo = pfd;
        if (ofilter > 0) {              /* stop output filter */
                write(ofd, "\031\1", 2);
-               while ((pid = wait3(&status, WUNTRACED, 0)) > 0 && pid != ofilter)
+               while ((pid =
+                   wait3((int *)&status, WUNTRACED, 0)) > 0 && pid != ofilter)
                        ;
                if (status.w_stopval != WSTOPPED) {
                        (void) close(fi);
                        ;
                if (status.w_stopval != WSTOPPED) {
                        (void) close(fi);
-                       log("output filter died (%d)", status.w_retcode);
-                       return(1);
+                       syslog(LOG_WARNING,
+                               "%s: output filter died (retcode=%d termsig=%d)",
+                               printer, status.w_retcode, status.w_termsig);
+                       return(REPRINT);
                }
                stopped++;
        }
                }
                stopped++;
        }
@@ -475,34 +674,57 @@ start:
        if ((child = dofork(DORETURN)) == 0) {  /* child */
                dup2(fi, 0);
                dup2(fo, 1);
        if ((child = dofork(DORETURN)) == 0) {  /* child */
                dup2(fi, 0);
                dup2(fo, 1);
+               n = open(tempfile, O_WRONLY|O_CREAT|O_TRUNC, 0664);
+               if (n >= 0)
+                       dup2(n, 2);
+               closelog();
                for (n = 3; n < NOFILE; n++)
                        (void) close(n);
                execv(prog, av);
                for (n = 3; n < NOFILE; n++)
                        (void) close(n);
                execv(prog, av);
-               log("cannot execl %s", prog);
+               syslog(LOG_ERR, "cannot execv %s", prog);
                exit(2);
        }
        (void) close(fi);
        if (child < 0)
                status.w_retcode = 100;
        else
                exit(2);
        }
        (void) close(fi);
        if (child < 0)
                status.w_retcode = 100;
        else
-               while ((pid = wait(&status)) > 0 && pid != child)
+               while ((pid = wait((int *)&status)) > 0 && pid != child)
                        ;
        child = 0;
        prchild = 0;
        if (stopped) {          /* restart output filter */
                if (kill(ofilter, SIGCONT) < 0) {
                        ;
        child = 0;
        prchild = 0;
        if (stopped) {          /* restart output filter */
                if (kill(ofilter, SIGCONT) < 0) {
-                       log("cannot restart output filter");
+                       syslog(LOG_ERR, "cannot restart output filter");
                        exit(1);
                }
        }
        tof = 0;
                        exit(1);
                }
        }
        tof = 0;
-       if (!WIFEXITED(status) || status.w_retcode > 1) {
-               log("Daemon Filter '%c' Malfunction (%d)", format, status.w_retcode);
-               return(-1);
-       } else if (status.w_retcode == 1)
-               return(1);
-       tof = 1;
-       return(0);
+
+       /* Copy filter output to "lf" logfile */
+       if (fp = fopen(tempfile, "r")) {
+               while (fgets(buf, sizeof(buf), fp))
+                       fputs(buf, stderr);
+               fclose(fp);
+       }
+
+       if (!WIFEXITED(status)) {
+               syslog(LOG_WARNING, "%s: filter '%c' terminated (termsig=%d)",
+                       printer, format, status.w_termsig);
+               return(ERROR);
+       }
+       switch (status.w_retcode) {
+       case 0:
+               tof = 1;
+               return(OK);
+       case 1:
+               return(REPRINT);
+       case 2:
+               return(ERROR);
+       default:
+               syslog(LOG_WARNING, "%s: filter '%c' exited (retcode=%d)",
+                       printer, format, status.w_retcode);
+               return(FILTERERR);
+       }
 }
 
 /*
 }
 
 /*
@@ -510,20 +732,18 @@ start:
  * Return -1 if a non-recoverable error occured, 1 if a recoverable error and
  * 0 if all is well.
  */
  * Return -1 if a non-recoverable error occured, 1 if a recoverable error and
  * 0 if all is well.
  */
-static
+static int
 sendit(file)
        char *file;
 {
 sendit(file)
        char *file;
 {
-       register int linelen, err = 0;
-       char last[132];
+       register int i, err = OK;
+       char *cp, last[BUFSIZ];
 
        /*
         * open control file
         */
 
        /*
         * open control file
         */
-       if ((cfp = fopen(file, "r")) == NULL) {
-               log("control file (%s) open failure <errno = %d>", file, errno);
-               return(0);
-       }
+       if ((cfp = fopen(file, "r")) == NULL)
+               return(OK);
        /*
         *      read the control file for work to do
         *
        /*
         *      read the control file for work to do
         *
@@ -541,24 +761,43 @@ sendit(file)
         */
        while (getline(cfp)) {
        again:
         */
        while (getline(cfp)) {
        again:
+               if (line[0] == 'S') {
+                       cp = line+1;
+                       i = 0;
+                       while (*cp >= '0' && *cp <= '9')
+                               i = i * 10 + (*cp++ - '0');
+                       fdev = i;
+                       cp++;
+                       i = 0;
+                       while (*cp >= '0' && *cp <= '9')
+                               i = i * 10 + (*cp++ - '0');
+                       fino = i;
+                       continue;
+               }
                if (line[0] >= 'a' && line[0] <= 'z') {
                        strcpy(last, line);
                if (line[0] >= 'a' && line[0] <= 'z') {
                        strcpy(last, line);
-                       while (linelen = getline(cfp))
+                       while (i = getline(cfp))
                                if (strcmp(last, line))
                                        break;
                                if (strcmp(last, line))
                                        break;
-                       if ((err = sendfile('\3', last+1)) > 0) {
-                               (void) fclose(cfp);
-                               return(1);
-                       } else if (err)
+                       switch (sendfile('\3', last+1)) {
+                       case OK:
+                               if (i)
+                                       goto again;
                                break;
                                break;
-                       if (linelen)
-                               goto again;
+                       case REPRINT:
+                               (void) fclose(cfp);
+                               return(REPRINT);
+                       case ACCESS:
+                               sendmail(logname, ACCESS);
+                       case ERROR:
+                               err = ERROR;
+                       }
                        break;
                }
        }
                        break;
                }
        }
-       if (!err && sendfile('\2', file) > 0) {
+       if (err == OK && sendfile('\2', file) > 0) {
                (void) fclose(cfp);
                (void) fclose(cfp);
-               return(1);
+               return(REPRINT);
        }
        /*
         * pass 2
        }
        /*
         * pass 2
@@ -568,40 +807,55 @@ sendit(file)
                if (line[0] == 'U')
                        (void) unlink(line+1);
        /*
                if (line[0] == 'U')
                        (void) unlink(line+1);
        /*
-        * clean-up incase another control file exists
+        * clean-up in case another control file exists
         */
        (void) fclose(cfp);
        (void) unlink(file);
         */
        (void) fclose(cfp);
        (void) unlink(file);
-       return(0);
+       return(err);
 }
 
 /*
  * Send a data file to the remote machine and spool it.
  * Return positive if we should try resending.
  */
 }
 
 /*
  * Send a data file to the remote machine and spool it.
  * Return positive if we should try resending.
  */
-static
+static int
 sendfile(type, file)
 sendfile(type, file)
-       char type, *file;
+       int type;
+       char *file;
 {
        register int f, i, amt;
        struct stat stb;
        char buf[BUFSIZ];
 {
        register int f, i, amt;
        struct stat stb;
        char buf[BUFSIZ];
-       int sizerr;
+       int sizerr, resp;
 
 
-       if ((f = open(file, O_RDONLY)) < 0 || fstat(f, &stb) < 0) {
-               log("file (%s) open failure <errno = %d>", file, errno);
-               return(-1);
-       }
-       (void) sprintf(buf, "%c%d %s\n", type, stb.st_size, file);
+       if (lstat(file, &stb) < 0 || (f = open(file, O_RDONLY)) < 0)
+               return(ERROR);
+       /*
+        * Check to see if data file is a symbolic link. If so, it should
+        * still point to the same file or someone is trying to print something
+        * he shouldn't.
+        */
+       if ((stb.st_mode & S_IFMT) == S_IFLNK && fstat(f, &stb) == 0 &&
+           (stb.st_dev != fdev || stb.st_ino != fino))
+               return(ACCESS);
+       (void) sprintf(buf, "%c%ld %s\n", type, (long)stb.st_size, file);
        amt = strlen(buf);
        amt = strlen(buf);
-       if (write(pfd, buf, amt) != amt) {
-               (void) close(f);
-               return(1);
-       }
-       if (noresponse()) {
-               (void) close(f);
-               return(1);
+       for (i = 0;  ; i++) {
+               if (write(pfd, buf, amt) != amt ||
+                   (resp = response()) < 0 || resp == '\1') {
+                       (void) close(f);
+                       return(REPRINT);
+               } else if (resp == '\0')
+                       break;
+               if (i == 0)
+                       pstatus("no space on remote; waiting for queue to drain");
+               if (i == 10)
+                       syslog(LOG_ALERT, "%s: can't send to %s; queue full",
+                               printer, RM);
+               sleep(5 * 60);
        }
        }
+       if (i)
+               pstatus("sending to %s", RM);
        sizerr = 0;
        for (i = 0; i < stb.st_size; i += BUFSIZ) {
                amt = BUFSIZ;
        sizerr = 0;
        for (i = 0; i < stb.st_size; i += BUFSIZ) {
                amt = BUFSIZ;
@@ -611,20 +865,23 @@ sendfile(type, file)
                        sizerr = 1;
                if (write(pfd, buf, amt) != amt) {
                        (void) close(f);
                        sizerr = 1;
                if (write(pfd, buf, amt) != amt) {
                        (void) close(f);
-                       return(1);
+                       return(REPRINT);
                }
        }
                }
        }
+
+
+
+
        (void) close(f);
        if (sizerr) {
        (void) close(f);
        if (sizerr) {
-               log("%s: changed size", file);
-               (void) write(pfd, "\1", 1);  /* tell recvjob to ignore this file */
-               return(-1);
+               syslog(LOG_INFO, "%s: %s: changed size", printer, file);
+               /* tell recvjob to ignore this file */
+               (void) write(pfd, "\1", 1);
+               return(ERROR);
        }
        }
-       if (write(pfd, "", 1) != 1)
-               return(1);
-       if (noresponse())
-               return(1);
-       return(0);
+       if (write(pfd, "", 1) != 1 || response())
+               return(REPRINT);
+       return(OK);
 }
 
 /*
 }
 
 /*
@@ -632,22 +889,22 @@ sendfile(type, file)
  * are in sync with eachother.
  * Return non-zero if the connection was lost.
  */
  * are in sync with eachother.
  * Return non-zero if the connection was lost.
  */
-static
-noresponse()
+static char
+response()
 {
        char resp;
 
 {
        char resp;
 
-       if (read(pfd, &resp, 1) != 1 || resp != '\0') {
-               log("lost connection or error in recvjob");
-               return(1);
+       if (read(pfd, &resp, 1) != 1) {
+               syslog(LOG_INFO, "%s: lost connection", printer);
+               return(-1);
        }
        }
-       return(0);
+       return(resp);
 }
 
 /*
  * Banner printing stuff
  */
 }
 
 /*
  * Banner printing stuff
  */
-static
+static void
 banner(name1, name2)
        char *name1, *name2;
 {
 banner(name1, name2)
        char *name1, *name2;
 {
@@ -690,8 +947,9 @@ banner(name1, name2)
 
 static char *
 scnline(key, p, c)
 
 static char *
 scnline(key, p, c)
-       register char key, *p;
-       char c;
+       register int key;
+       register char *p;
+       int c;
 {
        register scnwidth;
 
 {
        register scnwidth;
 
@@ -704,10 +962,10 @@ scnline(key, p, c)
 
 #define TRC(q) (((q)-' ')&0177)
 
 
 #define TRC(q) (((q)-' ')&0177)
 
-static
+static void
 scan_out(scfd, scsp, dlm)
 scan_out(scfd, scsp, dlm)
-       int scfd;
-       char *scsp, dlm;
+       int scfd, dlm;
+       char *scsp;
 {
        register char *strp;
        register nchrs, j;
 {
        register char *strp;
        register nchrs, j;
@@ -738,9 +996,9 @@ scan_out(scfd, scsp, dlm)
        }
 }
 
        }
 }
 
-static
+static int
 dropit(c)
 dropit(c)
-       char c;
+       int c;
 {
        switch(c) {
 
 {
        switch(c) {
 
@@ -763,59 +1021,84 @@ dropit(c)
  * sendmail ---
  *   tell people about job completion
  */
  * sendmail ---
  *   tell people about job completion
  */
-static
-sendmail(bombed)
+static void
+sendmail(user, bombed)
+       char *user;
        int bombed;
 {
        int bombed;
 {
-       static int p[2];
        register int i;
        register int i;
-       int stat;
+       int p[2], s;
        register char *cp;
        char buf[100];
        register char *cp;
        char buf[100];
+       struct stat stb;
+       FILE *fp;
 
        pipe(p);
 
        pipe(p);
-       if ((stat = dofork(DORETURN)) == 0) {           /* child */
+       if ((s = dofork(DORETURN)) == 0) {              /* child */
                dup2(p[0], 0);
                dup2(p[0], 0);
+               closelog();
                for (i = 3; i < NOFILE; i++)
                        (void) close(i);
                for (i = 3; i < NOFILE; i++)
                        (void) close(i);
-               if ((cp = rindex(MAIL, '/')) != NULL)
+               if ((cp = rindex(_PATH_SENDMAIL, '/')) != NULL)
                        cp++;
                        cp++;
-               else
-                       cp = MAIL;
-               sprintf(buf, "%s@%s", line+1, host);
-               execl(MAIL, cp, buf, 0);
+       else
+                       cp = _PATH_SENDMAIL;
+               sprintf(buf, "%s@%s", user, fromhost);
+               execl(_PATH_SENDMAIL, cp, buf, 0);
                exit(0);
                exit(0);
-       } else if (stat > 0) {                          /* parent */
+       } else if (s > 0) {                             /* parent */
                dup2(p[1], 1);
                dup2(p[1], 1);
-               printf("To: %s\n", line+1);
-               printf("Subject: printer job\n\n");
+               printf("To: %s@%s\n", user, fromhost);
+               printf("Subject: %s printer job \"%s\"\n", printer,
+                       *jobname ? jobname : "<unknown>");
+               printf("Reply-To: root@%s\n\n", host);
                printf("Your printer job ");
                if (*jobname)
                        printf("(%s) ", jobname);
                switch (bombed) {
                printf("Your printer job ");
                if (*jobname)
                        printf("(%s) ", jobname);
                switch (bombed) {
-               case 0:
+               case OK:
                        printf("\ncompleted successfully\n");
                        printf("\ncompleted successfully\n");
+                       cp = "OK";
                        break;
                default:
                        break;
                default:
-               case 1:
+               case FATALERR:
                        printf("\ncould not be printed\n");
                        printf("\ncould not be printed\n");
+                       cp = "FATALERR";
                        break;
                        break;
-               case 2:
+               case NOACCT:
                        printf("\ncould not be printed without an account on %s\n", host);
                        printf("\ncould not be printed without an account on %s\n", host);
+                       cp = "NOACCT";
+                       break;
+               case FILTERERR:
+                       if (stat(tempfile, &stb) < 0 || stb.st_size == 0 ||
+                           (fp = fopen(tempfile, "r")) == NULL) {
+                               printf("\nhad some errors and may not have printed\n");
+                               break;
+                       }
+                       printf("\nhad the following errors and may not have printed:\n");
+                       while ((i = getc(fp)) != EOF)
+                               putchar(i);
+                       (void) fclose(fp);
+                       cp = "FILTERERR";
                        break;
                        break;
+               case ACCESS:
+                       printf("\nwas not printed because it was not linked to the original file\n");
+                       cp = "ACCESS";
                }
                fflush(stdout);
                (void) close(1);
        }
        (void) close(p[0]);
        (void) close(p[1]);
                }
                fflush(stdout);
                (void) close(1);
        }
        (void) close(p[0]);
        (void) close(p[1]);
-       wait(&stat);
+       wait(NULL);
+       syslog(LOG_INFO, "mail sent to user %s about job %s on printer %s (%s)",
+               user, *jobname ? jobname : "<unknown>", printer, cp);
 }
 
 /*
  * dofork - fork with retries on failure
  */
 }
 
 /*
  * dofork - fork with retries on failure
  */
-static
+static int
 dofork(action)
        int action;
 {
 dofork(action)
        int action;
 {
@@ -833,13 +1116,13 @@ dofork(action)
                        setuid(DU);
                return(pid);
        }
                        setuid(DU);
                return(pid);
        }
-       log("can't fork");
+       syslog(LOG_ERR, "can't fork");
 
        switch (action) {
        case DORETURN:
                return (-1);
        default:
 
        switch (action) {
        case DORETURN:
                return (-1);
        default:
-               log("bad action (%d) to dofork", action);
+               syslog(LOG_ERR, "bad action (%d) to dofork", action);
                /*FALL THRU*/
        case DOABORT:
                exit(1);
                /*FALL THRU*/
        case DOABORT:
                exit(1);
@@ -848,145 +1131,133 @@ dofork(action)
 }
 
 /*
 }
 
 /*
- * Cleanup child processes when a SIGINT is caught.
+ * Kill child processes to abort current job.
  */
  */
-static
-onintr()
+static void
+abortpr(signo)
+       int signo;
 {
 {
+       (void) unlink(tempfile);
        kill(0, SIGINT);
        if (ofilter > 0)
                kill(ofilter, SIGCONT);
        kill(0, SIGINT);
        if (ofilter > 0)
                kill(ofilter, SIGCONT);
-       while (wait(0) > 0)
+       while (wait(NULL) > 0)
                ;
        exit(0);
 }
 
                ;
        exit(0);
 }
 
-static
+static void
 init()
 {
        int status;
 init()
 {
        int status;
+       char *s;
 
 
-       if ((status = pgetent(line, printer)) < 0) {
-               log("can't open printer description file");
+       if ((status = cgetent(&bp, printcapdb, printer)) == -2) {
+               syslog(LOG_ERR, "can't open printer description file");
                exit(1);
                exit(1);
-       } else if (status == 0) {
-               log("unknown printer");
+       } else if (status == -1) {
+               syslog(LOG_ERR, "unknown printer: %s", printer);
                exit(1);
                exit(1);
-       }
-       if ((LP = pgetstr("lp", &bp)) == NULL)
-               LP = DEFDEVLP;
-       if ((RP = pgetstr("rp", &bp)) == NULL)
+       } else if (status == -3)
+               fatal("potential reference loop detected in printcap file");
+
+       if (cgetstr(bp, "lp", &LP) == -1)
+               LP = _PATH_DEFDEVLP;
+       if (cgetstr(bp, "rp", &RP) == -1)
                RP = DEFLP;
                RP = DEFLP;
-       if ((LO = pgetstr("lo", &bp)) == NULL)
+       if (cgetstr(bp, "lo", &LO) == -1)
                LO = DEFLOCK;
                LO = DEFLOCK;
-       if ((ST = pgetstr("st", &bp)) == NULL)
+       if (cgetstr(bp, "st", &ST) == -1)
                ST = DEFSTAT;
                ST = DEFSTAT;
-       if ((LF = pgetstr("lf", &bp)) == NULL)
-               LF = DEFLOGF;
-       if ((SD = pgetstr("sd", &bp)) == NULL)
-               SD = DEFSPOOL;
-       if ((DU = pgetnum("du")) < 0)
+       if (cgetstr(bp, "lf", &LF) == -1)
+               LF = _PATH_CONSOLE;
+       if (cgetstr(bp, "sd", &SD) == -1)
+               SD = _PATH_DEFSPOOL;
+       if (cgetnum(bp, "du", &DU) < 0)
                DU = DEFUID;
                DU = DEFUID;
-       if ((FF = pgetstr("ff", &bp)) == NULL)
+       if (cgetstr(bp,"ff", &FF) == -1)
                FF = DEFFF;
                FF = DEFFF;
-       if ((PW = pgetnum("pw")) < 0)
+       if (cgetnum(bp, "pw", &PW) < 0)
                PW = DEFWIDTH;
        sprintf(&width[2], "%d", PW);
                PW = DEFWIDTH;
        sprintf(&width[2], "%d", PW);
-       if ((PL = pgetnum("pl")) < 0)
+       if (cgetnum(bp, "pl", &PL) < 0)
                PL = DEFLENGTH;
        sprintf(&length[2], "%d", PL);
                PL = DEFLENGTH;
        sprintf(&length[2], "%d", PL);
-       if ((PX = pgetnum("px")) < 0)
+       if (cgetnum(bp,"px", &PX) < 0)
                PX = 0;
        sprintf(&pxwidth[2], "%d", PX);
                PX = 0;
        sprintf(&pxwidth[2], "%d", PX);
-       if ((PY = pgetnum("py")) < 0)
+       if (cgetnum(bp, "py", &PY) < 0)
                PY = 0;
        sprintf(&pxlength[2], "%d", PY);
                PY = 0;
        sprintf(&pxlength[2], "%d", PY);
-       RM = pgetstr("rm", &bp);
-       AF = pgetstr("af", &bp);
-       OF = pgetstr("of", &bp);
-       IF = pgetstr("if", &bp);
-       RF = pgetstr("rf", &bp);
-       TF = pgetstr("tf", &bp);
-       DF = pgetstr("df", &bp);
-       GF = pgetstr("gf", &bp);
-       VF = pgetstr("vf", &bp);
-       CF = pgetstr("cf", &bp);
-       TR = pgetstr("tr", &bp);
-       RS = pgetflag("rs");
-       SF = pgetflag("sf");
-       SH = pgetflag("sh");
-       SB = pgetflag("sb");
-       RW = pgetflag("rw");
-       BR = pgetnum("br");
-       if ((FC = pgetnum("fc")) < 0)
+       cgetstr(bp, "rm", &RM);
+       if (s = checkremote())
+               syslog(LOG_WARNING, s);
+
+       cgetstr(bp, "af", &AF);
+       cgetstr(bp, "of", &OF);
+       cgetstr(bp, "if", &IF);
+       cgetstr(bp, "rf", &RF);
+       cgetstr(bp, "tf", &TF);
+       cgetstr(bp, "nf", &NF);
+       cgetstr(bp, "df", &DF);
+       cgetstr(bp, "gf", &GF);
+       cgetstr(bp, "vf", &VF);
+       cgetstr(bp, "cf", &CF);
+       cgetstr(bp, "tr", &TR);
+
+       RS = (cgetcap(bp, "rs", ':') != NULL);
+       SF = (cgetcap(bp, "sf", ':') != NULL);
+       SH = (cgetcap(bp, "sh", ':') != NULL);
+       SB = (cgetcap(bp, "sb", ':') != NULL);
+       HL = (cgetcap(bp, "hl", ':') != NULL);
+       RW = (cgetcap(bp, "rw", ':') != NULL);
+
+       cgetnum(bp, "br", &BR);
+       if (cgetnum(bp, "fc", &FC) < 0)
                FC = 0;
                FC = 0;
-       if ((FS = pgetnum("fs")) < 0)
+       if (cgetnum(bp, "fs", &FS) < 0)
                FS = 0;
                FS = 0;
-       if ((XC = pgetnum("xc")) < 0)
+       if (cgetnum(bp, "xc", &XC) < 0)
                XC = 0;
                XC = 0;
-       if ((XS = pgetnum("xs")) < 0)
+       if (cgetnum(bp, "xs", &XS) < 0)
                XS = 0;
                XS = 0;
-       tof = !pgetflag("fo");
+
+       tof = (cgetcap(bp, "fo", ':') == NULL);
 }
 
 /*
  * Acquire line printer or remote connection.
  */
 }
 
 /*
  * Acquire line printer or remote connection.
  */
-static
+static void
 openpr()
 {
 openpr()
 {
-       register int i, n;
+       register int i;
+       char *cp;
 
 
-       if (*LP) {
-               for (i = 1; ; i = i < 32 ? i << 1 : i) {
-                       pfd = open(LP, RW ? O_RDWR : O_WRONLY);
-                       if (pfd >= 0)
-                               break;
-                       if (errno == ENOENT) {
-                               log("cannot open %s", LP);
-                               exit(1);
-                       }
-                       if (i == 1)
-                               status("waiting for %s to become ready (offline ?)", printer);
-                       sleep(i);
-               }
-               if (isatty(pfd))
-                       setty();
-               status("%s is ready and printing", printer);
-       } else if (RM != NULL) {
-               for (i = 1; ; i = i < 512 ? i << 1 : i) {
-                       pfd = getport(RM);
-                       if (pfd >= 0) {
-                               (void) sprintf(line, "\2%s\n", RP);
-                               n = strlen(line);
-                               if (write(pfd, line, n) != n)
-                                       break;
-                               if (noresponse())
-                                       (void) close(pfd);
-                               else
-                                       break;
-                       }
-                       if (i == 1)
-                               status("waiting for %s to come up", RM);
-                       sleep(i);
-               }
-               status("sending to %s", RM);
-               remote = 1;
+       if (!remote && *LP) {
+               if (cp = index(LP, '@'))
+                       opennet(cp);
+               else
+                       opentty();
+       } else if (remote) {
+               openrem();
        } else {
        } else {
-               log("no line printer device or remote machine name");
+               syslog(LOG_ERR, "%s: no line printer device or host name",
+                       printer);
                exit(1);
        }
                exit(1);
        }
+
        /*
         * Start up an output filter, if needed.
         */
        /*
         * Start up an output filter, if needed.
         */
-       if (OF) {
+       if (!remote && OF) {
                int p[2];
                int p[2];
-               char *cp;
 
                pipe(p);
                if ((ofilter = dofork(DOABORT)) == 0) { /* child */
                        dup2(p[0], 0);          /* pipe is std in */
                        dup2(pfd, 1);           /* printer is std out */
 
                pipe(p);
                if ((ofilter = dofork(DOABORT)) == 0) { /* child */
                        dup2(p[0], 0);          /* pipe is std in */
                        dup2(pfd, 1);           /* printer is std out */
+                       closelog();
                        for (i = 3; i < NOFILE; i++)
                                (void) close(i);
                        if ((cp = rindex(OF, '/')) == NULL)
                        for (i = 3; i < NOFILE; i++)
                                (void) close(i);
                        if ((cp = rindex(OF, '/')) == NULL)
@@ -994,7 +1265,7 @@ openpr()
                        else
                                cp++;
                        execl(OF, cp, width, length, 0);
                        else
                                cp++;
                        execl(OF, cp, width, length, 0);
-                       log("can't execl output filter %s", OF);
+                       syslog(LOG_ERR, "%s: %s: %m", printer, OF);
                        exit(1);
                }
                (void) close(p[0]);             /* close input side */
                        exit(1);
                }
                (void) close(p[0]);             /* close input side */
@@ -1005,6 +1276,115 @@ openpr()
        }
 }
 
        }
 }
 
+/*
+ * Printer connected directly to the network
+ * or to a terminal server on the net
+ */
+static void
+opennet(cp)
+       char *cp;
+{
+       register int i;
+       int resp, port;
+       char save_ch;
+
+       save_ch = *cp;
+       *cp = '\0';
+       port = atoi(LP);
+       if (port <= 0) {
+               syslog(LOG_ERR, "%s: bad port number: %s", printer, LP);
+               exit(1);
+       }
+       *cp++ = save_ch;
+
+       for (i = 1; ; i = i < 256 ? i << 1 : i) {
+               resp = -1;
+               pfd = getport(cp, port);
+               if (pfd < 0 && errno == ECONNREFUSED)
+                       resp = 1;
+               else if (pfd >= 0) {
+                       /*
+                        * need to delay a bit for rs232 lines
+                        * to stabilize in case printer is
+                        * connected via a terminal server
+                        */
+                       delay(500);
+                       break;
+               }
+               if (i == 1) {
+                  if (resp < 0)
+                       pstatus("waiting for %s to come up", LP);
+                  else
+                       pstatus("waiting for access to printer on %s", LP);
+               }
+               sleep(i);
+       }
+       pstatus("sending to %s port %d", cp, port);
+}
+
+/*
+ * Printer is connected to an RS232 port on this host
+ */
+static void
+opentty()
+{
+       register int i;
+       int resp, port;
+
+       for (i = 1; ; i = i < 32 ? i << 1 : i) {
+               pfd = open(LP, RW ? O_RDWR : O_WRONLY);
+               if (pfd >= 0) {
+                       delay(500);
+                       break;
+               }
+               if (errno == ENOENT) {
+                       syslog(LOG_ERR, "%s: %m", LP);
+                       exit(1);
+               }
+               if (i == 1)
+                       pstatus("waiting for %s to become ready (offline ?)",
+                               printer);
+               sleep(i);
+       }
+       if (isatty(pfd))
+               setty();
+       pstatus("%s is ready and printing", printer);
+}
+
+/*
+ * Printer is on a remote host
+ */
+static void
+openrem()
+{
+       register int i, n;
+       int resp, port;
+
+       for (i = 1; ; i = i < 256 ? i << 1 : i) {
+               resp = -1;
+               pfd = getport(RM, 0);
+               if (pfd >= 0) {
+                       (void) sprintf(line, "\2%s\n", RP);
+                       n = strlen(line);
+                       if (write(pfd, line, n) == n &&
+                           (resp = response()) == '\0')
+                               break;
+                       (void) close(pfd);
+               }
+               if (i == 1) {
+                       if (resp < 0)
+                               pstatus("waiting for %s to come up", RM);
+                       else {
+                               pstatus("waiting for queue to be enabled on %s",
+                                       RM);
+                               i = 256;
+                       }
+               }
+               sleep(i);
+       }
+       pstatus("sending to %s", RM);
+}
+
 struct bauds {
        int     baud;
        int     speed;
 struct bauds {
        int     baud;
        int     speed;
@@ -1030,18 +1410,18 @@ struct bauds {
 /*
  * setup tty lines.
  */
 /*
  * setup tty lines.
  */
-static
+static void
 setty()
 {
        struct sgttyb ttybuf;
        register struct bauds *bp;
 
        if (ioctl(pfd, TIOCEXCL, (char *)0) < 0) {
 setty()
 {
        struct sgttyb ttybuf;
        register struct bauds *bp;
 
        if (ioctl(pfd, TIOCEXCL, (char *)0) < 0) {
-               log("cannot set exclusive-use");
+               syslog(LOG_ERR, "%s: ioctl(TIOCEXCL): %m", printer);
                exit(1);
        }
        if (ioctl(pfd, TIOCGETP, (char *)&ttybuf) < 0) {
                exit(1);
        }
        if (ioctl(pfd, TIOCGETP, (char *)&ttybuf) < 0) {
-               log("cannot get tty parameters");
+               syslog(LOG_ERR, "%s: ioctl(TIOCGETP): %m", printer);
                exit(1);
        }
        if (BR > 0) {
                exit(1);
        }
        if (BR > 0) {
@@ -1049,47 +1429,64 @@ setty()
                        if (BR == bp->baud)
                                break;
                if (!bp->baud) {
                        if (BR == bp->baud)
                                break;
                if (!bp->baud) {
-                       log("illegal baud rate %d", BR);
+                       syslog(LOG_ERR, "%s: illegal baud rate %d", printer, BR);
                        exit(1);
                }
                ttybuf.sg_ispeed = ttybuf.sg_ospeed = bp->speed;
        }
                        exit(1);
                }
                ttybuf.sg_ispeed = ttybuf.sg_ospeed = bp->speed;
        }
-       if (FC)
-               ttybuf.sg_flags &= ~FC;
-       if (FS)
-               ttybuf.sg_flags |= FS;
+       ttybuf.sg_flags &= ~FC;
+       ttybuf.sg_flags |= FS;
        if (ioctl(pfd, TIOCSETP, (char *)&ttybuf) < 0) {
        if (ioctl(pfd, TIOCSETP, (char *)&ttybuf) < 0) {
-               log("cannot set tty parameters");
+               syslog(LOG_ERR, "%s: ioctl(TIOCSETP): %m", printer);
                exit(1);
        }
        if (XC) {
                if (ioctl(pfd, TIOCLBIC, &XC) < 0) {
                exit(1);
        }
        if (XC) {
                if (ioctl(pfd, TIOCLBIC, &XC) < 0) {
-                       log("cannot set local tty parameters");
+                       syslog(LOG_ERR, "%s: ioctl(TIOCLBIC): %m", printer);
                        exit(1);
                }
        }
        if (XS) {
                if (ioctl(pfd, TIOCLBIS, &XS) < 0) {
                        exit(1);
                }
        }
        if (XS) {
                if (ioctl(pfd, TIOCLBIS, &XS) < 0) {
-                       log("cannot set local tty parameters");
+                       syslog(LOG_ERR, "%s: ioctl(TIOCLBIS): %m", printer);
                        exit(1);
                }
        }
 }
 
                        exit(1);
                }
        }
 }
 
-/*VARARGS1*/
-static
-status(msg, a1, a2, a3)
+#if __STDC__
+#include <stdarg.h>
+#else
+#include <varargs.h>
+#endif
+
+static void
+#if __STDC__
+pstatus(const char *msg, ...)
+#else
+pstatus(msg, va_alist)
        char *msg;
        char *msg;
+        va_dcl
+#endif
 {
        register int fd;
        char buf[BUFSIZ];
 {
        register int fd;
        char buf[BUFSIZ];
+       va_list ap;
+#if __STDC__
+       va_start(ap, msg);
+#else
+       va_start(ap);
+#endif
 
        umask(0);
        fd = open(ST, O_WRONLY|O_CREAT, 0664);
 
        umask(0);
        fd = open(ST, O_WRONLY|O_CREAT, 0664);
-       if (fd < 0 || flock(fd, LOCK_EX) < 0)
-               fatal("cannot create status file");
+       if (fd < 0 || flock(fd, LOCK_EX) < 0) {
+               syslog(LOG_ERR, "%s: %s: %m", printer, ST);
+               exit(1);
+       }
        ftruncate(fd, 0);
        ftruncate(fd, 0);
-       sprintf(buf, msg, a1, a2, a3);
+       (void)vsnprintf(buf, sizeof(buf), msg, ap);
+       va_end(ap);
        strcat(buf, "\n");
        (void) write(fd, buf, strlen(buf));
        (void) close(fd);
        strcat(buf, "\n");
        (void) write(fd, buf, strlen(buf));
        (void) close(fd);