BSD 4_4_Lite2 release
[unix-history] / usr / src / usr.sbin / lpr / lpd / printjob.c
index 4d75a90..2d17619 100644 (file)
@@ -1,14 +1,48 @@
 /*
 /*
- * Copyright (c) 1983 Regents of the University of California.
- * All rights reserved.
+ * Copyright (c) 1983, 1993
+ *     The Regents of the University of California.  All rights reserved.
  *
  *
- * %sccs.include.redist.c%
+ *
+ * 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
  */
 
 #ifndef lint
-static char sccsid[] = "@(#)printjob.c 5.12 (Berkeley) %G%";
+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 */
 
 #endif /* not lint */
 
+
 /*
  * printjob -- print jobs in the queue.
  *
 /*
  * printjob -- print jobs in the queue.
  *
@@ -16,8 +50,27 @@ static char sccsid[] = "@(#)printjob.c       5.12 (Berkeley) %G%";
  *     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 "pathnames.h"
+#include "extern.h"
 
 #define DORETURN       0       /* absorb fork error */
 #define DOABORT                1       /* abort if dofork fails */
 
 #define DORETURN       0       /* absorb fork error */
 #define DOABORT                1       /* abort if dofork fails */
@@ -33,40 +86,60 @@ static char sccsid[] = "@(#)printjob.c      5.12 (Berkeley) %G%";
 #define        FILTERERR       3
 #define        ACCESS          4
 
 #define        FILTERERR       3
 #define        ACCESS          4
 
-char   title[80];              /* ``pr'' title */
-FILE   *cfp;                   /* control file */
-int    pfd;                    /* printer file descriptor */
-int    ofd;                    /* output filter file descriptor */
-int    lfd;                    /* lock file descriptor */
-int    pid;                    /* pid of lpd process */
-int    prchild;                /* id of pr process */
-int    child;                  /* id of any filters */
-int    ofilter;                /* id of output filter, if any */
-int    tof;                    /* true if at top of form */
-int    remote;                 /* true if sending files to remote */
-dev_t  fdev;                   /* device of file pointed to by symlink */
-ino_t  fino;                   /* inode of file pointed to by symlink */
-
-char   fromhost[32];           /* user's host machine */
-char   logname[32];            /* user's login name */
-char   jobname[100];           /* job or file name */
-char   class[32];              /* classification field */
-char   width[10] = "-w";       /* page width in characters */
-char   length[10] = "-l";      /* page length in lines */
-char   pxwidth[10] = "-x";     /* page width in pixels */
-char   pxlength[10] = "-y";    /* page length in pixels */
-char   indent[10] = "-i0";     /* indentation size in characters */
-char   tempfile[] = "errsXXXXXX"; /* file name for filter output */
-
+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    class[32];              /* classification field */
+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    logname[32];            /* user's login name */
+static char    pxlength[10] = "-y";    /* page length in pixels */
+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;
-       int count = 0;
-       extern int abortpr();
+       off_t pidoff;
+       int errcnt, count = 0;
 
        init();                                 /* set up capabilities */
        (void) write(1, "", 1);                 /* ack that daemon is started */
 
        init();                                 /* set up capabilities */
        (void) write(1, "", 1);                 /* ack that daemon is started */
@@ -139,6 +212,7 @@ 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);
        restart:
                (void) lseek(lfd, pidoff, 0);
                (void) sprintf(line, "%s\n", q->q_name);
@@ -169,12 +243,13 @@ again:
                }
                if (i == OK)            /* file ok and printed */
                        count++;
                }
                if (i == OK)            /* file ok and printed */
                        count++;
-               else if (i == REPRINT) { /* try reprinting the job */
+               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);
                        syslog(LOG_INFO, "restarting %s", printer);
                        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;
                        }
                                        ;
                                ofilter = 0;
                        }
@@ -183,6 +258,17 @@ again:
                                syslog(LOG_WARNING, "%s: %s: %m", printer, LO);
                        openpr();               /* try to reopen printer */
                        goto restart;
                                syslog(LOG_WARNING, "%s: %s: %m", printer, LO);
                        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);
@@ -220,6 +306,7 @@ char ifonts[4][40] = {
  * 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.
  */
+static int
 printit(file)
        char *file;
 {
 printit(file)
        char *file;
 {
@@ -239,7 +326,7 @@ printit(file)
         */
        for (i = 0; i < 4; i++)
                strcpy(fonts[i], ifonts[i]);
         */
        for (i = 0; i < 4; i++)
                strcpy(fonts[i], ifonts[i]);
-       strcpy(width+2, "0");
+       sprintf(&width[2], "%d", PW);
        strcpy(indent+2, "0");
 
        /*
        strcpy(indent+2, "0");
 
        /*
@@ -257,6 +344,7 @@ 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)
         *              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)
@@ -291,7 +379,7 @@ printit(file)
                case 'P':
                        strncpy(logname, line+1, sizeof(logname)-1);
                        if (RS) {                       /* restricted */
                case 'P':
                        strncpy(logname, line+1, sizeof(logname)-1);
                        if (RS) {                       /* restricted */
-                               if (getpwnam(logname) == (struct passwd *)0) {
+                               if (getpwnam(logname) == NULL) {
                                        bombed = NOACCT;
                                        sendmail(line+1, bombed);
                                        goto pass2;
                                        bombed = NOACCT;
                                        sendmail(line+1, bombed);
                                        goto pass2;
@@ -371,6 +459,7 @@ printit(file)
                case 'N':
                case 'U':
                case 'M':
                case 'N':
                case 'U':
                case 'M':
+               case 'R':
                        continue;
                }
 
                        continue;
                }
 
@@ -411,6 +500,7 @@ pass2:
  * Note: all filters take stdin as the file, stdout as the printer,
  * stderr as the log file, and must not ignore SIGINT.
  */
  * Note: all filters take stdin as the file, stdout as the printer,
  * stderr as the log file, and must not ignore SIGINT.
  */
+static int
 print(format, file)
        int format;
        char *file;
 print(format, file)
        int format;
        char *file;
@@ -465,6 +555,7 @@ 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);
                        execl(_PATH_PR, "pr", width, length,
                        for (n = 3; n < NOFILE; n++)
                                (void) close(n);
                        execl(_PATH_PR, "pr", width, length,
@@ -511,7 +602,8 @@ print(format, file)
                } else {
                        for (n = 0; n < 4; n++) {
                                if (fonts[n][0] != '/')
                } else {
                        for (n = 0; n < 4; n++) {
                                if (fonts[n][0] != '/')
-                                       (void) write(fo, _PATH_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) write(fo, fonts[n], strlen(fonts[n]));
                                (void) write(fo, "\n", 1);
                        }
@@ -546,6 +638,13 @@ print(format, file)
                        printer, format);
                return(ERROR);
        }
                        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]++;
        else
        if ((av[0] = rindex(prog, '/')) != NULL)
                av[0]++;
        else
@@ -559,12 +658,14 @@ print(format, file)
        fo = pfd;
        if (ofilter > 0) {              /* stop output filter */
                write(ofd, "\031\1", 2);
        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);
-                       syslog(LOG_WARNING, "%s: output filter died (%d)",
-                               printer, status.w_retcode);
+                       syslog(LOG_WARNING,
+                               "%s: output filter died (retcode=%d termsig=%d)",
+                               printer, status.w_retcode, status.w_termsig);
                        return(REPRINT);
                }
                stopped++;
                        return(REPRINT);
                }
                stopped++;
@@ -576,6 +677,7 @@ start:
                n = open(tempfile, O_WRONLY|O_CREAT|O_TRUNC, 0664);
                if (n >= 0)
                        dup2(n, 2);
                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);
@@ -586,7 +688,7 @@ start:
        if (child < 0)
                status.w_retcode = 100;
        else
        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;
                        ;
        child = 0;
        prchild = 0;
@@ -600,15 +702,13 @@ start:
 
        /* Copy filter output to "lf" logfile */
        if (fp = fopen(tempfile, "r")) {
 
        /* Copy filter output to "lf" logfile */
        if (fp = fopen(tempfile, "r")) {
-               char tbuf[512];
-
                while (fgets(buf, sizeof(buf), fp))
                        fputs(buf, stderr);
                while (fgets(buf, sizeof(buf), fp))
                        fputs(buf, stderr);
-               close(fp);
+               fclose(fp);
        }
 
        if (!WIFEXITED(status)) {
        }
 
        if (!WIFEXITED(status)) {
-               syslog(LOG_WARNING, "%s: Daemon filter '%c' terminated (%d)",
+               syslog(LOG_WARNING, "%s: filter '%c' terminated (termsig=%d)",
                        printer, format, status.w_termsig);
                return(ERROR);
        }
                        printer, format, status.w_termsig);
                return(ERROR);
        }
@@ -618,11 +718,12 @@ start:
                return(OK);
        case 1:
                return(REPRINT);
                return(OK);
        case 1:
                return(REPRINT);
-       default:
-               syslog(LOG_WARNING, "%s: Daemon filter '%c' exited (%d)",
-                       printer, format, status.w_retcode);
        case 2:
                return(ERROR);
        case 2:
                return(ERROR);
+       default:
+               syslog(LOG_WARNING, "%s: filter '%c' exited (retcode=%d)",
+                       printer, format, status.w_retcode);
+               return(FILTERERR);
        }
 }
 
        }
 }
 
@@ -631,6 +732,7 @@ 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 int
 sendit(file)
        char *file;
 {
 sendit(file)
        char *file;
 {
@@ -716,8 +818,10 @@ sendit(file)
  * 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 int
 sendfile(type, file)
 sendfile(type, file)
-       char type, *file;
+       int type;
+       char *file;
 {
        register int f, i, amt;
        struct stat stb;
 {
        register int f, i, amt;
        struct stat stb;
@@ -734,7 +838,7 @@ sendfile(type, file)
        if ((stb.st_mode & S_IFMT) == S_IFLNK && fstat(f, &stb) == 0 &&
            (stb.st_dev != fdev || stb.st_ino != fino))
                return(ACCESS);
        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%d %s\n", type, stb.st_size, file);
+       (void) sprintf(buf, "%c%ld %s\n", type, (long)stb.st_size, file);
        amt = strlen(buf);
        for (i = 0;  ; i++) {
                if (write(pfd, buf, amt) != amt ||
        amt = strlen(buf);
        for (i = 0;  ; i++) {
                if (write(pfd, buf, amt) != amt ||
@@ -744,14 +848,14 @@ sendfile(type, file)
                } else if (resp == '\0')
                        break;
                if (i == 0)
                } else if (resp == '\0')
                        break;
                if (i == 0)
-                       status("no space on remote; waiting for queue to drain");
+                       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)
                if (i == 10)
                        syslog(LOG_ALERT, "%s: can't send to %s; queue full",
                                printer, RM);
                sleep(5 * 60);
        }
        if (i)
-               status("sending to %s", RM);
+               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;
@@ -764,6 +868,10 @@ sendfile(type, file)
                        return(REPRINT);
                }
        }
                        return(REPRINT);
                }
        }
+
+
+
+
        (void) close(f);
        if (sizerr) {
                syslog(LOG_INFO, "%s: %s: changed size", printer, file);
        (void) close(f);
        if (sizerr) {
                syslog(LOG_INFO, "%s: %s: changed size", printer, file);
@@ -781,6 +889,7 @@ 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 char
 response()
 {
        char resp;
 response()
 {
        char resp;
@@ -795,6 +904,7 @@ response()
 /*
  * Banner printing stuff
  */
 /*
  * Banner printing stuff
  */
+static void
 banner(name1, name2)
        char *name1, *name2;
 {
 banner(name1, name2)
        char *name1, *name2;
 {
@@ -835,10 +945,11 @@ banner(name1, name2)
        tof = 1;
 }
 
        tof = 1;
 }
 
-char *
+static char *
 scnline(key, p, c)
 scnline(key, p, c)
-       register char key, *p;
-       char c;
+       register int key;
+       register char *p;
+       int c;
 {
        register scnwidth;
 
 {
        register scnwidth;
 
@@ -851,9 +962,10 @@ scnline(key, p, c)
 
 #define TRC(q) (((q)-' ')&0177)
 
 
 #define TRC(q) (((q)-' ')&0177)
 
+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;
@@ -884,8 +996,9 @@ scan_out(scfd, scsp, dlm)
        }
 }
 
        }
 }
 
+static int
 dropit(c)
 dropit(c)
-       char c;
+       int c;
 {
        switch(c) {
 
 {
        switch(c) {
 
@@ -908,6 +1021,7 @@ dropit(c)
  * sendmail ---
  *   tell people about job completion
  */
  * sendmail ---
  *   tell people about job completion
  */
+static void
 sendmail(user, bombed)
        char *user;
        int bombed;
 sendmail(user, bombed)
        char *user;
        int bombed;
@@ -922,11 +1036,12 @@ sendmail(user, bombed)
        pipe(p);
        if ((s = dofork(DORETURN)) == 0) {              /* child */
                dup2(p[0], 0);
        pipe(p);
        if ((s = dofork(DORETURN)) == 0) {              /* child */
                dup2(p[0], 0);
+               closelog();
                for (i = 3; i < NOFILE; i++)
                        (void) close(i);
                if ((cp = rindex(_PATH_SENDMAIL, '/')) != NULL)
                        cp++;
                for (i = 3; i < NOFILE; i++)
                        (void) close(i);
                if ((cp = rindex(_PATH_SENDMAIL, '/')) != NULL)
                        cp++;
-               else
+       else
                        cp = _PATH_SENDMAIL;
                sprintf(buf, "%s@%s", user, fromhost);
                execl(_PATH_SENDMAIL, cp, buf, 0);
                        cp = _PATH_SENDMAIL;
                sprintf(buf, "%s@%s", user, fromhost);
                execl(_PATH_SENDMAIL, cp, buf, 0);
@@ -934,46 +1049,56 @@ sendmail(user, bombed)
        } else if (s > 0) {                             /* parent */
                dup2(p[1], 1);
                printf("To: %s@%s\n", user, fromhost);
        } else if (s > 0) {                             /* parent */
                dup2(p[1], 1);
                printf("To: %s@%s\n", user, fromhost);
-               printf("Subject: printer job\n\n");
+               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) {
                case OK:
                        printf("\ncompleted successfully\n");
                printf("Your printer job ");
                if (*jobname)
                        printf("(%s) ", jobname);
                switch (bombed) {
                case OK:
                        printf("\ncompleted successfully\n");
+                       cp = "OK";
                        break;
                default:
                case FATALERR:
                        printf("\ncould not be printed\n");
                        break;
                default:
                case FATALERR:
                        printf("\ncould not be printed\n");
+                       cp = "FATALERR";
                        break;
                case NOACCT:
                        printf("\ncould not be printed without an account on %s\n", host);
                        break;
                case NOACCT:
                        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) {
                        break;
                case FILTERERR:
                        if (stat(tempfile, &stb) < 0 || stb.st_size == 0 ||
                            (fp = fopen(tempfile, "r")) == NULL) {
-                               printf("\nwas printed but had some errors\n");
+                               printf("\nhad some errors and may not have printed\n");
                                break;
                        }
                                break;
                        }
-                       printf("\nwas printed but had the following errors:\n");
+                       printf("\nhad the following errors and may not have printed:\n");
                        while ((i = getc(fp)) != EOF)
                                putchar(i);
                        (void) fclose(fp);
                        while ((i = getc(fp)) != EOF)
                                putchar(i);
                        (void) fclose(fp);
+                       cp = "FILTERERR";
                        break;
                case ACCESS:
                        printf("\nwas not printed because it was not linked to the original file\n");
                        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(&s);
+       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 int
 dofork(action)
        int action;
 {
 dofork(action)
        int action;
 {
@@ -1008,154 +1133,131 @@ dofork(action)
 /*
  * Kill child processes to abort current job.
  */
 /*
  * Kill child processes to abort current job.
  */
-abortpr()
+static void
+abortpr(signo)
+       int signo;
 {
        (void) unlink(tempfile);
        kill(0, SIGINT);
        if (ofilter > 0)
                kill(ofilter, SIGCONT);
 {
        (void) unlink(tempfile);
        kill(0, SIGINT);
        if (ofilter > 0)
                kill(ofilter, SIGCONT);
-       while (wait(0) > 0)
+       while (wait(NULL) > 0)
                ;
        exit(0);
 }
 
                ;
        exit(0);
 }
 
+static void
 init()
 {
        int status;
        char *s;
 
 init()
 {
        int status;
        char *s;
 
-       if ((status = pgetent(line, printer)) < 0) {
+       if ((status = cgetent(&bp, printcapdb, printer)) == -2) {
                syslog(LOG_ERR, "can't open printer description file");
                exit(1);
                syslog(LOG_ERR, "can't open printer description file");
                exit(1);
-       } else if (status == 0) {
+       } else if (status == -1) {
                syslog(LOG_ERR, "unknown printer: %s", printer);
                exit(1);
                syslog(LOG_ERR, "unknown printer: %s", printer);
                exit(1);
-       }
-       if ((LP = pgetstr("lp", &bp)) == NULL)
+       } else if (status == -3)
+               fatal("potential reference loop detected in printcap file");
+
+       if (cgetstr(bp, "lp", &LP) == -1)
                LP = _PATH_DEFDEVLP;
                LP = _PATH_DEFDEVLP;
-       if ((RP = pgetstr("rp", &bp)) == NULL)
+       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)
+       if (cgetstr(bp, "lf", &LF) == -1)
                LF = _PATH_CONSOLE;
                LF = _PATH_CONSOLE;
-       if ((SD = pgetstr("sd", &bp)) == NULL)
+       if (cgetstr(bp, "sd", &SD) == -1)
                SD = _PATH_DEFSPOOL;
                SD = _PATH_DEFSPOOL;
-       if ((DU = pgetnum("du")) < 0)
+       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);
+       cgetstr(bp, "rm", &RM);
        if (s = checkremote())
                syslog(LOG_WARNING, s);
 
        if (s = checkremote())
                syslog(LOG_WARNING, s);
 
-       AF = pgetstr("af", &bp);
-       OF = pgetstr("of", &bp);
-       IF = pgetstr("if", &bp);
-       RF = pgetstr("rf", &bp);
-       TF = pgetstr("tf", &bp);
-       NF = pgetstr("nf", &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");
-       HL = pgetflag("hl");
-       RW = pgetflag("rw");
-       BR = pgetnum("br");
-       if ((FC = pgetnum("fc")) < 0)
+       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 void
 openpr()
 {
 openpr()
 {
-       register int i, n;
-       int resp;
+       register int i;
+       char *cp;
 
 
-       if (!sendtorem && *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) {
-                               syslog(LOG_ERR, "%s: %m", 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 < 256 ? i << 1 : i) {
-                       resp = -1;
-                       pfd = getport(RM);
-                       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)
-                                       status("waiting for %s to come up", RM);
-                               else {
-                                       status("waiting for queue to be enabled on %s", RM);
-                                       i = 256;
-                               }
-                       }
-                       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 {
                syslog(LOG_ERR, "%s: no line printer device or host name",
                        printer);
                exit(1);
        }
        } else {
                syslog(LOG_ERR, "%s: no line printer device or host name",
                        printer);
                exit(1);
        }
+
        /*
         * Start up an output filter, if needed.
         */
        if (!remote && OF) {
                int p[2];
        /*
         * Start up an output filter, if needed.
         */
        if (!remote && OF) {
                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)
@@ -1174,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;
@@ -1199,6 +1410,7 @@ struct bauds {
 /*
  * setup tty lines.
  */
 /*
  * setup tty lines.
  */
+static void
 setty()
 {
        struct sgttyb ttybuf;
 setty()
 {
        struct sgttyb ttybuf;
@@ -1242,12 +1454,29 @@ setty()
        }
 }
 
        }
 }
 
-/*VARARGS1*/
-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);
@@ -1256,7 +1485,8 @@ status(msg, a1, a2, a3)
                exit(1);
        }
        ftruncate(fd, 0);
                exit(1);
        }
        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);