386BSD 0.1 development
authorWilliam F. Jolitz <wjolitz@soda.berkeley.edu>
Fri, 19 Apr 1991 20:06:33 +0000 (12:06 -0800)
committerWilliam F. Jolitz <wjolitz@soda.berkeley.edu>
Fri, 19 Apr 1991 20:06:33 +0000 (12:06 -0800)
Work on file usr/src/usr.sbin/lpr/common_source/displayq.c
Work on file usr/src/usr.sbin/lpr/common_source/common.c
Work on file usr/src/usr.sbin/lpr/common_source/lp.h
Work on file usr/src/usr.sbin/lpr/common_source/lpc.h
Work on file usr/src/usr.sbin/lpr/common_source/lp.local.h
Work on file usr/src/usr.sbin/lpr/common_source/pathnames.h
Work on file usr/src/usr.sbin/lpr/common_source/rmjob.c
Work on file usr/src/usr.sbin/lpr/common_source/printcap.c
Work on file usr/src/usr.sbin/lpr/common_source/startdaemon.c
Work on file usr/src/usr.sbin/lpr/filters/lpf.c
Work on file usr/src/usr.sbin/lpr/lpc/cmdtab.c
Work on file usr/src/usr.sbin/lpr/lpc/cmds.c
Work on file usr/src/usr.sbin/lpr/lpc/lpc.c
Work on file usr/src/usr.sbin/lpr/lpc/lpc.8
Work on file usr/src/usr.sbin/lpr/lpd/lpd.8
Work on file usr/src/usr.sbin/lpr/lpd/lpd.c
Work on file usr/src/usr.sbin/lpr/lpd/lpdchar.c

Co-Authored-By: Lynne Greer Jolitz <ljolitz@cardio.ucsf.edu>
Synthesized-from: 386BSD-0.1

17 files changed:
usr/src/usr.sbin/lpr/common_source/common.c [new file with mode: 0644]
usr/src/usr.sbin/lpr/common_source/displayq.c [new file with mode: 0644]
usr/src/usr.sbin/lpr/common_source/lp.h [new file with mode: 0644]
usr/src/usr.sbin/lpr/common_source/lp.local.h [new file with mode: 0644]
usr/src/usr.sbin/lpr/common_source/lpc.h [new file with mode: 0644]
usr/src/usr.sbin/lpr/common_source/pathnames.h [new file with mode: 0644]
usr/src/usr.sbin/lpr/common_source/printcap.c [new file with mode: 0644]
usr/src/usr.sbin/lpr/common_source/rmjob.c [new file with mode: 0644]
usr/src/usr.sbin/lpr/common_source/startdaemon.c [new file with mode: 0644]
usr/src/usr.sbin/lpr/filters/lpf.c [new file with mode: 0644]
usr/src/usr.sbin/lpr/lpc/cmds.c [new file with mode: 0644]
usr/src/usr.sbin/lpr/lpc/cmdtab.c [new file with mode: 0644]
usr/src/usr.sbin/lpr/lpc/lpc.8 [new file with mode: 0644]
usr/src/usr.sbin/lpr/lpc/lpc.c [new file with mode: 0644]
usr/src/usr.sbin/lpr/lpd/lpd.8 [new file with mode: 0644]
usr/src/usr.sbin/lpr/lpd/lpd.c [new file with mode: 0644]
usr/src/usr.sbin/lpr/lpd/lpdchar.c [new file with mode: 0644]

diff --git a/usr/src/usr.sbin/lpr/common_source/common.c b/usr/src/usr.sbin/lpr/common_source/common.c
new file mode 100644 (file)
index 0000000..d7b97cd
--- /dev/null
@@ -0,0 +1,309 @@
+/*
+ * Copyright (c) 1983 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 sccsid[] = "@(#)common.c   5.7 (Berkeley) 3/2/91";
+#endif /* not lint */
+
+/*
+ * Routines and data common to all the line printer functions.
+ */
+
+#include "lp.h"
+
+int    DU;             /* daeomon user-id */
+int    MX;             /* maximum number of blocks to copy */
+int    MC;             /* maximum number of copies allowed */
+char   *LP;            /* line printer device name */
+char   *RM;            /* remote machine name */
+char   *RP;            /* remote printer name */
+char   *LO;            /* lock file name */
+char   *ST;            /* status file name */
+char   *SD;            /* spool directory */
+char   *AF;            /* accounting file */
+char   *LF;            /* log file for error messages */
+char   *OF;            /* name of output filter (created once) */
+char   *IF;            /* name of input filter (created per job) */
+char   *RF;            /* name of fortran text filter (per job) */
+char   *TF;            /* name of troff filter (per job) */
+char   *NF;            /* name of ditroff filter (per job) */
+char   *DF;            /* name of tex filter (per job) */
+char   *GF;            /* name of graph(1G) filter (per job) */
+char   *VF;            /* name of vplot filter (per job) */
+char   *CF;            /* name of cifplot filter (per job) */
+char   *PF;            /* name of vrast filter (per job) */
+char   *FF;            /* form feed string */
+char   *TR;            /* trailer string to be output when Q empties */
+short  SC;             /* suppress multiple copies */
+short  SF;             /* suppress FF on each print job */
+short  SH;             /* suppress header page */
+short  SB;             /* short banner instead of normal header */
+short  HL;             /* print header last */
+short  RW;             /* open LP for reading and writing */
+short  PW;             /* page width */
+short  PL;             /* page length */
+short  PX;             /* page width in pixels */
+short  PY;             /* page length in pixels */
+short  BR;             /* baud rate if lp is a tty */
+int    FC;             /* flags to clear if lp is a tty */
+int    FS;             /* flags to set if lp is a tty */
+int    XC;             /* flags to clear for local mode */
+int    XS;             /* flags to set for local mode */
+short  RS;             /* restricted to those with local accounts */
+
+char   line[BUFSIZ];
+char   pbuf[BUFSIZ/2]; /* buffer for printcap strings */
+char   *bp = pbuf;     /* pointer into pbuf for pgetent() */
+char   *name;          /* program name */
+char   *printer;       /* printer name */
+char   host[32];       /* host machine name */
+char   *from = host;   /* client's machine name */
+int    sendtorem;      /* are we sending to a remote? */
+
+/*
+ * Create a connection to the remote printer server.
+ * Most of this code comes from rcmd.c.
+ */
+getport(rhost)
+       char *rhost;
+{
+       struct hostent *hp;
+       struct servent *sp;
+       struct sockaddr_in sin;
+       int s, timo = 1, lport = IPPORT_RESERVED - 1;
+       int err;
+
+       /*
+        * Get the host address and port number to connect to.
+        */
+       if (rhost == NULL)
+               fatal("no remote host to connect to");
+       hp = gethostbyname(rhost);
+       if (hp == NULL)
+               fatal("unknown host %s", rhost);
+       sp = getservbyname("printer", "tcp");
+       if (sp == NULL)
+               fatal("printer/tcp: unknown service");
+       bzero((char *)&sin, sizeof(sin));
+       bcopy(hp->h_addr, (caddr_t)&sin.sin_addr, hp->h_length);
+       sin.sin_family = hp->h_addrtype;
+       sin.sin_port = sp->s_port;
+
+       /*
+        * Try connecting to the server.
+        */
+retry:
+       s = rresvport(&lport);
+       if (s < 0)
+               return(-1);
+       if (connect(s, (struct sockaddr *)&sin, sizeof(sin)) < 0) {
+               err = errno;
+               (void) close(s);
+               errno = err;
+               if (errno == EADDRINUSE) {
+                       lport--;
+                       goto retry;
+               }
+               if (errno == ECONNREFUSED && timo <= 16) {
+                       sleep(timo);
+                       timo *= 2;
+                       goto retry;
+               }
+               return(-1);
+       }
+       return(s);
+}
+
+/*
+ * Getline reads a line from the control file cfp, removes tabs, converts
+ *  new-line to null and leaves it in line.
+ * Returns 0 at EOF or the number of characters read.
+ */
+getline(cfp)
+       FILE *cfp;
+{
+       register int linel = 0;
+       register char *lp = line;
+       register c;
+
+       while ((c = getc(cfp)) != '\n') {
+               if (c == EOF)
+                       return(0);
+               if (c == '\t') {
+                       do {
+                               *lp++ = ' ';
+                               linel++;
+                       } while ((linel & 07) != 0);
+                       continue;
+               }
+               *lp++ = c;
+               linel++;
+       }
+       *lp++ = '\0';
+       return(linel);
+}
+
+/*
+ * Scan the current directory and make a list of daemon files sorted by
+ * creation time.
+ * Return the number of entries and a pointer to the list.
+ */
+getq(namelist)
+       struct queue *(*namelist[]);
+{
+       register struct direct *d;
+       register struct queue *q, **queue;
+       register int nitems;
+       struct stat stbuf;
+       DIR *dirp;
+       int arraysz;
+       static int compar();
+
+       if ((dirp = opendir(SD)) == NULL)
+               return(-1);
+       if (fstat(dirp->dd_fd, &stbuf) < 0)
+               goto errdone;
+
+       /*
+        * Estimate the array size by taking the size of the directory file
+        * and dividing it by a multiple of the minimum size entry. 
+        */
+       arraysz = (stbuf.st_size / 24);
+       queue = (struct queue **)malloc(arraysz * sizeof(struct queue *));
+       if (queue == NULL)
+               goto errdone;
+
+       nitems = 0;
+       while ((d = readdir(dirp)) != NULL) {
+               if (d->d_name[0] != 'c' || d->d_name[1] != 'f')
+                       continue;       /* daemon control files only */
+               if (stat(d->d_name, &stbuf) < 0)
+                       continue;       /* Doesn't exist */
+               q = (struct queue *)malloc(sizeof(time_t)+strlen(d->d_name)+1);
+               if (q == NULL)
+                       goto errdone;
+               q->q_time = stbuf.st_mtime;
+               strcpy(q->q_name, d->d_name);
+               /*
+                * Check to make sure the array has space left and
+                * realloc the maximum size.
+                */
+               if (++nitems > arraysz) {
+                       queue = (struct queue **)realloc((char *)queue,
+                               (stbuf.st_size/12) * sizeof(struct queue *));
+                       if (queue == NULL)
+                               goto errdone;
+               }
+               queue[nitems-1] = q;
+       }
+       closedir(dirp);
+       if (nitems)
+               qsort(queue, nitems, sizeof(struct queue *), compar);
+       *namelist = queue;
+       return(nitems);
+
+errdone:
+       closedir(dirp);
+       return(-1);
+}
+
+/*
+ * Compare modification times.
+ */
+static
+compar(p1, p2)
+       register struct queue **p1, **p2;
+{
+       if ((*p1)->q_time < (*p2)->q_time)
+               return(-1);
+       if ((*p1)->q_time > (*p2)->q_time)
+               return(1);
+       return(0);
+}
+
+/*
+ * Figure out whether the local machine is the same
+ * as the remote machine (RM) entry (if it exists).
+ */
+char *
+checkremote()
+{
+       char name[MAXHOSTNAMELEN];
+       register struct hostent *hp;
+       static char errbuf[128];
+
+       sendtorem = 0;  /* assume printer is local */
+       if (RM != (char *)NULL) {
+               /* get the official name of the local host */
+               gethostname(name, sizeof(name));
+               name[sizeof(name)-1] = '\0';
+               hp = gethostbyname(name);
+               if (hp == (struct hostent *) NULL) {
+                   (void) sprintf(errbuf,
+                       "unable to get official name for local machine %s",
+                       name);
+                   return errbuf;
+               } else (void) strcpy(name, hp->h_name);
+
+               /* get the official name of RM */
+               hp = gethostbyname(RM);
+               if (hp == (struct hostent *) NULL) {
+                   (void) sprintf(errbuf,
+                       "unable to get official name for remote machine %s",
+                       RM);
+                   return errbuf;
+               }
+
+               /*
+                * if the two hosts are not the same,
+                * then the printer must be remote.
+                */
+               if (strcmp(name, hp->h_name) != 0)
+                       sendtorem = 1;
+       }
+       return (char *)0;
+}
+
+/*VARARGS1*/
+fatal(msg, a1, a2, a3)
+       char *msg;
+{
+       if (from != host)
+               printf("%s: ", host);
+       printf("%s: ", name);
+       if (printer)
+               printf("%s: ", printer);
+       printf(msg, a1, a2, a3);
+       putchar('\n');
+       exit(1);
+}
diff --git a/usr/src/usr.sbin/lpr/common_source/displayq.c b/usr/src/usr.sbin/lpr/common_source/displayq.c
new file mode 100644 (file)
index 0000000..df58c00
--- /dev/null
@@ -0,0 +1,425 @@
+/*
+ * Copyright (c) 1983 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 sccsid[] = "@(#)displayq.c 5.13 (Berkeley) 6/1/90";
+#endif /* not lint */
+
+/*
+ * Routines to display the state of the queue.
+ */
+
+#include "lp.h"
+#include "pathnames.h"
+
+#define JOBCOL 40              /* column for job # in -l format */
+#define OWNCOL 7               /* start of Owner column in normal */
+#define SIZCOL 62              /* start of Size column in normal */
+
+/*
+ * Stuff for handling job specifications
+ */
+extern char    *user[];        /* users to process */
+extern int     users;          /* # of users in user array */
+extern int     requ[];         /* job number of spool entries */
+extern int     requests;       /* # of spool requests */
+
+int    lflag;          /* long output option */
+char   current[40];    /* current file being printed */
+int    garbage;        /* # of garbage cf files */
+int    rank;           /* order to be printed (-1=none, 0=active) */
+long   totsize;        /* total print job size in bytes */
+int    first;          /* first file in ``files'' column? */
+int    col;            /* column on screen */
+char   file[132];      /* print file name */
+
+char   *head0 = "Rank   Owner      Job  Files";
+char   *head1 = "Total Size\n";
+
+/*
+ * Display the current state of the queue. Format = 1 if long format.
+ */
+displayq(format)
+       int format;
+{
+       register struct queue *q;
+       register int i, nitems, fd;
+       register char   *cp;
+       struct queue **queue;
+       struct stat statb;
+       FILE *fp;
+       char c;
+
+       lflag = format;
+       totsize = 0;
+       rank = -1;
+
+       if ((i = pgetent(line, printer)) < 0)
+               fatal("cannot open printer description file");
+       else if (i == 0)
+               fatal("unknown printer");
+       if ((LP = pgetstr("lp", &bp)) == NULL)
+               LP = _PATH_DEFDEVLP;
+       if ((RP = pgetstr("rp", &bp)) == NULL)
+               RP = DEFLP;
+       if ((SD = pgetstr("sd", &bp)) == NULL)
+               SD = _PATH_DEFSPOOL;
+       if ((LO = pgetstr("lo", &bp)) == NULL)
+               LO = DEFLOCK;
+       if ((ST = pgetstr("st", &bp)) == NULL)
+               ST = DEFSTAT;
+       RM = pgetstr("rm", &bp);
+       if (cp = checkremote())
+               printf("Warning: %s\n", cp);
+
+       /*
+        * Print out local queue
+        * Find all the control files in the spooling directory
+        */
+       if (chdir(SD) < 0)
+               fatal("cannot chdir to spooling directory");
+       if ((nitems = getq(&queue)) < 0)
+               fatal("cannot examine spooling area\n");
+       if (stat(LO, &statb) >= 0) {
+               if (statb.st_mode & 0100) {
+                       if (sendtorem)
+                               printf("%s: ", host);
+                       printf("Warning: %s is down: ", printer);
+                       fd = open(ST, O_RDONLY);
+                       if (fd >= 0) {
+                               (void) flock(fd, LOCK_SH);
+                               while ((i = read(fd, line, sizeof(line))) > 0)
+                                       (void) fwrite(line, 1, i, stdout);
+                               (void) close(fd);       /* unlocks as well */
+                       } else
+                               putchar('\n');
+               }
+               if (statb.st_mode & 010) {
+                       if (sendtorem)
+                               printf("%s: ", host);
+                       printf("Warning: %s queue is turned off\n", printer);
+               }
+       }
+
+       if (nitems) {
+               fp = fopen(LO, "r");
+               if (fp == NULL)
+                       warn();
+               else {
+                       /* get daemon pid */
+                       cp = current;
+                       while ((*cp = getc(fp)) != EOF && *cp != '\n')
+                               cp++;
+                       *cp = '\0';
+                       i = atoi(current);
+                       if (i <= 0 || kill(i, 0) < 0)
+                               warn();
+                       else {
+                               /* read current file name */
+                               cp = current;
+                               while ((*cp = getc(fp)) != EOF && *cp != '\n')
+                                       cp++;
+                               *cp = '\0';
+                               /*
+                                * Print the status file.
+                                */
+                               if (sendtorem)
+                                       printf("%s: ", host);
+                               fd = open(ST, O_RDONLY);
+                               if (fd >= 0) {
+                                       (void) flock(fd, LOCK_SH);
+                                       while ((i = read(fd, line, sizeof(line))) > 0)
+                                               (void) fwrite(line, 1, i, stdout);
+                                       (void) close(fd);       /* unlocks as well */
+                               } else
+                                       putchar('\n');
+                       }
+                       (void) fclose(fp);
+               }
+               /*
+                * Now, examine the control files and print out the jobs to
+                * be done for each user.
+                */
+               if (!lflag)
+                       header();
+               for (i = 0; i < nitems; i++) {
+                       q = queue[i];
+                       inform(q->q_name);
+                       free(q);
+               }
+               free(queue);
+       }
+       if (!sendtorem) {
+               if (nitems == 0)
+                       puts("no entries");
+               return;
+       }
+
+       /*
+        * Print foreign queue
+        * Note that a file in transit may show up in either queue.
+        */
+       if (nitems)
+               putchar('\n');
+       (void) sprintf(line, "%c%s", format + '\3', RP);
+       cp = line;
+       for (i = 0; i < requests; i++) {
+               cp += strlen(cp);
+               (void) sprintf(cp, " %d", requ[i]);
+       }
+       for (i = 0; i < users; i++) {
+               cp += strlen(cp);
+               *cp++ = ' ';
+               (void) strcpy(cp, user[i]);
+       }
+       strcat(line, "\n");
+       fd = getport(RM);
+       if (fd < 0) {
+               if (from != host)
+                       printf("%s: ", host);
+               printf("connection to %s is down\n", RM);
+       }
+       else {
+               i = strlen(line);
+               if (write(fd, line, i) != i)
+                       fatal("Lost connection");
+               while ((i = read(fd, line, sizeof(line))) > 0)
+                       (void) fwrite(line, 1, i, stdout);
+               (void) close(fd);
+       }
+}
+
+/*
+ * Print a warning message if there is no daemon present.
+ */
+warn()
+{
+       if (sendtorem)
+               printf("\n%s: ", host);
+       puts("Warning: no daemon present");
+       current[0] = '\0';
+}
+
+/*
+ * Print the header for the short listing format
+ */
+header()
+{
+       printf(head0);
+       col = strlen(head0)+1;
+       blankfill(SIZCOL);
+       printf(head1);
+}
+
+inform(cf)
+       char *cf;
+{
+       register int j, k;
+       register char *cp;
+       FILE *cfp;
+
+       /*
+        * There's a chance the control file has gone away
+        * in the meantime; if this is the case just keep going
+        */
+       if ((cfp = fopen(cf, "r")) == NULL)
+               return;
+
+       if (rank < 0)
+               rank = 0;
+       if (sendtorem || garbage || strcmp(cf, current))
+               rank++;
+       j = 0;
+       while (getline(cfp)) {
+               switch (line[0]) {
+               case 'P': /* Was this file specified in the user's list? */
+                       if (!inlist(line+1, cf)) {
+                               fclose(cfp);
+                               return;
+                       }
+                       if (lflag) {
+                               printf("\n%s: ", line+1);
+                               col = strlen(line+1) + 2;
+                               prank(rank);
+                               blankfill(JOBCOL);
+                               printf(" [job %s]\n", cf+3);
+                       } else {
+                               col = 0;
+                               prank(rank);
+                               blankfill(OWNCOL);
+                               printf("%-10s %-3d  ", line+1, atoi(cf+3));
+                               col += 16;
+                               first = 1;
+                       }
+                       continue;
+               default: /* some format specifer and file name? */
+                       if (line[0] < 'a' || line[0] > 'z')
+                               continue;
+                       if (j == 0 || strcmp(file, line+1) != 0)
+                               (void) strcpy(file, line+1);
+                       j++;
+                       continue;
+               case 'N':
+                       show(line+1, file, j);
+                       file[0] = '\0';
+                       j = 0;
+               }
+       }
+       fclose(cfp);
+       if (!lflag) {
+               blankfill(SIZCOL);
+               printf("%ld bytes\n", totsize);
+               totsize = 0;
+       }
+}
+
+inlist(name, file)
+       char *name, *file;
+{
+       register int *r, n;
+       register char **u, *cp;
+
+       if (users == 0 && requests == 0)
+               return(1);
+       /*
+        * Check to see if it's in the user list
+        */
+       for (u = user; u < &user[users]; u++)
+               if (!strcmp(*u, name))
+                       return(1);
+       /*
+        * Check the request list
+        */
+       for (n = 0, cp = file+3; isdigit(*cp); )
+               n = n * 10 + (*cp++ - '0');
+       for (r = requ; r < &requ[requests]; r++)
+               if (*r == n && !strcmp(cp, from))
+                       return(1);
+       return(0);
+}
+
+show(nfile, file, copies)
+       register char *nfile, *file;
+{
+       if (strcmp(nfile, " ") == 0)
+               nfile = "(standard input)";
+       if (lflag)
+               ldump(nfile, file, copies);
+       else
+               dump(nfile, file, copies);
+}
+
+/*
+ * Fill the line with blanks to the specified column
+ */
+blankfill(n)
+       register int n;
+{
+       while (col++ < n)
+               putchar(' ');
+}
+
+/*
+ * Give the abbreviated dump of the file names
+ */
+dump(nfile, file, copies)
+       char *nfile, *file;
+{
+       register short n, fill;
+       struct stat lbuf;
+
+       /*
+        * Print as many files as will fit
+        *  (leaving room for the total size)
+        */
+        fill = first ? 0 : 2;  /* fill space for ``, '' */
+        if (((n = strlen(nfile)) + col + fill) >= SIZCOL-4) {
+               if (col < SIZCOL) {
+                       printf(" ..."), col += 4;
+                       blankfill(SIZCOL);
+               }
+       } else {
+               if (first)
+                       first = 0;
+               else
+                       printf(", ");
+               printf("%s", nfile);
+               col += n+fill;
+       }
+       if (*file && !stat(file, &lbuf))
+               totsize += copies * lbuf.st_size;
+}
+
+/*
+ * Print the long info about the file
+ */
+ldump(nfile, file, copies)
+       char *nfile, *file;
+{
+       struct stat lbuf;
+
+       putchar('\t');
+       if (copies > 1)
+               printf("%-2d copies of %-19s", copies, nfile);
+       else
+               printf("%-32s", nfile);
+       if (*file && !stat(file, &lbuf))
+               printf(" %ld bytes", lbuf.st_size);
+       else
+               printf(" ??? bytes");
+       putchar('\n');
+}
+
+/*
+ * Print the job's rank in the queue,
+ *   update col for screen management
+ */
+prank(n)
+{
+       char line[100];
+       static char *r[] = {
+               "th", "st", "nd", "rd", "th", "th", "th", "th", "th", "th"
+       };
+
+       if (n == 0) {
+               printf("active");
+               col += 6;
+               return;
+       }
+       if ((n/10)%10 == 1)
+               (void) sprintf(line, "%dth", n);
+       else
+               (void) sprintf(line, "%d%s", n, r[n%10]);
+       col += strlen(line);
+       printf("%s", line);
+}
diff --git a/usr/src/usr.sbin/lpr/common_source/lp.h b/usr/src/usr.sbin/lpr/common_source/lp.h
new file mode 100644 (file)
index 0000000..1f57657
--- /dev/null
@@ -0,0 +1,121 @@
+/*
+ * Copyright (c) 1983 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.
+ *
+ *     @(#)lp.h        5.5 (Berkeley) 6/1/90
+ */
+
+/*
+ * Global definitions for the line printer system.
+ */
+
+#include <stdio.h>
+#include <sys/param.h>
+#include <sys/file.h>
+#include <sys/dir.h>
+#include <sys/stat.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <netinet/in.h>
+#include <netdb.h>
+#include <pwd.h>
+#include <syslog.h>
+#include <signal.h>
+#include <sys/wait.h>
+#include <sgtty.h>
+#include <ctype.h>
+#include <errno.h>
+#include "lp.local.h"
+
+extern int     DU;             /* daeomon user-id */
+extern int     MX;             /* maximum number of blocks to copy */
+extern int     MC;             /* maximum number of copies allowed */
+extern char    *LP;            /* line printer device name */
+extern char    *RM;            /* remote machine name */
+extern char    *RG;            /* restricted group */
+extern char    *RP;            /* remote printer name */
+extern char    *LO;            /* lock file name */
+extern char    *ST;            /* status file name */
+extern char    *SD;            /* spool directory */
+extern char    *AF;            /* accounting file */
+extern char    *LF;            /* log file for error messages */
+extern char    *OF;            /* name of output filter (created once) */
+extern char    *IF;            /* name of input filter (created per job) */
+extern char    *RF;            /* name of fortran text filter (per job) */
+extern char    *TF;            /* name of troff(1) filter (per job) */
+extern char    *NF;            /* name of ditroff(1) filter (per job) */
+extern char    *DF;            /* name of tex filter (per job) */
+extern char    *GF;            /* name of graph(1G) filter (per job) */
+extern char    *VF;            /* name of raster filter (per job) */
+extern char    *CF;            /* name of cifplot filter (per job) */
+extern char    *FF;            /* form feed string */
+extern char    *TR;            /* trailer string to be output when Q empties */
+extern short   SC;             /* suppress multiple copies */
+extern short   SF;             /* suppress FF on each print job */
+extern short   SH;             /* suppress header page */
+extern short   SB;             /* short banner instead of normal header */
+extern short   HL;             /* print header last */
+extern short   RW;             /* open LP for reading and writing */
+extern short   PW;             /* page width */
+extern short   PX;             /* page width in pixels */
+extern short   PY;             /* page length in pixels */
+extern short   PL;             /* page length */
+extern short   BR;             /* baud rate if lp is a tty */
+extern int     FC;             /* flags to clear if lp is a tty */
+extern int     FS;             /* flags to set if lp is a tty */
+extern int     XC;             /* flags to clear for local mode */
+extern int     XS;             /* flags to set for local mode */
+extern short   RS;             /* restricted to those with local accounts */
+
+extern char    line[BUFSIZ];
+extern char    pbuf[];         /* buffer for printcap entry */
+extern char    *bp;            /* pointer into ebuf for pgetent() */
+extern char    *name;          /* program name */
+extern char    *printer;       /* printer name */
+extern char    host[32];       /* host machine name */
+extern char    *from;          /* client's machine name */
+extern int     sendtorem;      /* are we sending to a remote? */
+extern int     errno;
+
+/*
+ * Structure used for building a sorted list of control files.
+ */
+struct queue {
+       time_t  q_time;                 /* modification time */
+       char    q_name[MAXNAMLEN+1];    /* control file name */
+};
+
+char   *pgetstr();
+char   *malloc();
+char   *getenv();
+char   *index();
+char   *rindex();
+char   *checkremote();
diff --git a/usr/src/usr.sbin/lpr/common_source/lp.local.h b/usr/src/usr.sbin/lpr/common_source/lp.local.h
new file mode 100644 (file)
index 0000000..56db34a
--- /dev/null
@@ -0,0 +1,96 @@
+/*
+ * Copyright (c) 1983 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.
+ *
+ *     @(#)lp.local.h  5.5 (Berkeley) 6/1/90
+ */
+
+/*
+ * Possibly, local parameters to the spooling system
+ */
+
+/*
+ * Magic number mapping for binary files, used by lpr to avoid
+ *   printing objects files.
+ */
+
+#include <a.out.h>
+#include <ar.h>
+
+#ifndef A_MAGIC1       /* must be a VM/UNIX system */
+#      define A_MAGIC1 OMAGIC
+#      define A_MAGIC2 NMAGIC
+#      define A_MAGIC3 ZMAGIC
+#      undef ARMAG
+#      define ARMAG    0177545
+#endif
+
+/*
+ * Defaults for line printer capabilities data base
+ */
+#define        DEFLP           "lp"
+#define DEFLOCK                "lock"
+#define DEFSTAT                "status"
+#define        DEFMX           1000
+#define DEFMAXCOPIES   0
+#define DEFFF          "\f"
+#define DEFWIDTH       132
+#define DEFLENGTH      66
+#define DEFUID         1
+
+/*
+ * When files are created in the spooling area, they are normally
+ *   readable only by their owner and the spooling group.  If you
+ *   want otherwise, change this mode.
+ */
+#define FILMOD         0660
+
+/*
+ * Printer is assumed to support LINELEN (for block chars)
+ *   and background character (blank) is a space
+ */
+#define LINELEN                132
+#define BACKGND                ' '
+
+#define HEIGHT 9               /* height of characters */
+#define WIDTH  8               /* width of characters */
+#define DROP   3               /* offset to drop characters with descenders */
+
+/*
+ * Define TERMCAP if the terminal capabilites are to be used for lpq.
+ */
+#define TERMCAP
+
+/*
+ * Maximum number of user and job requests for lpq and lprm.
+ */
+#define MAXUSERS       50
+#define MAXREQUESTS    50
diff --git a/usr/src/usr.sbin/lpr/common_source/lpc.h b/usr/src/usr.sbin/lpr/common_source/lpc.h
new file mode 100644 (file)
index 0000000..7104d95
--- /dev/null
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 1983 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.
+ *
+ *     @(#)lpc.h       5.4 (Berkeley) 6/1/90
+ */
+
+/*
+ * Line printer control program.
+ */
+struct cmd {
+       char    *c_name;                /* command name */
+       char    *c_help;                /* help message */
+       int     (*c_handler)();         /* routine to do the work */
+       int     c_priv;                 /* privileged command */
+};
diff --git a/usr/src/usr.sbin/lpr/common_source/pathnames.h b/usr/src/usr.sbin/lpr/common_source/pathnames.h
new file mode 100644 (file)
index 0000000..907a6df
--- /dev/null
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 1989 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.
+ *
+ *     @(#)pathnames.h 5.4 (Berkeley) 6/1/90
+ */
+
+#include <paths.h>
+
+#define        _PATH_DEFDEVLP          "/dev/lp"
+#define        _PATH_DEFSPOOL          "/var/spool/output/lpd"
+#define        _PATH_HOSTSEQUIV        "/etc/hosts.equiv"
+#define        _PATH_HOSTSLPD          "/etc/hosts.lpd"
+#define        _PATH_MASTERLOCK        "/var/spool/output/lpd.lock"
+#define        _PATH_PR                "/usr/bin/pr"
+#define        _PATH_PRINTCAP          "/etc/printcap"
+#define        _PATH_SOCKETNAME        "/var/run/printer"
+#define        _PATH_VFONT             "/usr/libdata/vfont/"
+#define        _PATH_VFONTB            "/usr/libdata/vfont/B"
+#define        _PATH_VFONTI            "/usr/libdata/vfont/I"
+#define        _PATH_VFONTR            "/usr/libdata/vfont/R"
+#define        _PATH_VFONTS            "/usr/libdata/vfont/S"
diff --git a/usr/src/usr.sbin/lpr/common_source/printcap.c b/usr/src/usr.sbin/lpr/common_source/printcap.c
new file mode 100644 (file)
index 0000000..47b1b80
--- /dev/null
@@ -0,0 +1,444 @@
+/*
+ * Copyright (c) 1983 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 sccsid[] = "@(#)printcap.c 5.7 (Berkeley) 3/4/91";
+#endif /* not lint */
+
+#include <ctype.h>
+#include <stdio.h>
+#include "pathnames.h"
+
+#ifndef BUFSIZ
+#define        BUFSIZ  1024
+#endif
+#define MAXHOP 32      /* max number of tc= indirections */
+
+/*
+ * termcap - routines for dealing with the terminal capability data base
+ *
+ * BUG:                Should use a "last" pointer in tbuf, so that searching
+ *             for capabilities alphabetically would not be a n**2/2
+ *             process when large numbers of capabilities are given.
+ * Note:       If we add a last pointer now we will screw up the
+ *             tc capability. We really should compile termcap.
+ *
+ * Essentially all the work here is scanning and decoding escapes
+ * in string capabilities.  We don't use stdio because the editor
+ * doesn't, and because living w/o it is not hard.
+ */
+
+#define PRINTCAP
+
+#ifdef PRINTCAP
+#define tgetent        pgetent
+#define tskip  pskip
+#define tgetstr        pgetstr
+#define tdecode pdecode
+#define tgetnum        pgetnum
+#define        tgetflag pgetflag
+#define tdecode pdecode
+#define tnchktc        pnchktc
+#define        tnamatch pnamatch
+#define V6
+#endif
+
+static FILE *pfp = NULL;       /* printcap data base file pointer */
+static char *tbuf;
+static int hopcount;           /* detect infinite loops in termcap, init 0 */
+char   *tskip();
+char   *tgetstr();
+char   *tdecode();
+char   *getenv();
+
+/*
+ * Similar to tgetent except it returns the next enrty instead of
+ * doing a lookup.
+ */
+getprent(bp)
+       register char *bp;
+{
+       register int c, skip = 0;
+
+       if (pfp == NULL && (pfp = fopen(_PATH_PRINTCAP, "r")) == NULL)
+               return(-1);
+       tbuf = bp;
+       for (;;) {
+               switch (c = getc(pfp)) {
+               case EOF:
+                       fclose(pfp);
+                       pfp = NULL;
+                       return(0);
+               case '\n':
+                       if (bp == tbuf) {
+                               skip = 0;
+                               continue;
+                       }
+                       if (bp[-1] == '\\') {
+                               bp--;
+                               continue;
+                       }
+                       *bp = '\0';
+                       return(1);
+               case '#':
+                       if (bp == tbuf)
+                               skip++;
+               default:
+                       if (skip)
+                               continue;
+                       if (bp >= tbuf+BUFSIZ) {
+                               write(2, "Termcap entry too long\n", 23);
+                               *bp = '\0';
+                               return(1);
+                       }
+                       *bp++ = c;
+               }
+       }
+}
+
+endprent()
+{
+       if (pfp != NULL)
+               fclose(pfp);
+}
+
+/*
+ * Get an entry for terminal name in buffer bp,
+ * from the termcap file.  Parse is very rudimentary;
+ * we just notice escaped newlines.
+ */
+tgetent(bp, name)
+       char *bp, *name;
+{
+       register char *cp;
+       register int c;
+       register int i = 0, cnt = 0;
+       char ibuf[BUFSIZ];
+       char *cp2;
+       int tf;
+
+       tbuf = bp;
+       tf = 0;
+#ifndef V6
+       cp = getenv("TERMCAP");
+       /*
+        * TERMCAP can have one of two things in it. It can be the
+        * name of a file to use instead of /etc/termcap. In this
+        * case it better start with a "/". Or it can be an entry to
+        * use so we don't have to read the file. In this case it
+        * has to already have the newlines crunched out.
+        */
+       if (cp && *cp) {
+               if (*cp!='/') {
+                       cp2 = getenv("TERM");
+                       if (cp2==(char *) 0 || strcmp(name,cp2)==0) {
+                               strcpy(bp,cp);
+                               return(tnchktc());
+                       } else {
+                               tf = open(_PATH_PRINTCAP, 0);
+                       }
+               } else
+                       tf = open(cp, 0);
+       }
+       if (tf==0)
+               tf = open(_PATH_PRINTCAP, 0);
+#else
+       tf = open(_PATH_PRINTCAP, 0);
+#endif
+       if (tf < 0)
+               return (-1);
+       for (;;) {
+               cp = bp;
+               for (;;) {
+                       if (i == cnt) {
+                               cnt = read(tf, ibuf, BUFSIZ);
+                               if (cnt <= 0) {
+                                       close(tf);
+                                       return (0);
+                               }
+                               i = 0;
+                       }
+                       c = ibuf[i++];
+                       if (c == '\n') {
+                               if (cp > bp && cp[-1] == '\\'){
+                                       cp--;
+                                       continue;
+                               }
+                               break;
+                       }
+                       if (cp >= bp+BUFSIZ) {
+                               write(2,"Termcap entry too long\n", 23);
+                               break;
+                       } else
+                               *cp++ = c;
+               }
+               *cp = 0;
+
+               /*
+                * The real work for the match.
+                */
+               if (tnamatch(name)) {
+                       close(tf);
+                       return(tnchktc());
+               }
+       }
+}
+
+/*
+ * tnchktc: check the last entry, see if it's tc=xxx. If so,
+ * recursively find xxx and append that entry (minus the names)
+ * to take the place of the tc=xxx entry. This allows termcap
+ * entries to say "like an HP2621 but doesn't turn on the labels".
+ * Note that this works because of the left to right scan.
+ */
+tnchktc()
+{
+       register char *p, *q;
+       char tcname[16];        /* name of similar terminal */
+       char tcbuf[BUFSIZ];
+       char *holdtbuf = tbuf;
+       int l;
+
+       p = tbuf + strlen(tbuf) - 2;    /* before the last colon */
+       while (*--p != ':')
+               if (p<tbuf) {
+                       write(2, "Bad termcap entry\n", 18);
+                       return (0);
+               }
+       p++;
+       /* p now points to beginning of last field */
+       if (p[0] != 't' || p[1] != 'c')
+               return(1);
+       strcpy(tcname,p+3);
+       q = tcname;
+       while (q && *q != ':')
+               q++;
+       *q = 0;
+       if (++hopcount > MAXHOP) {
+               write(2, "Infinite tc= loop\n", 18);
+               return (0);
+       }
+       if (tgetent(tcbuf, tcname) != 1)
+               return(0);
+       for (q=tcbuf; *q != ':'; q++)
+               ;
+       l = p - holdtbuf + strlen(q);
+       if (l > BUFSIZ) {
+               write(2, "Termcap entry too long\n", 23);
+               q[BUFSIZ - (p-tbuf)] = 0;
+       }
+       strcpy(p, q+1);
+       tbuf = holdtbuf;
+       return(1);
+}
+
+/*
+ * Tnamatch deals with name matching.  The first field of the termcap
+ * entry is a sequence of names separated by |'s, so we compare
+ * against each such name.  The normal : terminator after the last
+ * name (before the first field) stops us.
+ */
+tnamatch(np)
+       char *np;
+{
+       register char *Np, *Bp;
+
+       Bp = tbuf;
+       if (*Bp == '#')
+               return(0);
+       for (;;) {
+               for (Np = np; *Np && *Bp == *Np; Bp++, Np++)
+                       continue;
+               if (*Np == 0 && (*Bp == '|' || *Bp == ':' || *Bp == 0))
+                       return (1);
+               while (*Bp && *Bp != ':' && *Bp != '|')
+                       Bp++;
+               if (*Bp == 0 || *Bp == ':')
+                       return (0);
+               Bp++;
+       }
+}
+
+/*
+ * Skip to the next field.  Notice that this is very dumb, not
+ * knowing about \: escapes or any such.  If necessary, :'s can be put
+ * into the termcap file in octal.
+ */
+static char *
+tskip(bp)
+       register char *bp;
+{
+
+       while (*bp && *bp != ':')
+               bp++;
+       if (*bp == ':')
+               bp++;
+       return (bp);
+}
+
+/*
+ * Return the (numeric) option id.
+ * Numeric options look like
+ *     li#80
+ * i.e. the option string is separated from the numeric value by
+ * a # character.  If the option is not found we return -1.
+ * Note that we handle octal numbers beginning with 0.
+ */
+tgetnum(id)
+       char *id;
+{
+       register int i, base;
+       register char *bp = tbuf;
+
+       for (;;) {
+               bp = tskip(bp);
+               if (*bp == 0)
+                       return (-1);
+               if (*bp++ != id[0] || *bp == 0 || *bp++ != id[1])
+                       continue;
+               if (*bp == '@')
+                       return(-1);
+               if (*bp != '#')
+                       continue;
+               bp++;
+               base = 10;
+               if (*bp == '0')
+                       base = 8;
+               i = 0;
+               while (isdigit(*bp))
+                       i *= base, i += *bp++ - '0';
+               return (i);
+       }
+}
+
+/*
+ * Handle a flag option.
+ * Flag options are given "naked", i.e. followed by a : or the end
+ * of the buffer.  Return 1 if we find the option, or 0 if it is
+ * not given.
+ */
+tgetflag(id)
+       char *id;
+{
+       register char *bp = tbuf;
+
+       for (;;) {
+               bp = tskip(bp);
+               if (!*bp)
+                       return (0);
+               if (*bp++ == id[0] && *bp != 0 && *bp++ == id[1]) {
+                       if (!*bp || *bp == ':')
+                               return (1);
+                       else if (*bp == '@')
+                               return(0);
+               }
+       }
+}
+
+/*
+ * Get a string valued option.
+ * These are given as
+ *     cl=^Z
+ * Much decoding is done on the strings, and the strings are
+ * placed in area, which is a ref parameter which is updated.
+ * No checking on area overflow.
+ */
+char *
+tgetstr(id, area)
+       char *id, **area;
+{
+       register char *bp = tbuf;
+
+       for (;;) {
+               bp = tskip(bp);
+               if (!*bp)
+                       return (0);
+               if (*bp++ != id[0] || *bp == 0 || *bp++ != id[1])
+                       continue;
+               if (*bp == '@')
+                       return(0);
+               if (*bp != '=')
+                       continue;
+               bp++;
+               return (tdecode(bp, area));
+       }
+}
+
+/*
+ * Tdecode does the grung work to decode the
+ * string capability escapes.
+ */
+static char *
+tdecode(str, area)
+       register char *str;
+       char **area;
+{
+       register char *cp;
+       register int c;
+       register char *dp;
+       int i;
+
+       cp = *area;
+       while ((c = *str++) && c != ':') {
+               switch (c) {
+
+               case '^':
+                       c = *str++ & 037;
+                       break;
+
+               case '\\':
+                       dp = "E\033^^\\\\::n\nr\rt\tb\bf\f";
+                       c = *str++;
+nextc:
+                       if (*dp++ == c) {
+                               c = *dp++;
+                               break;
+                       }
+                       dp++;
+                       if (*dp)
+                               goto nextc;
+                       if (isdigit(c)) {
+                               c -= '0', i = 2;
+                               do
+                                       c <<= 3, c |= *str++ - '0';
+                               while (--i && isdigit(*str));
+                       }
+                       break;
+               }
+               *cp++ = c;
+       }
+       *cp++ = 0;
+       str = *area;
+       *area = cp;
+       return (str);
+}
diff --git a/usr/src/usr.sbin/lpr/common_source/rmjob.c b/usr/src/usr.sbin/lpr/common_source/rmjob.c
new file mode 100644 (file)
index 0000000..989c682
--- /dev/null
@@ -0,0 +1,321 @@
+/*
+ * Copyright (c) 1983 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 sccsid[] = "@(#)rmjob.c    5.7 (Berkeley) 6/1/90";
+#endif /* not lint */
+
+/*
+ * rmjob - remove the specified jobs from the queue.
+ */
+
+#include "lp.h"
+#include "pathnames.h"
+
+/*
+ * Stuff for handling lprm specifications
+ */
+extern char    *user[];                /* users to process */
+extern int     users;                  /* # of users in user array */
+extern int     requ[];                 /* job number of spool entries */
+extern int     requests;               /* # of spool requests */
+extern char    *person;                /* name of person doing lprm */
+
+char   root[] = "root";
+int    all = 0;                /* eliminate all files (root only) */
+int    cur_daemon;             /* daemon's pid */
+char   current[40];            /* active control file name */
+
+int    iscf();
+
+rmjob()
+{
+       register int i, nitems;
+       int assasinated = 0;
+       struct direct **files;
+       char *cp;
+
+       if ((i = pgetent(line, printer)) < 0)
+               fatal("cannot open printer description file");
+       else if (i == 0)
+               fatal("unknown printer");
+       if ((SD = pgetstr("sd", &bp)) == NULL)
+               SD = _PATH_DEFSPOOL;
+       if ((LO = pgetstr("lo", &bp)) == NULL)
+               LO = DEFLOCK;
+       if ((LP = pgetstr("lp", &bp)) == NULL)
+               LP = _PATH_DEFDEVLP;
+       if ((RP = pgetstr("rp", &bp)) == NULL)
+               RP = DEFLP;
+       RM = pgetstr("rm", &bp);
+       if (cp = checkremote())
+               printf("Warning: %s\n", cp);
+
+       /*
+        * If the format was `lprm -' and the user isn't the super-user,
+        *  then fake things to look like he said `lprm user'.
+        */
+       if (users < 0) {
+               if (getuid() == 0)
+                       all = 1;        /* all files in local queue */
+               else {
+                       user[0] = person;
+                       users = 1;
+               }
+       }
+       if (!strcmp(person, "-all")) {
+               if (from == host)
+                       fatal("The login name \"-all\" is reserved");
+               all = 1;        /* all those from 'from' */
+               person = root;
+       }
+
+       if (chdir(SD) < 0)
+               fatal("cannot chdir to spool directory");
+       if ((nitems = scandir(".", &files, iscf, NULL)) < 0)
+               fatal("cannot access spool directory");
+
+       if (nitems) {
+               /*
+                * Check for an active printer daemon (in which case we
+                *  kill it if it is reading our file) then remove stuff
+                *  (after which we have to restart the daemon).
+                */
+               if (lockchk(LO) && chk(current)) {
+                       assasinated = kill(cur_daemon, SIGINT) == 0;
+                       if (!assasinated)
+                               fatal("cannot kill printer daemon");
+               }
+               /*
+                * process the files
+                */
+               for (i = 0; i < nitems; i++)
+                       process(files[i]->d_name);
+       }
+       rmremote();
+       /*
+        * Restart the printer daemon if it was killed
+        */
+       if (assasinated && !startdaemon(printer))
+               fatal("cannot restart printer daemon\n");
+       exit(0);
+}
+
+/*
+ * Process a lock file: collect the pid of the active
+ *  daemon and the file name of the active spool entry.
+ * Return boolean indicating existence of a lock file.
+ */
+lockchk(s)
+       char *s;
+{
+       register FILE *fp;
+       register int i, n;
+
+       if ((fp = fopen(s, "r")) == NULL)
+               if (errno == EACCES)
+                       fatal("can't access lock file");
+               else
+                       return(0);
+       if (!getline(fp)) {
+               (void) fclose(fp);
+               return(0);              /* no daemon present */
+       }
+       cur_daemon = atoi(line);
+       if (kill(cur_daemon, 0) < 0) {
+               (void) fclose(fp);
+               return(0);              /* no daemon present */
+       }
+       for (i = 1; (n = fread(current, sizeof(char), sizeof(current), fp)) <= 0; i++) {
+               if (i > 5) {
+                       n = 1;
+                       break;
+               }
+               sleep(i);
+       }
+       current[n-1] = '\0';
+       (void) fclose(fp);
+       return(1);
+}
+
+/*
+ * Process a control file.
+ */
+process(file)
+       char *file;
+{
+       FILE *cfp;
+
+       if (!chk(file))
+               return;
+       if ((cfp = fopen(file, "r")) == NULL)
+               fatal("cannot open %s", file);
+       while (getline(cfp)) {
+               switch (line[0]) {
+               case 'U':  /* unlink associated files */
+                       if (from != host)
+                               printf("%s: ", host);
+                       printf(unlink(line+1) ? "cannot dequeue %s\n" :
+                               "%s dequeued\n", line+1);
+               }
+       }
+       (void) fclose(cfp);
+       if (from != host)
+               printf("%s: ", host);
+       printf(unlink(file) ? "cannot dequeue %s\n" : "%s dequeued\n", file);
+}
+
+/*
+ * Do the dirty work in checking
+ */
+chk(file)
+       char *file;
+{
+       register int *r, n;
+       register char **u, *cp;
+       FILE *cfp;
+
+       /*
+        * Check for valid cf file name (mostly checking current).
+        */
+       if (strlen(file) < 7 || file[0] != 'c' || file[1] != 'f')
+               return(0);
+
+       if (all && (from == host || !strcmp(from, file+6)))
+               return(1);
+
+       /*
+        * get the owner's name from the control file.
+        */
+       if ((cfp = fopen(file, "r")) == NULL)
+               return(0);
+       while (getline(cfp)) {
+               if (line[0] == 'P')
+                       break;
+       }
+       (void) fclose(cfp);
+       if (line[0] != 'P')
+               return(0);
+
+       if (users == 0 && requests == 0)
+               return(!strcmp(file, current) && isowner(line+1, file));
+       /*
+        * Check the request list
+        */
+       for (n = 0, cp = file+3; isdigit(*cp); )
+               n = n * 10 + (*cp++ - '0');
+       for (r = requ; r < &requ[requests]; r++)
+               if (*r == n && isowner(line+1, file))
+                       return(1);
+       /*
+        * Check to see if it's in the user list
+        */
+       for (u = user; u < &user[users]; u++)
+               if (!strcmp(*u, line+1) && isowner(line+1, file))
+                       return(1);
+       return(0);
+}
+
+/*
+ * If root is removing a file on the local machine, allow it.
+ * If root is removing a file from a remote machine, only allow
+ * files sent from the remote machine to be removed.
+ * Normal users can only remove the file from where it was sent.
+ */
+isowner(owner, file)
+       char *owner, *file;
+{
+       if (!strcmp(person, root) && (from == host || !strcmp(from, file+6)))
+               return(1);
+       if (!strcmp(person, owner) && !strcmp(from, file+6))
+               return(1);
+       if (from != host)
+               printf("%s: ", host);
+       printf("%s: Permission denied\n", file);
+       return(0);
+}
+
+/*
+ * Check to see if we are sending files to a remote machine. If we are,
+ * then try removing files on the remote machine.
+ */
+rmremote()
+{
+       register char *cp;
+       register int i, rem;
+       char buf[BUFSIZ];
+
+       if (!sendtorem)
+               return; /* not sending to a remote machine */
+
+       /*
+        * Flush stdout so the user can see what has been deleted
+        * while we wait (possibly) for the connection.
+        */
+       fflush(stdout);
+
+       sprintf(buf, "\5%s %s", RP, all ? "-all" : person);
+       cp = buf;
+       for (i = 0; i < users; i++) {
+               cp += strlen(cp);
+               *cp++ = ' ';
+               strcpy(cp, user[i]);
+       }
+       for (i = 0; i < requests; i++) {
+               cp += strlen(cp);
+               (void) sprintf(cp, " %d", requ[i]);
+       }
+       strcat(cp, "\n");
+       rem = getport(RM);
+       if (rem < 0) {
+               if (from != host)
+                       printf("%s: ", host);
+               printf("connection to %s is down\n", RM);
+       } else {
+               i = strlen(buf);
+               if (write(rem, buf, i) != i)
+                       fatal("Lost connection");
+               while ((i = read(rem, buf, sizeof(buf))) > 0)
+                       (void) fwrite(buf, 1, i, stdout);
+               (void) close(rem);
+       }
+}
+
+/*
+ * Return 1 if the filename begins with 'cf'
+ */
+iscf(d)
+       struct direct *d;
+{
+       return(d->d_name[0] == 'c' && d->d_name[1] == 'f');
+}
diff --git a/usr/src/usr.sbin/lpr/common_source/startdaemon.c b/usr/src/usr.sbin/lpr/common_source/startdaemon.c
new file mode 100644 (file)
index 0000000..3b3e865
--- /dev/null
@@ -0,0 +1,98 @@
+/*
+ * Copyright (c) 1983 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 sccsid[] = "@(#)startdaemon.c      5.7 (Berkeley) 3/2/91";
+#endif /* not lint */
+
+/*
+ * Tell the printer daemon that there are new files in the spool directory.
+ */
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <stdio.h>
+#include "lp.local.h"
+#include "pathnames.h"
+
+startdaemon(printer)
+       char *printer;
+{
+       struct sockaddr_un sun;
+       register int s, n;
+       char buf[BUFSIZ];
+       static void perr();
+
+       s = socket(AF_UNIX, SOCK_STREAM, 0);
+       if (s < 0) {
+               perr("socket");
+               return(0);
+       }
+       sun.sun_family = AF_UNIX;
+       strcpy(sun.sun_path, _PATH_SOCKETNAME);
+       if (connect(s, (struct sockaddr *)&sun, strlen(sun.sun_path) + 2) < 0) {
+               perr("connect");
+               (void) close(s);
+               return(0);
+       }
+       (void) sprintf(buf, "\1%s\n", printer);
+       n = strlen(buf);
+       if (write(s, buf, n) != n) {
+               perr("write");
+               (void) close(s);
+               return(0);
+       }
+       if (read(s, buf, 1) == 1) {
+               if (buf[0] == '\0') {           /* everything is OK */
+                       (void) close(s);
+                       return(1);
+               }
+               putchar(buf[0]);
+       }
+       while ((n = read(s, buf, sizeof(buf))) > 0)
+               fwrite(buf, 1, n, stdout);
+       (void) close(s);
+       return(0);
+}
+
+static void
+perr(msg)
+       char *msg;
+{
+       extern int errno;
+       extern char *name;
+       char *strerror();
+
+       (void)printf("%s: %s: %s\n", name, msg, strerror(errno));
+}
diff --git a/usr/src/usr.sbin/lpr/filters/lpf.c b/usr/src/usr.sbin/lpr/filters/lpf.c
new file mode 100644 (file)
index 0000000..862832b
--- /dev/null
@@ -0,0 +1,214 @@
+/*
+ * Copyright (c) 1983 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
+char copyright[] =
+"@(#) Copyright (c) 1983 Regents of the University of California.\n\
+ All rights reserved.\n";
+#endif /* not lint */
+
+#ifndef lint
+static char sccsid[] = "@(#)lpf.c      5.4 (Berkeley) 6/1/90";
+#endif /* not lint */
+
+/*
+ *     filter which reads the output of nroff and converts lines
+ *     with ^H's to overwritten lines.  Thus this works like 'ul'
+ *     but is much better: it can handle more than 2 overwrites
+ *     and it is written with some style.
+ *     modified by kls to use register references instead of arrays
+ *     to try to gain a little speed.
+ */
+
+#include <stdio.h>
+#include <signal.h>
+
+#define MAXWIDTH  132
+#define MAXREP    10
+
+char   buf[MAXREP][MAXWIDTH];
+int    maxcol[MAXREP] = {-1};
+int    lineno;
+int    width = 132;    /* default line length */
+int    length = 66;    /* page length */
+int    indent;         /* indentation length */
+int    npages = 1;
+int    literal;        /* print control characters */
+char   *name;          /* user's login name */
+char   *host;          /* user's machine name */
+char   *acctfile;      /* accounting information file */
+
+main(argc, argv) 
+       int argc;
+       char *argv[];
+{
+       register FILE *p = stdin, *o = stdout;
+       register int i, col;
+       register char *cp;
+       int done, linedone, maxrep;
+       char ch, *limit;
+
+       while (--argc) {
+               if (*(cp = *++argv) == '-') {
+                       switch (cp[1]) {
+                       case 'n':
+                               argc--;
+                               name = *++argv;
+                               break;
+
+                       case 'h':
+                               argc--;
+                               host = *++argv;
+                               break;
+
+                       case 'w':
+                               if ((i = atoi(&cp[2])) > 0 && i <= MAXWIDTH)
+                                       width = i;
+                               break;
+
+                       case 'l':
+                               length = atoi(&cp[2]);
+                               break;
+
+                       case 'i':
+                               indent = atoi(&cp[2]);
+                               break;
+
+                       case 'c':       /* Print control chars */
+                               literal++;
+                               break;
+                       }
+               } else
+                       acctfile = cp;
+       }
+
+       for (cp = buf[0], limit = buf[MAXREP]; cp < limit; *cp++ = ' ');
+       done = 0;
+       
+       while (!done) {
+               col = indent;
+               maxrep = -1;
+               linedone = 0;
+               while (!linedone) {
+                       switch (ch = getc(p)) {
+                       case EOF:
+                               linedone = done = 1;
+                               ch = '\n';
+                               break;
+
+                       case '\f':
+                               lineno = length;
+                       case '\n':
+                               if (maxrep < 0)
+                                       maxrep = 0;
+                               linedone = 1;
+                               break;
+
+                       case '\b':
+                               if (--col < indent)
+                                       col = indent;
+                               break;
+
+                       case '\r':
+                               col = indent;
+                               break;
+
+                       case '\t':
+                               col = ((col - indent) | 07) + indent + 1;
+                               break;
+
+                       case '\031':
+                               /*
+                                * lpd needs to use a different filter to
+                                * print data so stop what we are doing and
+                                * wait for lpd to restart us.
+                                */
+                               if ((ch = getchar()) == '\1') {
+                                       fflush(stdout);
+                                       kill(getpid(), SIGSTOP);
+                                       break;
+                               } else {
+                                       ungetc(ch, stdin);
+                                       ch = '\031';
+                               }
+
+                       default:
+                               if (col >= width || !literal && ch < ' ') {
+                                       col++;
+                                       break;
+                               }
+                               cp = &buf[0][col];
+                               for (i = 0; i < MAXREP; i++) {
+                                       if (i > maxrep)
+                                               maxrep = i;
+                                       if (*cp == ' ') {
+                                               *cp = ch;
+                                               if (col > maxcol[i])
+                                                       maxcol[i] = col;
+                                               break;
+                                       }
+                                       cp += MAXWIDTH;
+                               }
+                               col++;
+                               break;
+                       }
+               }
+
+               /* print out lines */
+               for (i = 0; i <= maxrep; i++) {
+                       for (cp = buf[i], limit = cp+maxcol[i]; cp <= limit;) {
+                               putc(*cp, o);
+                               *cp++ = ' ';
+                       }
+                       if (i < maxrep)
+                               putc('\r', o);
+                       else
+                               putc(ch, o);
+                       if (++lineno >= length) {
+                               fflush(o);
+                               npages++;
+                               lineno = 0;
+                       }
+                       maxcol[i] = -1;
+               }
+       }
+       if (lineno) {           /* be sure to end on a page boundary */
+               putchar('\f');
+               npages++;
+       }
+       if (name && acctfile && access(acctfile, 02) >= 0 &&
+           freopen(acctfile, "a", stdout) != NULL) {
+               printf("%7.2f\t%s:%s\n", (float)npages, host, name);
+       }
+       exit(0);
+}
diff --git a/usr/src/usr.sbin/lpr/lpc/cmds.c b/usr/src/usr.sbin/lpr/lpc/cmds.c
new file mode 100644 (file)
index 0000000..471a9c9
--- /dev/null
@@ -0,0 +1,1016 @@
+/*
+ * Copyright (c) 1983 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 sccsid[] = "@(#)cmds.c     5.7 (Berkeley) 6/1/90";
+#endif /* not lint */
+
+/*
+ * lpc -- line printer control program -- commands:
+ */
+
+#include "lp.h"
+#include <sys/time.h>
+#include "pathnames.h"
+
+/*
+ * kill an existing daemon and disable printing.
+ */
+abort(argc, argv)
+       char *argv[];
+{
+       register int c, status;
+       register char *cp1, *cp2;
+       char prbuf[100];
+
+       if (argc == 1) {
+               printf("Usage: abort {all | printer ...}\n");
+               return;
+       }
+       if (argc == 2 && !strcmp(argv[1], "all")) {
+               printer = prbuf;
+               while (getprent(line) > 0) {
+                       cp1 = prbuf;
+                       cp2 = line;
+                       while ((c = *cp2++) && c != '|' && c != ':')
+                               *cp1++ = c;
+                       *cp1 = '\0';
+                       abortpr(1);
+               }
+               return;
+       }
+       while (--argc) {
+               printer = *++argv;
+               if ((status = pgetent(line, printer)) < 0) {
+                       printf("cannot open printer description file\n");
+                       continue;
+               } else if (status == 0) {
+                       printf("unknown printer %s\n", printer);
+                       continue;
+               }
+               abortpr(1);
+       }
+}
+
+abortpr(dis)
+{
+       register FILE *fp;
+       struct stat stbuf;
+       int pid, fd;
+
+       bp = pbuf;
+       if ((SD = pgetstr("sd", &bp)) == NULL)
+               SD = _PATH_DEFSPOOL;
+       if ((LO = pgetstr("lo", &bp)) == NULL)
+               LO = DEFLOCK;
+       (void) sprintf(line, "%s/%s", SD, LO);
+       printf("%s:\n", printer);
+
+       /*
+        * Turn on the owner execute bit of the lock file to disable printing.
+        */
+       if (dis) {
+               if (stat(line, &stbuf) >= 0) {
+                       if (chmod(line, (stbuf.st_mode & 0777) | 0100) < 0)
+                               printf("\tcannot disable printing\n");
+                       else {
+                               upstat("printing disabled\n");
+                               printf("\tprinting disabled\n");
+                       }
+               } else if (errno == ENOENT) {
+                       if ((fd = open(line, O_WRONLY|O_CREAT, 0760)) < 0)
+                               printf("\tcannot create lock file\n");
+                       else {
+                               (void) close(fd);
+                               upstat("printing disabled\n");
+                               printf("\tprinting disabled\n");
+                               printf("\tno daemon to abort\n");
+                       }
+                       return;
+               } else {
+                       printf("\tcannot stat lock file\n");
+                       return;
+               }
+       }
+       /*
+        * Kill the current daemon to stop printing now.
+        */
+       if ((fp = fopen(line, "r")) == NULL) {
+               printf("\tcannot open lock file\n");
+               return;
+       }
+       if (!getline(fp) || flock(fileno(fp), LOCK_SH|LOCK_NB) == 0) {
+               (void) fclose(fp);      /* unlocks as well */
+               printf("\tno daemon to abort\n");
+               return;
+       }
+       (void) fclose(fp);
+       if (kill(pid = atoi(line), SIGTERM) < 0)
+               printf("\tWarning: daemon (pid %d) not killed\n", pid);
+       else
+               printf("\tdaemon (pid %d) killed\n", pid);
+}
+
+/*
+ * Write a message into the status file.
+ */
+upstat(msg)
+       char *msg;
+{
+       register int fd;
+       char statfile[BUFSIZ];
+
+       bp = pbuf;
+       if ((ST = pgetstr("st", &bp)) == NULL)
+               ST = DEFSTAT;
+       (void) sprintf(statfile, "%s/%s", SD, ST);
+       umask(0);
+       fd = open(statfile, O_WRONLY|O_CREAT, 0664);
+       if (fd < 0 || flock(fd, LOCK_EX) < 0) {
+               printf("\tcannot create status file\n");
+               return;
+       }
+       (void) ftruncate(fd, 0);
+       if (msg == (char *)NULL)
+               (void) write(fd, "\n", 1);
+       else
+               (void) write(fd, msg, strlen(msg));
+       (void) close(fd);
+}
+
+/*
+ * Remove all spool files and temporaries from the spooling area.
+ */
+clean(argc, argv)
+       char *argv[];
+{
+       register int c, status;
+       register char *cp1, *cp2;
+       char prbuf[100];
+
+       if (argc == 1) {
+               printf("Usage: clean {all | printer ...}\n");
+               return;
+       }
+       if (argc == 2 && !strcmp(argv[1], "all")) {
+               printer = prbuf;
+               while (getprent(line) > 0) {
+                       cp1 = prbuf;
+                       cp2 = line;
+                       while ((c = *cp2++) && c != '|' && c != ':')
+                               *cp1++ = c;
+                       *cp1 = '\0';
+                       cleanpr();
+               }
+               return;
+       }
+       while (--argc) {
+               printer = *++argv;
+               if ((status = pgetent(line, printer)) < 0) {
+                       printf("cannot open printer description file\n");
+                       continue;
+               } else if (status == 0) {
+                       printf("unknown printer %s\n", printer);
+                       continue;
+               }
+               cleanpr();
+       }
+}
+
+select(d)
+struct direct *d;
+{
+       int c = d->d_name[0];
+
+       if ((c == 't' || c == 'c' || c == 'd') && d->d_name[1] == 'f')
+               return(1);
+       return(0);
+}
+
+/*
+ * Comparison routine for scandir. Sort by job number and machine, then
+ * by `cf', `tf', or `df', then by the sequence letter A-Z, a-z.
+ */
+sortq(d1, d2)
+struct direct **d1, **d2;
+{
+       int c1, c2;
+
+       if (c1 = strcmp((*d1)->d_name + 3, (*d2)->d_name + 3))
+               return(c1);
+       c1 = (*d1)->d_name[0];
+       c2 = (*d2)->d_name[0];
+       if (c1 == c2)
+               return((*d1)->d_name[2] - (*d2)->d_name[2]);
+       if (c1 == 'c')
+               return(-1);
+       if (c1 == 'd' || c2 == 'c')
+               return(1);
+       return(-1);
+}
+
+/*
+ * Remove incomplete jobs from spooling area.
+ */
+cleanpr()
+{
+       register int i, n;
+       register char *cp, *cp1, *lp;
+       struct direct **queue;
+       int nitems;
+
+       bp = pbuf;
+       if ((SD = pgetstr("sd", &bp)) == NULL)
+               SD = _PATH_DEFSPOOL;
+       printf("%s:\n", printer);
+
+       for (lp = line, cp = SD; *lp++ = *cp++; )
+               ;
+       lp[-1] = '/';
+
+       nitems = scandir(SD, &queue, select, sortq);
+       if (nitems < 0) {
+               printf("\tcannot examine spool directory\n");
+               return;
+       }
+       if (nitems == 0)
+               return;
+       i = 0;
+       do {
+               cp = queue[i]->d_name;
+               if (*cp == 'c') {
+                       n = 0;
+                       while (i + 1 < nitems) {
+                               cp1 = queue[i + 1]->d_name;
+                               if (*cp1 != 'd' || strcmp(cp + 3, cp1 + 3))
+                                       break;
+                               i++;
+                               n++;
+                       }
+                       if (n == 0) {
+                               strcpy(lp, cp);
+                               unlinkf(line);
+                       }
+               } else {
+                       /*
+                        * Must be a df with no cf (otherwise, it would have
+                        * been skipped above) or a tf file (which can always
+                        * be removed).
+                        */
+                       strcpy(lp, cp);
+                       unlinkf(line);
+               }
+       } while (++i < nitems);
+}
+unlinkf(name)
+       char    *name;
+{
+       if (unlink(name) < 0)
+               printf("\tcannot remove %s\n", name);
+       else
+               printf("\tremoved %s\n", name);
+}
+
+/*
+ * Enable queuing to the printer (allow lpr's).
+ */
+enable(argc, argv)
+       char *argv[];
+{
+       register int c, status;
+       register char *cp1, *cp2;
+       char prbuf[100];
+
+       if (argc == 1) {
+               printf("Usage: enable {all | printer ...}\n");
+               return;
+       }
+       if (argc == 2 && !strcmp(argv[1], "all")) {
+               printer = prbuf;
+               while (getprent(line) > 0) {
+                       cp1 = prbuf;
+                       cp2 = line;
+                       while ((c = *cp2++) && c != '|' && c != ':')
+                               *cp1++ = c;
+                       *cp1 = '\0';
+                       enablepr();
+               }
+               return;
+       }
+       while (--argc) {
+               printer = *++argv;
+               if ((status = pgetent(line, printer)) < 0) {
+                       printf("cannot open printer description file\n");
+                       continue;
+               } else if (status == 0) {
+                       printf("unknown printer %s\n", printer);
+                       continue;
+               }
+               enablepr();
+       }
+}
+
+enablepr()
+{
+       struct stat stbuf;
+
+       bp = pbuf;
+       if ((SD = pgetstr("sd", &bp)) == NULL)
+               SD = _PATH_DEFSPOOL;
+       if ((LO = pgetstr("lo", &bp)) == NULL)
+               LO = DEFLOCK;
+       (void) sprintf(line, "%s/%s", SD, LO);
+       printf("%s:\n", printer);
+
+       /*
+        * Turn off the group execute bit of the lock file to enable queuing.
+        */
+       if (stat(line, &stbuf) >= 0) {
+               if (chmod(line, stbuf.st_mode & 0767) < 0)
+                       printf("\tcannot enable queuing\n");
+               else
+                       printf("\tqueuing enabled\n");
+       }
+}
+
+/*
+ * Disable queuing.
+ */
+disable(argc, argv)
+       char *argv[];
+{
+       register int c, status;
+       register char *cp1, *cp2;
+       char prbuf[100];
+
+       if (argc == 1) {
+               printf("Usage: disable {all | printer ...}\n");
+               return;
+       }
+       if (argc == 2 && !strcmp(argv[1], "all")) {
+               printer = prbuf;
+               while (getprent(line) > 0) {
+                       cp1 = prbuf;
+                       cp2 = line;
+                       while ((c = *cp2++) && c != '|' && c != ':')
+                               *cp1++ = c;
+                       *cp1 = '\0';
+                       disablepr();
+               }
+               return;
+       }
+       while (--argc) {
+               printer = *++argv;
+               if ((status = pgetent(line, printer)) < 0) {
+                       printf("cannot open printer description file\n");
+                       continue;
+               } else if (status == 0) {
+                       printf("unknown printer %s\n", printer);
+                       continue;
+               }
+               disablepr();
+       }
+}
+
+disablepr()
+{
+       register int fd;
+       struct stat stbuf;
+
+       bp = pbuf;
+       if ((SD = pgetstr("sd", &bp)) == NULL)
+               SD = _PATH_DEFSPOOL;
+       if ((LO = pgetstr("lo", &bp)) == NULL)
+               LO = DEFLOCK;
+       (void) sprintf(line, "%s/%s", SD, LO);
+       printf("%s:\n", printer);
+       /*
+        * Turn on the group execute bit of the lock file to disable queuing.
+        */
+       if (stat(line, &stbuf) >= 0) {
+               if (chmod(line, (stbuf.st_mode & 0777) | 010) < 0)
+                       printf("\tcannot disable queuing\n");
+               else
+                       printf("\tqueuing disabled\n");
+       } else if (errno == ENOENT) {
+               if ((fd = open(line, O_WRONLY|O_CREAT, 0670)) < 0)
+                       printf("\tcannot create lock file\n");
+               else {
+                       (void) close(fd);
+                       printf("\tqueuing disabled\n");
+               }
+               return;
+       } else
+               printf("\tcannot stat lock file\n");
+}
+
+/*
+ * Disable queuing and printing and put a message into the status file
+ * (reason for being down).
+ */
+down(argc, argv)
+       char *argv[];
+{
+       register int c, status;
+       register char *cp1, *cp2;
+       char prbuf[100];
+
+       if (argc == 1) {
+               printf("Usage: down {all | printer} [message ...]\n");
+               return;
+       }
+       if (!strcmp(argv[1], "all")) {
+               printer = prbuf;
+               while (getprent(line) > 0) {
+                       cp1 = prbuf;
+                       cp2 = line;
+                       while ((c = *cp2++) && c != '|' && c != ':')
+                               *cp1++ = c;
+                       *cp1 = '\0';
+                       putmsg(argc - 2, argv + 2);
+               }
+               return;
+       }
+       printer = argv[1];
+       if ((status = pgetent(line, printer)) < 0) {
+               printf("cannot open printer description file\n");
+               return;
+       } else if (status == 0) {
+               printf("unknown printer %s\n", printer);
+               return;
+       }
+       putmsg(argc - 2, argv + 2);
+}
+
+putmsg(argc, argv)
+       char **argv;
+{
+       register int fd;
+       register char *cp1, *cp2;
+       char buf[1024];
+       struct stat stbuf;
+
+       bp = pbuf;
+       if ((SD = pgetstr("sd", &bp)) == NULL)
+               SD = _PATH_DEFSPOOL;
+       if ((LO = pgetstr("lo", &bp)) == NULL)
+               LO = DEFLOCK;
+       if ((ST = pgetstr("st", &bp)) == NULL)
+               ST = DEFSTAT;
+       printf("%s:\n", printer);
+       /*
+        * Turn on the group execute bit of the lock file to disable queuing and
+        * turn on the owner execute bit of the lock file to disable printing.
+        */
+       (void) sprintf(line, "%s/%s", SD, LO);
+       if (stat(line, &stbuf) >= 0) {
+               if (chmod(line, (stbuf.st_mode & 0777) | 0110) < 0)
+                       printf("\tcannot disable queuing\n");
+               else
+                       printf("\tprinter and queuing disabled\n");
+       } else if (errno == ENOENT) {
+               if ((fd = open(line, O_WRONLY|O_CREAT, 0770)) < 0)
+                       printf("\tcannot create lock file\n");
+               else {
+                       (void) close(fd);
+                       printf("\tprinter and queuing disabled\n");
+               }
+               return;
+       } else
+               printf("\tcannot stat lock file\n");
+       /*
+        * Write the message into the status file.
+        */
+       (void) sprintf(line, "%s/%s", SD, ST);
+       fd = open(line, O_WRONLY|O_CREAT, 0664);
+       if (fd < 0 || flock(fd, LOCK_EX) < 0) {
+               printf("\tcannot create status file\n");
+               return;
+       }
+       (void) ftruncate(fd, 0);
+       if (argc <= 0) {
+               (void) write(fd, "\n", 1);
+               (void) close(fd);
+               return;
+       }
+       cp1 = buf;
+       while (--argc >= 0) {
+               cp2 = *argv++;
+               while (*cp1++ = *cp2++)
+                       ;
+               cp1[-1] = ' ';
+       }
+       cp1[-1] = '\n';
+       *cp1 = '\0';
+       (void) write(fd, buf, strlen(buf));
+       (void) close(fd);
+}
+
+/*
+ * Exit lpc
+ */
+quit(argc, argv)
+       char *argv[];
+{
+       exit(0);
+}
+
+/*
+ * Kill and restart the daemon.
+ */
+restart(argc, argv)
+       char *argv[];
+{
+       register int c, status;
+       register char *cp1, *cp2;
+       char prbuf[100];
+
+       if (argc == 1) {
+               printf("Usage: restart {all | printer ...}\n");
+               return;
+       }
+       if (argc == 2 && !strcmp(argv[1], "all")) {
+               printer = prbuf;
+               while (getprent(line) > 0) {
+                       cp1 = prbuf;
+                       cp2 = line;
+                       while ((c = *cp2++) && c != '|' && c != ':')
+                               *cp1++ = c;
+                       *cp1 = '\0';
+                       abortpr(0);
+                       startpr(0);
+               }
+               return;
+       }
+       while (--argc) {
+               printer = *++argv;
+               if ((status = pgetent(line, printer)) < 0) {
+                       printf("cannot open printer description file\n");
+                       continue;
+               } else if (status == 0) {
+                       printf("unknown printer %s\n", printer);
+                       continue;
+               }
+               abortpr(0);
+               startpr(0);
+       }
+}
+
+/*
+ * Enable printing on the specified printer and startup the daemon.
+ */
+start(argc, argv)
+       char *argv[];
+{
+       register int c, status;
+       register char *cp1, *cp2;
+       char prbuf[100];
+
+       if (argc == 1) {
+               printf("Usage: start {all | printer ...}\n");
+               return;
+       }
+       if (argc == 2 && !strcmp(argv[1], "all")) {
+               printer = prbuf;
+               while (getprent(line) > 0) {
+                       cp1 = prbuf;
+                       cp2 = line;
+                       while ((c = *cp2++) && c != '|' && c != ':')
+                               *cp1++ = c;
+                       *cp1 = '\0';
+                       startpr(1);
+               }
+               return;
+       }
+       while (--argc) {
+               printer = *++argv;
+               if ((status = pgetent(line, printer)) < 0) {
+                       printf("cannot open printer description file\n");
+                       continue;
+               } else if (status == 0) {
+                       printf("unknown printer %s\n", printer);
+                       continue;
+               }
+               startpr(1);
+       }
+}
+
+startpr(enable)
+{
+       struct stat stbuf;
+
+       bp = pbuf;
+       if ((SD = pgetstr("sd", &bp)) == NULL)
+               SD = _PATH_DEFSPOOL;
+       if ((LO = pgetstr("lo", &bp)) == NULL)
+               LO = DEFLOCK;
+       (void) sprintf(line, "%s/%s", SD, LO);
+       printf("%s:\n", printer);
+
+       /*
+        * Turn off the owner execute bit of the lock file to enable printing.
+        */
+       if (enable && stat(line, &stbuf) >= 0) {
+               if (chmod(line, stbuf.st_mode & (enable==2 ? 0666 : 0677)) < 0)
+                       printf("\tcannot enable printing\n");
+               else
+                       printf("\tprinting enabled\n");
+       }
+       if (!startdaemon(printer))
+               printf("\tcouldn't start daemon\n");
+       else
+               printf("\tdaemon started\n");
+}
+
+/*
+ * Print the status of each queue listed or all the queues.
+ */
+status(argc, argv)
+       char *argv[];
+{
+       register int c, status;
+       register char *cp1, *cp2;
+       char prbuf[100];
+
+       if (argc == 1) {
+               printer = prbuf;
+               while (getprent(line) > 0) {
+                       cp1 = prbuf;
+                       cp2 = line;
+                       while ((c = *cp2++) && c != '|' && c != ':')
+                               *cp1++ = c;
+                       *cp1 = '\0';
+                       prstat();
+               }
+               return;
+       }
+       while (--argc) {
+               printer = *++argv;
+               if ((status = pgetent(line, printer)) < 0) {
+                       printf("cannot open printer description file\n");
+                       continue;
+               } else if (status == 0) {
+                       printf("unknown printer %s\n", printer);
+                       continue;
+               }
+               prstat();
+       }
+}
+
+/*
+ * Print the status of the printer queue.
+ */
+prstat()
+{
+       struct stat stbuf;
+       register int fd, i;
+       register struct direct *dp;
+       DIR *dirp;
+
+       bp = pbuf;
+       if ((SD = pgetstr("sd", &bp)) == NULL)
+               SD = _PATH_DEFSPOOL;
+       if ((LO = pgetstr("lo", &bp)) == NULL)
+               LO = DEFLOCK;
+       if ((ST = pgetstr("st", &bp)) == NULL)
+               ST = DEFSTAT;
+       printf("%s:\n", printer);
+       (void) sprintf(line, "%s/%s", SD, LO);
+       if (stat(line, &stbuf) >= 0) {
+               printf("\tqueuing is %s\n",
+                       (stbuf.st_mode & 010) ? "disabled" : "enabled");
+               printf("\tprinting is %s\n",
+                       (stbuf.st_mode & 0100) ? "disabled" : "enabled");
+       } else {
+               printf("\tqueuing is enabled\n");
+               printf("\tprinting is enabled\n");
+       }
+       if ((dirp = opendir(SD)) == NULL) {
+               printf("\tcannot examine spool directory\n");
+               return;
+       }
+       i = 0;
+       while ((dp = readdir(dirp)) != NULL) {
+               if (*dp->d_name == 'c' && dp->d_name[1] == 'f')
+                       i++;
+       }
+       closedir(dirp);
+       if (i == 0)
+               printf("\tno entries\n");
+       else if (i == 1)
+               printf("\t1 entry in spool area\n");
+       else
+               printf("\t%d entries in spool area\n", i);
+       fd = open(line, O_RDONLY);
+       if (fd < 0 || flock(fd, LOCK_SH|LOCK_NB) == 0) {
+               (void) close(fd);       /* unlocks as well */
+               printf("\tno daemon present\n");
+               return;
+       }
+       (void) close(fd);
+       putchar('\t');
+       (void) sprintf(line, "%s/%s", SD, ST);
+       fd = open(line, O_RDONLY);
+       if (fd >= 0) {
+               (void) flock(fd, LOCK_SH);
+               while ((i = read(fd, line, sizeof(line))) > 0)
+                       (void) fwrite(line, 1, i, stdout);
+               (void) close(fd);       /* unlocks as well */
+       }
+}
+
+/*
+ * Stop the specified daemon after completing the current job and disable
+ * printing.
+ */
+stop(argc, argv)
+       char *argv[];
+{
+       register int c, status;
+       register char *cp1, *cp2;
+       char prbuf[100];
+
+       if (argc == 1) {
+               printf("Usage: stop {all | printer ...}\n");
+               return;
+       }
+       if (argc == 2 && !strcmp(argv[1], "all")) {
+               printer = prbuf;
+               while (getprent(line) > 0) {
+                       cp1 = prbuf;
+                       cp2 = line;
+                       while ((c = *cp2++) && c != '|' && c != ':')
+                               *cp1++ = c;
+                       *cp1 = '\0';
+                       stoppr();
+               }
+               return;
+       }
+       while (--argc) {
+               printer = *++argv;
+               if ((status = pgetent(line, printer)) < 0) {
+                       printf("cannot open printer description file\n");
+                       continue;
+               } else if (status == 0) {
+                       printf("unknown printer %s\n", printer);
+                       continue;
+               }
+               stoppr();
+       }
+}
+
+stoppr()
+{
+       register int fd;
+       struct stat stbuf;
+
+       bp = pbuf;
+       if ((SD = pgetstr("sd", &bp)) == NULL)
+               SD = _PATH_DEFSPOOL;
+       if ((LO = pgetstr("lo", &bp)) == NULL)
+               LO = DEFLOCK;
+       (void) sprintf(line, "%s/%s", SD, LO);
+       printf("%s:\n", printer);
+
+       /*
+        * Turn on the owner execute bit of the lock file to disable printing.
+        */
+       if (stat(line, &stbuf) >= 0) {
+               if (chmod(line, (stbuf.st_mode & 0777) | 0100) < 0)
+                       printf("\tcannot disable printing\n");
+               else {
+                       upstat("printing disabled\n");
+                       printf("\tprinting disabled\n");
+               }
+       } else if (errno == ENOENT) {
+               if ((fd = open(line, O_WRONLY|O_CREAT, 0760)) < 0)
+                       printf("\tcannot create lock file\n");
+               else {
+                       (void) close(fd);
+                       upstat("printing disabled\n");
+                       printf("\tprinting disabled\n");
+               }
+       } else
+               printf("\tcannot stat lock file\n");
+}
+
+struct queue **queue;
+int    nitems;
+time_t mtime;
+
+/*
+ * Put the specified jobs at the top of printer queue.
+ */
+topq(argc, argv)
+       char *argv[];
+{
+       register int n, i;
+       struct stat stbuf;
+       register char *cfname;
+       int status, changed;
+
+       if (argc < 3) {
+               printf("Usage: topq printer [jobnum ...] [user ...]\n");
+               return;
+       }
+
+       --argc;
+       printer = *++argv;
+       status = pgetent(line, printer);
+       if (status < 0) {
+               printf("cannot open printer description file\n");
+               return;
+       } else if (status == 0) {
+               printf("%s: unknown printer\n", printer);
+               return;
+       }
+       bp = pbuf;
+       if ((SD = pgetstr("sd", &bp)) == NULL)
+               SD = _PATH_DEFSPOOL;
+       if ((LO = pgetstr("lo", &bp)) == NULL)
+               LO = DEFLOCK;
+       printf("%s:\n", printer);
+
+       if (chdir(SD) < 0) {
+               printf("\tcannot chdir to %s\n", SD);
+               return;
+       }
+       nitems = getq(&queue);
+       if (nitems == 0)
+               return;
+       changed = 0;
+       mtime = queue[0]->q_time;
+       for (i = argc; --i; ) {
+               if (doarg(argv[i]) == 0) {
+                       printf("\tjob %s is not in the queue\n", argv[i]);
+                       continue;
+               } else
+                       changed++;
+       }
+       for (i = 0; i < nitems; i++)
+               free(queue[i]);
+       free(queue);
+       if (!changed) {
+               printf("\tqueue order unchanged\n");
+               return;
+       }
+       /*
+        * Turn on the public execute bit of the lock file to
+        * get lpd to rebuild the queue after the current job.
+        */
+       if (changed && stat(LO, &stbuf) >= 0)
+               (void) chmod(LO, (stbuf.st_mode & 0777) | 01);
+} 
+
+/*
+ * Reposition the job by changing the modification time of
+ * the control file.
+ */
+touch(q)
+       struct queue *q;
+{
+       struct timeval tvp[2];
+
+       tvp[0].tv_sec = tvp[1].tv_sec = --mtime;
+       tvp[0].tv_usec = tvp[1].tv_usec = 0;
+       return(utimes(q->q_name, tvp));
+}
+
+/*
+ * Checks if specified job name is in the printer's queue.
+ * Returns:  negative (-1) if argument name is not in the queue.
+ */
+doarg(job)
+       char *job;
+{
+       register struct queue **qq;
+       register int jobnum, n;
+       register char *cp, *machine;
+       int cnt = 0;
+       FILE *fp;
+
+       /*
+        * Look for a job item consisting of system name, colon, number 
+        * (example: ucbarpa:114)  
+        */
+       if ((cp = index(job, ':')) != NULL) {
+               machine = job;
+               *cp++ = '\0';
+               job = cp;
+       } else
+               machine = NULL;
+
+       /*
+        * Check for job specified by number (example: 112 or 235ucbarpa).
+        */
+       if (isdigit(*job)) {
+               jobnum = 0;
+               do
+                       jobnum = jobnum * 10 + (*job++ - '0');
+               while (isdigit(*job));
+               for (qq = queue + nitems; --qq >= queue; ) {
+                       n = 0;
+                       for (cp = (*qq)->q_name+3; isdigit(*cp); )
+                               n = n * 10 + (*cp++ - '0');
+                       if (jobnum != n)
+                               continue;
+                       if (*job && strcmp(job, cp) != 0)
+                               continue;
+                       if (machine != NULL && strcmp(machine, cp) != 0)
+                               continue;
+                       if (touch(*qq) == 0) {
+                               printf("\tmoved %s\n", (*qq)->q_name);
+                               cnt++;
+                       }
+               }
+               return(cnt);
+       }
+       /*
+        * Process item consisting of owner's name (example: henry).
+        */
+       for (qq = queue + nitems; --qq >= queue; ) {
+               if ((fp = fopen((*qq)->q_name, "r")) == NULL)
+                       continue;
+               while (getline(fp) > 0)
+                       if (line[0] == 'P')
+                               break;
+               (void) fclose(fp);
+               if (line[0] != 'P' || strcmp(job, line+1) != 0)
+                       continue;
+               if (touch(*qq) == 0) {
+                       printf("\tmoved %s\n", (*qq)->q_name);
+                       cnt++;
+               }
+       }
+       return(cnt);
+}
+
+/*
+ * Enable everything and start printer (undo `down').
+ */
+up(argc, argv)
+       char *argv[];
+{
+       register int c, status;
+       register char *cp1, *cp2;
+       char prbuf[100];
+
+       if (argc == 1) {
+               printf("Usage: up {all | printer ...}\n");
+               return;
+       }
+       if (argc == 2 && !strcmp(argv[1], "all")) {
+               printer = prbuf;
+               while (getprent(line) > 0) {
+                       cp1 = prbuf;
+                       cp2 = line;
+                       while ((c = *cp2++) && c != '|' && c != ':')
+                               *cp1++ = c;
+                       *cp1 = '\0';
+                       startpr(2);
+               }
+               return;
+       }
+       while (--argc) {
+               printer = *++argv;
+               if ((status = pgetent(line, printer)) < 0) {
+                       printf("cannot open printer description file\n");
+                       continue;
+               } else if (status == 0) {
+                       printf("unknown printer %s\n", printer);
+                       continue;
+               }
+               startpr(2);
+       }
+}
diff --git a/usr/src/usr.sbin/lpr/lpc/cmdtab.c b/usr/src/usr.sbin/lpr/lpc/cmdtab.c
new file mode 100644 (file)
index 0000000..ad52316
--- /dev/null
@@ -0,0 +1,80 @@
+/*
+ * Copyright (c) 1983 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 sccsid[] = "@(#)cmdtab.c   5.4 (Berkeley) 6/1/90";
+#endif /* not lint */
+
+/*
+ * lpc -- command tables
+ */
+
+#include "lpc.h"
+
+int    abort(), clean(), enable(), disable(), down(), help();
+int    quit(), restart(), start(), status(), stop(), topq(), up();
+
+char   aborthelp[] =   "terminate a spooling daemon immediately and disable printing";
+char   cleanhelp[] =   "remove cruft files from a queue";
+char   enablehelp[] =  "turn a spooling queue on";
+char   disablehelp[] = "turn a spooling queue off";
+char   downhelp[] =    "do a 'stop' followed by 'disable' and put a message in status";
+char   helphelp[] =    "get help on commands";
+char   quithelp[] =    "exit lpc";
+char   restarthelp[] = "kill (if possible) and restart a spooling daemon";
+char   starthelp[] =   "enable printing and start a spooling daemon";
+char   statushelp[] =  "show status of daemon and queue";
+char   stophelp[] =    "stop a spooling daemon after current job completes and disable printing";
+char   topqhelp[] =    "put job at top of printer queue";
+char   uphelp[] =      "enable everything and restart spooling daemon";
+
+struct cmd cmdtab[] = {
+       { "abort",      aborthelp,      abort,          1 },
+       { "clean",      cleanhelp,      clean,          1 },
+       { "enable",     enablehelp,     enable,         1 },
+       { "exit",       quithelp,       quit,           0 },
+       { "disable",    disablehelp,    disable,        1 },
+       { "down",       downhelp,       down,           1 },
+       { "help",       helphelp,       help,           0 },
+       { "quit",       quithelp,       quit,           0 },
+       { "restart",    restarthelp,    restart,        0 },
+       { "start",      starthelp,      start,          1 },
+       { "status",     statushelp,     status,         0 },
+       { "stop",       stophelp,       stop,           1 },
+       { "topq",       topqhelp,       topq,           1 },
+       { "up",         uphelp,         up,             1 },
+       { "?",          helphelp,       help,           0 },
+       { 0 },
+};
+
+int    NCMDS = sizeof (cmdtab) / sizeof (cmdtab[0]);
diff --git a/usr/src/usr.sbin/lpr/lpc/lpc.8 b/usr/src/usr.sbin/lpr/lpc/lpc.8
new file mode 100644 (file)
index 0000000..f69169a
--- /dev/null
@@ -0,0 +1,174 @@
+.\" Copyright (c) 1983, 1991 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.
+.\"
+.\"     @(#)lpc.8      6.4 (Berkeley) 3/16/91
+.\"
+.Dd March 16, 1991
+.Dt LPC 8
+.Os BSD 4.2
+.Sh NAME
+.Nm lpc
+.Nd line printer control program
+.Sh SYNOPSIS
+.Nm lpc
+.Oo
+.Ar command
+.Op Ar argument ...
+.Oc
+.Sh DESCRIPTION
+.Nm Lpc
+is used by the system administrator to control the
+operation of the line printer system.  
+For each line printer configured in
+.Pa /etc/printcap ,
+.Nm lpc
+may be used to:
+.Bl -bullet -offset indent
+.It
+disable or enable a printer,
+.It
+disable or enable a printer's spooling queue,
+.It
+rearrange the order of jobs in a spooling queue,
+.It
+find the status of printers, and their associated
+spooling queues and printer dameons.
+.El
+.Pp
+Without any arguments,
+.Nm lpc
+will prompt for commands from the standard input.
+If arguments are supplied,
+.Nm lpc
+interprets the first argument as a command and the remaining
+arguments as parameters to the command.  The standard input
+may be redirected causing
+.Nm lpc
+to read commands from file.
+Commands may be abreviated;
+the following is the list of recognized commands.
+.Pp
+.Bl -tag -width Ds -compact
+.It Ic \&? No [ command ... ]
+.It Ic help No [ command ... ]
+Print a short description of each command specified in the argument list,
+or, if no arguments are given, a list of the recognized commands.
+.Pp
+.It Ic abort  No {\ all\ |\ printer\ }
+Terminate an active spooling daemon on the local host immediately and
+then disable printing (preventing new daemons from being started by
+.Xr lpr )
+for the specified printers.
+.Pp
+.It Ic clean  No {\ all\ |\ printer\ }
+Remove any temporary files, data files, and control files that cannot
+be printed (i.e., do not form a complete printer job)
+from the specified printer queue(s) on the local machine.
+.Pp
+.It Ic disable  No {\ all\ |\ printer\ }
+Turn the specified printer queues off.  This prevents new
+printer jobs from being entered into the queue by
+.Xr lpr .
+.Pp
+.It Ic down No {\ all\ |\ printer\ } message ...
+Turn the specified printer queue off, disable printing and put
+.Em message
+in the printer status file. The message doesn't need to be quoted, the
+remaining arguments are treated like
+.Xr echo 1 .
+This is normally used to take a printer down and let others know why
+.Xr lpq 1
+will indicate the printer is down and print the status message).
+.Pp
+.It Ic enable  No {\ all\ |\ printer\ }
+Enable spooling on the local queue for the listed printers. 
+This will allow
+.Xr lpr 1
+to put new jobs in the spool queue.
+.Pp
+.It Ic exit
+.It Ic quit
+Exit from lpc.
+.Pp
+.It Ic restart  No {\ all\ |\ printer\ }
+Attempt to start a new printer daemon. 
+This is useful when some abnormal condition causes the daemon to
+die unexpectedly leaving jobs in the queue.
+.Xr Lpq
+will report that there is no daemon present when this condition occurs. 
+If the user is the super-user,
+try to abort the current daemon first (i.e., kill and restart a stuck daemon).
+.Pp
+.It Ic start  No {\ all\ |\ printer\ }
+Enable printing and start a spooling daemon for the listed printers.
+.Pp
+.It Ic status  No {\ all\ |\ printer\ }
+Display the status of daemons and queues on the local machine.
+.Pp
+.It Ic stop  No {\ all\ |\ printer\ }
+Stop a spooling daemon after the current job completes and disable
+printing.
+.Pp
+.It Ic topq No printer\ [\ jobnum\ ...\ ]\ [\ user\ ...\ ]
+Place the jobs in the order listed at the top of the printer queue.
+.Pp
+.It Ic up  No {\ all\ |\ printer\ }
+Enable everything and start a new printer daemon. Undoes the effects of
+.Ic down .
+.Sh FILES
+.Bl -tag -width /var/spool/*/lockx -compact
+.It Pa /etc/printcap
+printer description file
+.It Pa /var/spool/*
+spool directories
+.It Pa /var/spool/*/lock
+lock file for queue control
+.El
+.Sh SEE ALSO
+.Xr lpd 8 ,
+.Xr lpr 1 ,
+.Xr lpq 1 ,
+.Xr lprm 1 ,
+.Xr printcap 5
+.Sh DIAGNOSTICS
+.Bl -tag -width Ds
+.It Sy "?Ambiguous command"
+abreviation matches more than one command
+.It Sy "?Invalid command"
+no match was found
+.It Sy "?Privileged command"
+command can be executed by root only
+.El
+.Sh HISTORY
+The
+.Nm
+command appeared in
+.Bx 4.2 .
diff --git a/usr/src/usr.sbin/lpr/lpc/lpc.c b/usr/src/usr.sbin/lpr/lpc/lpc.c
new file mode 100644 (file)
index 0000000..0f38315
--- /dev/null
@@ -0,0 +1,262 @@
+/*
+ * Copyright (c) 1983 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
+char copyright[] =
+"@(#) Copyright (c) 1983 Regents of the University of California.\n\
+ All rights reserved.\n";
+#endif /* not lint */
+
+#ifndef lint
+static char sccsid[] = "@(#)lpc.c      5.11 (Berkeley) 3/2/91";
+#endif /* not lint */
+
+/*
+ * lpc -- line printer control program
+ */
+#include <stdio.h>
+#include <signal.h>
+#include <ctype.h>
+#include <setjmp.h>
+#include <syslog.h>
+
+#include "lpc.h"
+
+int    fromatty;
+
+char   cmdline[200];
+int    margc;
+char   *margv[20];
+int    top;
+void   intr();
+struct cmd *getcmd();
+
+jmp_buf        toplevel;
+
+main(argc, argv)
+       char *argv[];
+{
+       register struct cmd *c;
+       extern char *name;
+
+       name = argv[0];
+       openlog("lpd", 0, LOG_LPR);
+
+       if (--argc > 0) {
+               c = getcmd(*++argv);
+               if (c == (struct cmd *)-1) {
+                       printf("?Ambiguous command\n");
+                       exit(1);
+               }
+               if (c == 0) {
+                       printf("?Invalid command\n");
+                       exit(1);
+               }
+               if (c->c_priv && getuid()) {
+                       printf("?Privileged command\n");
+                       exit(1);
+               }
+               (*c->c_handler)(argc, argv);
+               exit(0);
+       }
+       fromatty = isatty(fileno(stdin));
+       top = setjmp(toplevel) == 0;
+       if (top)
+               signal(SIGINT, intr);
+       for (;;) {
+               cmdscanner(top);
+               top = 1;
+       }
+}
+
+void
+intr()
+{
+       if (!fromatty)
+               exit(0);
+       longjmp(toplevel, 1);
+}
+
+/*
+ * Command parser.
+ */
+cmdscanner(top)
+       int top;
+{
+       register struct cmd *c;
+
+       if (!top)
+               putchar('\n');
+       for (;;) {
+               if (fromatty) {
+                       printf("lpc> ");
+                       fflush(stdout);
+               }
+               if (fgets(cmdline, sizeof(cmdline), stdin) == 0)
+                       quit();
+               if (cmdline[0] == 0 || cmdline[0] == '\n')
+                       break;
+               makeargv();
+               c = getcmd(margv[0]);
+               if (c == (struct cmd *)-1) {
+                       printf("?Ambiguous command\n");
+                       continue;
+               }
+               if (c == 0) {
+                       printf("?Invalid command\n");
+                       continue;
+               }
+               if (c->c_priv && getuid()) {
+                       printf("?Privileged command\n");
+                       continue;
+               }
+               (*c->c_handler)(margc, margv);
+       }
+       longjmp(toplevel, 0);
+}
+
+extern struct cmd cmdtab[];
+
+struct cmd *
+getcmd(name)
+       register char *name;
+{
+       register char *p, *q;
+       register struct cmd *c, *found;
+       register int nmatches, longest;
+
+       longest = 0;
+       nmatches = 0;
+       found = 0;
+       for (c = cmdtab; p = c->c_name; c++) {
+               for (q = name; *q == *p++; q++)
+                       if (*q == 0)            /* exact match? */
+                               return(c);
+               if (!*q) {                      /* the name was a prefix */
+                       if (q - name > longest) {
+                               longest = q - name;
+                               nmatches = 1;
+                               found = c;
+                       } else if (q - name == longest)
+                               nmatches++;
+               }
+       }
+       if (nmatches > 1)
+               return((struct cmd *)-1);
+       return(found);
+}
+
+/*
+ * Slice a string up into argc/argv.
+ */
+makeargv()
+{
+       register char *cp;
+       register char **argp = margv;
+
+       margc = 0;
+       for (cp = cmdline; *cp;) {
+               while (isspace(*cp))
+                       cp++;
+               if (*cp == '\0')
+                       break;
+               *argp++ = cp;
+               margc += 1;
+               while (*cp != '\0' && !isspace(*cp))
+                       cp++;
+               if (*cp == '\0')
+                       break;
+               *cp++ = '\0';
+       }
+       *argp++ = 0;
+}
+
+#define HELPINDENT (sizeof ("directory"))
+
+/*
+ * Help command.
+ */
+help(argc, argv)
+       int argc;
+       char *argv[];
+{
+       register struct cmd *c;
+
+       if (argc == 1) {
+               register int i, j, w;
+               int columns, width = 0, lines;
+               extern int NCMDS;
+
+               printf("Commands may be abbreviated.  Commands are:\n\n");
+               for (c = cmdtab; c->c_name; c++) {
+                       int len = strlen(c->c_name);
+
+                       if (len > width)
+                               width = len;
+               }
+               width = (width + 8) &~ 7;
+               columns = 80 / width;
+               if (columns == 0)
+                       columns = 1;
+               lines = (NCMDS + columns - 1) / columns;
+               for (i = 0; i < lines; i++) {
+                       for (j = 0; j < columns; j++) {
+                               c = cmdtab + j * lines + i;
+                               if (c->c_name)
+                                       printf("%s", c->c_name);
+                               if (c + lines >= &cmdtab[NCMDS]) {
+                                       printf("\n");
+                                       break;
+                               }
+                               w = strlen(c->c_name);
+                               while (w < width) {
+                                       w = (w + 8) &~ 7;
+                                       putchar('\t');
+                               }
+                       }
+               }
+               return;
+       }
+       while (--argc > 0) {
+               register char *arg;
+               arg = *++argv;
+               c = getcmd(arg);
+               if (c == (struct cmd *)-1)
+                       printf("?Ambiguous help command %s\n", arg);
+               else if (c == (struct cmd *)0)
+                       printf("?Invalid help command %s\n", arg);
+               else
+                       printf("%-*s\t%s\n", HELPINDENT,
+                               c->c_name, c->c_help);
+       }
+}
diff --git a/usr/src/usr.sbin/lpr/lpd/lpd.8 b/usr/src/usr.sbin/lpr/lpd/lpd.8
new file mode 100644 (file)
index 0000000..e4a96dd
--- /dev/null
@@ -0,0 +1,249 @@
+.\" Copyright (c) 1983, 1991 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.
+.\"
+.\"     @(#)lpd.8      6.6 (Berkeley) 3/16/91
+.\"
+.Dd March 16, 1991
+.Dt LPD 8
+.Os BSD 4.2
+.Sh NAME
+.Nm lpd
+.Nd line printer spooler daemon
+.Sh SYNOPSIS
+.Nm lpd
+.Op Fl l
+.Op Ar port#
+.Sh DESCRIPTION
+.Nm Lpd
+is the line printer daemon (spool area handler) and is normally invoked
+at boot time from the
+.Xr rc 8
+file.  It makes a single pass through the
+.Xr printcap 5
+file to find out about the existing printers and
+prints any files left after a crash. It then uses the system calls
+.Xr listen 2
+and
+.Xr accept 2
+to receive requests to print files in the queue,
+transfer files to the spooling area, display the queue,
+or remove jobs from the queue.  In each case, it forks a child to handle
+the request so the parent can continue to listen for more requests.
+.Pp
+Available options:
+.Bl -tag -width Ds
+.It Fl l
+The
+.Fl l
+flag causes
+.Nm lpd
+to log valid requests received from the network. This can be useful
+for debugging purposes.
+.It Ar "port#"
+The Internet port number used to rendezvous
+with other processes is normally obtained with
+.Xr getservbyname 3
+but can be changed with the
+.Ar port#
+argument.
+.El
+.Pp
+Access control is provided by two means. First, all requests must come from
+one of the machines listed in the file
+.Pa /etc/hosts.equiv
+or
+.Pa /etc/hosts.lpd .
+Second, if the
+.Li rs
+capability is specified in the
+.Xr printcap
+entry for the printer being accessed,
+.Em lpr
+requests will only be honored for those users with accounts on the
+machine with the printer.
+.Pp
+The file
+.Em minfree
+in each spool directory contains the number of disk blocks to leave free
+so that the line printer queue won't completely fill the disk.
+The
+.Em minfree
+file can be edited with your favorite text editor.
+.Pp
+The daemon begins processing files
+after it has successfully set the lock for exclusive
+access (descibed a bit later),
+and scans the spool directory
+for files beginning with 
+.Em cf .
+Lines in each
+.Em cf
+file specify files to be printed or non-printing actions to be
+performed.  Each such line begins with a key character
+to specify what to do with the remainder of the line.
+.Bl -tag -width Ds
+.It J
+Job Name.  String to be used for the job name on the burst page.
+.It C
+Classification.  String to be used for the classification line
+on the burst page.
+.It L
+Literal.  The line contains identification info from
+the password file and causes the banner page to be printed.
+.It T
+Title.  String to be used as the title for
+.Xr pr 1 .
+.It H
+Host Name.  Name of the machine where
+.Xr lpr
+was invoked.
+.It P
+Person.  Login name of the person who invoked
+.Xr lpr .
+This is used to verify ownership by
+.Xr lprm .
+.It M
+Send mail to the specified user when the current print job completes.
+.It f
+Formatted File.  Name of a file to print which is already formatted.
+.It l
+Like ``f'' but passes control characters and does not make page breaks.
+.It p
+Name of a file to print using
+.Xr pr 1
+as a filter.
+.It t
+Troff File.  The file contains
+.Xr troff 1
+output (cat phototypesetter commands).
+.It n
+Ditroff File.  The file contains device independent troff
+output.
+.It r
+DVI File.  The file contains
+.Tn Tex l
+output
+DVI format from Standford).
+.It g
+Graph File.  The file contains data produced by
+.Xr plot 3 .
+.It c
+Cifplot File. The file contains data produced by
+.Em cifplot .
+.It v
+The file contains a raster image.
+.It r
+The file contains text data with
+FORTRAN carriage control characters.
+.It \&1
+Troff Font R. Name of the font file to use instead of the default.
+.It \&2
+Troff Font I. Name of the font file to use instead of the default.
+.It \&3
+Troff Font B. Name of the font file to use instead of the default.
+.It \&4
+Troff Font S. Name of the font file to use instead of the default.
+.It W
+Width. Changes the page width (in characters) used by
+.Xr pr 1
+and the text filters.
+.It I
+Indent.  The number of characters to indent the output by (in ascii).
+.It U
+Unlink.  Name of file to remove upon completion of printing.
+.It N
+File name.  The name of the file which is being printed, or a blank
+for the standard input (when 
+.Xr lpr
+is invoked in a pipeline).
+.El
+.Pp
+If a file can not be opened, a message will be logged via
+.Xr syslog 3
+using the
+.Em LOG_LPR
+facility.
+.Nm Lpd
+will try up to 20 times
+to reopen a file it expects to be there, after which it will
+skip the file to be printed.
+.Pp
+.Nm Lpd
+uses
+.Xr flock 2
+to provide exclusive access to the lock file and to prevent multiple
+deamons from becoming active simultaneously.  If the daemon should be killed
+or die unexpectedly, the lock file need not be removed.
+The lock file is kept in a readable
+.Tn ASCII
+form
+and contains two lines.
+The first is the process id of the daemon and the second is the control
+file name of the current job being printed.  The second line is updated to
+reflect the current status of
+.Nm lpd
+for the programs
+.Xr lpq 1
+and
+.Xr lprm 1 .
+.Sh FILES
+.Bl -tag -width "/var/spool/*/minfree" -compact
+.It Pa /etc/printcap
+printer description file
+.It Pa /var/spool/*
+spool directories
+.It Pa /var/spool/*/minfree
+minimum free space to leave
+.It Pa /dev/lp*
+line printer devices
+.It Pa /dev/printer
+socket for local requests
+.It Pa /etc/hosts.equiv
+lists machine names allowed printer access
+.It Pa /etc/hosts.lpd
+lists machine names allowed printer access,
+but not under same administrative control.
+.El
+.Sh SEE ALSO
+.Xr lpc 8 ,
+.Xr pac 1 ,
+.Xr lpr 1 ,
+.Xr lpq 1 ,
+.Xr lprm 1 ,
+.Xr syslog 3 ,
+.Xr printcap 5
+.Rs
+.%T "4.2 BSD Line Printer Spooler Manual"
+.Re
+.Sh HISTORY
+An
+.Nm
+daemon appeared in Version 6 AT&T UNIX.
diff --git a/usr/src/usr.sbin/lpr/lpd/lpd.c b/usr/src/usr.sbin/lpr/lpd/lpd.c
new file mode 100644 (file)
index 0000000..edfda93
--- /dev/null
@@ -0,0 +1,464 @@
+/*
+ * Copyright (c) 1983 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
+char copyright[] =
+"@(#) Copyright (c) 1983 Regents of the University of California.\n\
+ All rights reserved.\n";
+#endif /* not lint */
+
+#ifndef lint
+static char sccsid[] = "@(#)lpd.c      5.12 (Berkeley) 3/7/91";
+#endif /* not lint */
+
+/*
+ * lpd -- line printer daemon.
+ *
+ * Listen for a connection and perform the requested operation.
+ * Operations are:
+ *     \1printer\n
+ *             check the queue for jobs and print any found.
+ *     \2printer\n
+ *             receive a job from another machine and queue it.
+ *     \3printer [users ...] [jobs ...]\n
+ *             return the current state of the queue (short form).
+ *     \4printer [users ...] [jobs ...]\n
+ *             return the current state of the queue (long form).
+ *     \5printer person [users ...] [jobs ...]\n
+ *             remove jobs from the queue.
+ *
+ * Strategy to maintain protected spooling area:
+ *     1. Spooling area is writable only by daemon and spooling group
+ *     2. lpr runs setuid root and setgrp spooling group; it uses
+ *        root to access any file it wants (verifying things before
+ *        with an access call) and group id to know how it should
+ *        set up ownership of files in the spooling area.
+ *     3. Files in spooling area are owned by root, group spooling
+ *        group, with mode 660.
+ *     4. lpd, lpq and lprm run setuid daemon and setgrp spooling group to
+ *        access files and printer.  Users can't get to anything
+ *        w/o help of lpq and lprm programs.
+ */
+
+#include "lp.h"
+#include "pathnames.h"
+
+int    lflag;                          /* log requests flag */
+int    from_remote;                    /* from remote socket */
+
+void mcleanup(), reapchild();
+
+main(argc, argv)
+       int argc;
+       char **argv;
+{
+       int f, funix, finet, options = 0, defreadfds, fromlen;
+       struct sockaddr_un sun, fromunix;
+       struct sockaddr_in sin, frominet;
+       int omask, lfd;
+
+       gethostname(host, sizeof(host));
+       name = argv[0];
+
+       while (--argc > 0) {
+               argv++;
+               if (argv[0][0] == '-')
+                       switch (argv[0][1]) {
+                       case 'd':
+                               options |= SO_DEBUG;
+                               break;
+                       case 'l':
+                               lflag++;
+                               break;
+                       }
+       }
+
+#ifndef DEBUG
+       /*
+        * Set up standard environment by detaching from the parent.
+        */
+       daemon(0, 0);
+#endif
+
+       openlog("lpd", LOG_PID, LOG_LPR);
+       (void) umask(0);
+       lfd = open(_PATH_MASTERLOCK, O_WRONLY|O_CREAT, 0644);
+       if (lfd < 0) {
+               syslog(LOG_ERR, "%s: %m", _PATH_MASTERLOCK);
+               exit(1);
+       }
+       if (flock(lfd, LOCK_EX|LOCK_NB) < 0) {
+               if (errno == EWOULDBLOCK)       /* active deamon present */
+                       exit(0);
+               syslog(LOG_ERR, "%s: %m", _PATH_MASTERLOCK);
+               exit(1);
+       }
+       ftruncate(lfd, 0);
+       /*
+        * write process id for others to know
+        */
+       sprintf(line, "%u\n", getpid());
+       f = strlen(line);
+       if (write(lfd, line, f) != f) {
+               syslog(LOG_ERR, "%s: %m", _PATH_MASTERLOCK);
+               exit(1);
+       }
+       signal(SIGCHLD, reapchild);
+       /*
+        * Restart all the printers.
+        */
+       startup();
+       (void) unlink(_PATH_SOCKETNAME);
+       funix = socket(AF_UNIX, SOCK_STREAM, 0);
+       if (funix < 0) {
+               syslog(LOG_ERR, "socket: %m");
+               exit(1);
+       }
+#define        mask(s) (1 << ((s) - 1))
+       omask = sigblock(mask(SIGHUP)|mask(SIGINT)|mask(SIGQUIT)|mask(SIGTERM));
+       signal(SIGHUP, mcleanup);
+       signal(SIGINT, mcleanup);
+       signal(SIGQUIT, mcleanup);
+       signal(SIGTERM, mcleanup);
+       sun.sun_family = AF_UNIX;
+       strcpy(sun.sun_path, _PATH_SOCKETNAME);
+       if (bind(funix,
+            (struct sockaddr *)&sun, strlen(sun.sun_path) + 2) < 0) {
+               syslog(LOG_ERR, "ubind: %m");
+               exit(1);
+       }
+       sigsetmask(omask);
+       defreadfds = 1 << funix;
+       listen(funix, 5);
+       finet = socket(AF_INET, SOCK_STREAM, 0);
+       if (finet >= 0) {
+               struct servent *sp;
+
+               if (options & SO_DEBUG)
+                       if (setsockopt(finet, SOL_SOCKET, SO_DEBUG, 0, 0) < 0) {
+                               syslog(LOG_ERR, "setsockopt (SO_DEBUG): %m");
+                               mcleanup();
+                       }
+               sp = getservbyname("printer", "tcp");
+               if (sp == NULL) {
+                       syslog(LOG_ERR, "printer/tcp: unknown service");
+                       mcleanup();
+               }
+               sin.sin_family = AF_INET;
+               sin.sin_port = sp->s_port;
+               if (bind(finet, (struct sockaddr *)&sin, sizeof(sin)) < 0) {
+                       syslog(LOG_ERR, "bind: %m");
+                       mcleanup();
+               }
+               defreadfds |= 1 << finet;
+               listen(finet, 5);
+       }
+       /*
+        * Main loop: accept, do a request, continue.
+        */
+       for (;;) {
+               int domain, nfds, s, readfds = defreadfds;
+
+               nfds = select(20, &readfds, 0, 0, 0);
+               if (nfds <= 0) {
+                       if (nfds < 0 && errno != EINTR)
+                               syslog(LOG_WARNING, "select: %m");
+                       continue;
+               }
+               if (readfds & (1 << funix)) {
+                       domain = AF_UNIX, fromlen = sizeof(fromunix);
+                       s = accept(funix,
+                           (struct sockaddr *)&fromunix, &fromlen);
+               } else if (readfds & (1 << finet)) {
+                       domain = AF_INET, fromlen = sizeof(frominet);
+                       s = accept(finet,
+                           (struct sockaddr *)&frominet, &fromlen);
+               }
+               if (s < 0) {
+                       if (errno != EINTR)
+                               syslog(LOG_WARNING, "accept: %m");
+                       continue;
+               }
+               if (fork() == 0) {
+                       signal(SIGCHLD, SIG_IGN);
+                       signal(SIGHUP, SIG_IGN);
+                       signal(SIGINT, SIG_IGN);
+                       signal(SIGQUIT, SIG_IGN);
+                       signal(SIGTERM, SIG_IGN);
+                       (void) close(funix);
+                       (void) close(finet);
+                       dup2(s, 1);
+                       (void) close(s);
+                       if (domain == AF_INET) {
+                               from_remote = 1;
+                               chkhost(&frominet);
+                       } else
+                               from_remote = 0;
+                       doit();
+                       exit(0);
+               }
+               (void) close(s);
+       }
+}
+
+void
+reapchild()
+{
+       union wait status;
+
+       while (wait3((int *)&status, WNOHANG, 0) > 0)
+               ;
+}
+
+void
+mcleanup()
+{
+       if (lflag)
+               syslog(LOG_INFO, "exiting");
+       unlink(_PATH_SOCKETNAME);
+       exit(0);
+}
+
+/*
+ * Stuff for handling job specifications
+ */
+char   *user[MAXUSERS];        /* users to process */
+int    users;                  /* # of users in user array */
+int    requ[MAXREQUESTS];      /* job number of spool entries */
+int    requests;               /* # of spool requests */
+char   *person;                /* name of person doing lprm */
+
+char   fromb[32];      /* buffer for client's machine name */
+char   cbuf[BUFSIZ];   /* command line buffer */
+char   *cmdnames[] = {
+       "null",
+       "printjob",
+       "recvjob",
+       "displayq short",
+       "displayq long",
+       "rmjob"
+};
+
+doit()
+{
+       register char *cp;
+       register int n;
+
+       for (;;) {
+               cp = cbuf;
+               do {
+                       if (cp >= &cbuf[sizeof(cbuf) - 1])
+                               fatal("Command line too long");
+                       if ((n = read(1, cp, 1)) != 1) {
+                               if (n < 0)
+                                       fatal("Lost connection");
+                               return;
+                       }
+               } while (*cp++ != '\n');
+               *--cp = '\0';
+               cp = cbuf;
+               if (lflag) {
+                       if (*cp >= '\1' && *cp <= '\5')
+                               syslog(LOG_INFO, "%s requests %s %s",
+                                       from, cmdnames[*cp], cp+1);
+                       else
+                               syslog(LOG_INFO, "bad request (%d) from %s",
+                                       *cp, from);
+               }
+               switch (*cp++) {
+               case '\1':      /* check the queue and print any jobs there */
+                       printer = cp;
+                       printjob();
+                       break;
+               case '\2':      /* receive files to be queued */
+                       if (!from_remote) {
+                               syslog(LOG_INFO, "illegal request (%d)", *cp);
+                               exit(1);
+                       }
+                       printer = cp;
+                       recvjob();
+                       break;
+               case '\3':      /* display the queue (short form) */
+               case '\4':      /* display the queue (long form) */
+                       printer = cp;
+                       while (*cp) {
+                               if (*cp != ' ') {
+                                       cp++;
+                                       continue;
+                               }
+                               *cp++ = '\0';
+                               while (isspace(*cp))
+                                       cp++;
+                               if (*cp == '\0')
+                                       break;
+                               if (isdigit(*cp)) {
+                                       if (requests >= MAXREQUESTS)
+                                               fatal("Too many requests");
+                                       requ[requests++] = atoi(cp);
+                               } else {
+                                       if (users >= MAXUSERS)
+                                               fatal("Too many users");
+                                       user[users++] = cp;
+                               }
+                       }
+                       displayq(cbuf[0] - '\3');
+                       exit(0);
+               case '\5':      /* remove a job from the queue */
+                       if (!from_remote) {
+                               syslog(LOG_INFO, "illegal request (%d)", *cp);
+                               exit(1);
+                       }
+                       printer = cp;
+                       while (*cp && *cp != ' ')
+                               cp++;
+                       if (!*cp)
+                               break;
+                       *cp++ = '\0';
+                       person = cp;
+                       while (*cp) {
+                               if (*cp != ' ') {
+                                       cp++;
+                                       continue;
+                               }
+                               *cp++ = '\0';
+                               while (isspace(*cp))
+                                       cp++;
+                               if (*cp == '\0')
+                                       break;
+                               if (isdigit(*cp)) {
+                                       if (requests >= MAXREQUESTS)
+                                               fatal("Too many requests");
+                                       requ[requests++] = atoi(cp);
+                               } else {
+                                       if (users >= MAXUSERS)
+                                               fatal("Too many users");
+                                       user[users++] = cp;
+                               }
+                       }
+                       rmjob();
+                       break;
+               }
+               fatal("Illegal service request");
+       }
+}
+
+/*
+ * Make a pass through the printcap database and start printing any
+ * files left from the last time the machine went down.
+ */
+startup()
+{
+       char buf[BUFSIZ];
+       register char *cp;
+       int pid;
+
+       printer = buf;
+
+       /*
+        * Restart the daemons.
+        */
+       while (getprent(buf) > 0) {
+               for (cp = buf; *cp; cp++)
+                       if (*cp == '|' || *cp == ':') {
+                               *cp = '\0';
+                               break;
+                       }
+               if ((pid = fork()) < 0) {
+                       syslog(LOG_WARNING, "startup: cannot fork");
+                       mcleanup();
+               }
+               if (!pid) {
+                       endprent();
+                       printjob();
+               }
+       }
+}
+
+#define DUMMY ":nobody::"
+
+/*
+ * Check to see if the from host has access to the line printer.
+ */
+chkhost(f)
+       struct sockaddr_in *f;
+{
+       register struct hostent *hp;
+       register FILE *hostf;
+       register char *cp, *sp;
+       char ahost[50];
+       int first = 1;
+       extern char *inet_ntoa();
+       int baselen = -1;
+
+       f->sin_port = ntohs(f->sin_port);
+       if (f->sin_family != AF_INET || f->sin_port >= IPPORT_RESERVED)
+               fatal("Malformed from address");
+       hp = gethostbyaddr((char *)&f->sin_addr,
+           sizeof(struct in_addr), f->sin_family);
+       if (hp == 0)
+               fatal("Host name for your address (%s) unknown",
+                       inet_ntoa(f->sin_addr));
+
+       strcpy(fromb, hp->h_name);
+       from = fromb;
+       if (!strcmp(from, host))
+               return;
+
+       sp = fromb;
+       cp = ahost;
+       while (*sp) {
+               if (*sp == '.') {
+                       if (baselen == -1)
+                               baselen = sp - fromb;
+                       *cp++ = *sp++;
+               } else {
+                       *cp++ = isupper(*sp) ? tolower(*sp++) : *sp++;
+               }
+       }
+       *cp = '\0';
+       hostf = fopen(_PATH_HOSTSEQUIV, "r");
+again:
+       if (hostf) {
+               if (!_validuser(hostf, ahost, DUMMY, DUMMY, baselen)) {
+                       (void) fclose(hostf);
+                       return;
+               }
+               (void) fclose(hostf);
+       }
+       if (first == 1) {
+               first = 0;
+               hostf = fopen(_PATH_HOSTSLPD, "r");
+               goto again;
+       }
+       fatal("Your host does not have line printer access");
+}
diff --git a/usr/src/usr.sbin/lpr/lpd/lpdchar.c b/usr/src/usr.sbin/lpr/lpd/lpdchar.c
new file mode 100644 (file)
index 0000000..74ac467
--- /dev/null
@@ -0,0 +1,1066 @@
+/*
+ * Copyright (c) 1983 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 sccsid[] = "@(#)lpdchar.c  5.4 (Berkeley) 6/1/90";
+#endif /* not lint */
+
+/*
+ *     Character set for line printer daemon
+ */
+#include "lp.local.h"
+
+#define c_______ 0
+#define c______1 01
+#define c_____1_ 02
+#define c____1__ 04
+#define c____11_ 06
+#define c___1___ 010
+#define c___1__1 011
+#define c___1_1_ 012
+#define c___11__ 014
+#define c__1____ 020
+#define c__1__1_ 022
+#define c__1_1__ 024
+#define c__11___ 030
+#define c__111__ 034
+#define c__111_1 035
+#define c__1111_ 036
+#define c__11111 037
+#define c_1_____ 040
+#define c_1____1 041
+#define c_1___1_ 042
+#define c_1__1__ 044
+#define c_1_1___ 050
+#define c_1_1__1 051
+#define c_1_1_1_ 052
+#define c_11____ 060
+#define c_11_11_ 066
+#define c_111___ 070
+#define c_111__1 071
+#define c_111_1_ 072
+#define c_1111__ 074
+#define c_1111_1 075
+#define c_11111_ 076
+#define c_111111 077
+#define c1______ 0100
+#define c1_____1 0101
+#define c1____1_ 0102
+#define c1____11 0103
+#define c1___1__ 0104
+#define c1___1_1 0105
+#define c1___11_ 0106
+#define c1__1___ 0110
+#define c1__1__1 0111
+#define c1__11_1 0115
+#define c1__1111 0117
+#define c1_1____ 0120
+#define c1_1___1 0121
+#define c1_1_1_1 0125
+#define c1_1_11_ 0126
+#define c1_111__ 0134
+#define c1_1111_ 0136
+#define c11____1 0141
+#define c11___1_ 0142
+#define c11___11 0143
+#define c11_1___ 0150
+#define c11_1__1 0151
+#define c111_11_ 0166
+#define c1111___ 0170
+#define c11111__ 0174
+#define c111111_ 0176
+#define c1111111 0177
+
+char scnkey[][HEIGHT] =        /* this is relatively easy to modify */
+                       /* just look: */
+{
+       { c_______,
+         c_______,
+         c_______,
+         c_______,
+         c_______,
+         c_______,
+         c_______,
+         c_______,
+         c_______ },                   /*   */
+
+       { c__11___,
+         c__11___,
+         c__11___,
+         c__11___,
+         c__11___,
+         c_______,
+         c_______,
+         c__11___,
+         c__11___ },                   /* ! */
+
+       { c_1__1__,
+         c_1__1__,
+         c_______,
+         c_______,
+         c_______,
+         c_______,
+         c_______,
+         c_______,
+         c_______ },                   /* " */
+
+       { c_______,
+         c__1_1__,
+         c__1_1__,
+         c1111111,
+         c__1_1__,
+         c1111111,
+         c__1_1__,
+         c__1_1__,
+         c_______ },                   /* # */
+
+       { c___1___,
+         c_11111_,
+         c1__1__1,
+         c1__1___,
+         c_11111_,
+         c___1__1,
+         c1__1__1,
+         c_11111_,
+         c___1___ },                   /* $ */
+
+       { c_1_____,
+         c1_1___1,
+         c_1___1_,
+         c____1__,
+         c___1___,
+         c__1____,
+         c_1___1_,
+         c1___1_1,
+         c_____1_ },                   /* % */
+       { c_11____,
+         c1__1___,
+         c1___1__,
+         c_1_1___,
+         c__1____,
+         c_1_1__1,
+         c1___11_,
+         c1___11_,
+         c_111__1 },                   /* & */
+       { c___11__,
+         c___11__,
+         c___1___,
+         c__1____,
+         c_______,
+         c_______,
+         c_______,
+         c_______,
+         c_______ },                   /* ' */
+       { c____1__,
+         c___1___,
+         c__1____,
+         c__1____,
+         c__1____,
+         c__1____,
+         c__1____,
+         c___1___,
+         c____1__ },                   /* ( */
+       { c__1____,
+         c___1___,
+         c____1__,
+         c____1__,
+         c____1__,
+         c____1__,
+         c____1__,
+         c___1___,
+         c__1____ },                   /* ) */
+       { c_______,
+         c___1___,
+         c1__1__1,
+         c_1_1_1_,
+         c__111__,
+         c_1_1_1_,
+         c1__1__1,
+         c___1___,
+         c_______ },                   /* * */
+       { c_______,
+         c___1___,
+         c___1___,
+         c___1___,
+         c1111111,
+         c___1___,
+         c___1___,
+         c___1___,
+         c_______ },                   /* + */
+       { c_______,
+         c_______,
+         c_______,
+         c_______,
+         c__11___,
+         c__11___,
+         c__1____,
+         c_1_____,
+         c_______ },                   /* , */
+       { c_______,
+         c_______,
+         c_______,
+         c_______,
+         c1111111,
+         c_______,
+         c_______,
+         c_______,
+         c_______ },                   /* - */
+       { c_______,
+         c_______,
+         c_______,
+         c_______,
+         c_______,
+         c_______,
+         c_______,
+         c__11___,
+         c__11___ },                   /* . */
+
+       { c_______,
+         c______1,
+         c_____1_,
+         c____1__,
+         c___1___,
+         c__1____,
+         c_1_____,
+         c1______,
+         c_______ },                   /* / */
+
+       { c_11111_,
+         c1_____1,
+         c1____11,
+         c1___1_1,
+         c1__1__1,
+         c1_1___1,
+         c11____1,
+         c1_____1,
+         c_11111_ },                   /* 0 */
+
+       { c___1___,
+         c__11___,
+         c_1_1___,
+         c___1___,
+         c___1___,
+         c___1___,
+         c___1___,
+         c___1___,
+         c_11111_ },                   /* 1 */
+
+       { c_11111_,
+         c1_____1,
+         c______1,
+         c_____1_,
+         c__111__,
+         c_1_____,
+         c1______,
+         c1______,
+         c1111111 },                   /* 2 */
+
+       { c_11111_,
+         c1_____1,
+         c______1,
+         c______1,
+         c__1111_,
+         c______1,
+         c______1,
+         c1_____1,
+         c_11111_ },                   /* 3 */
+
+       { c_____1_,
+         c____11_,
+         c___1_1_,
+         c__1__1_,
+         c_1___1_,
+         c1____1_,
+         c1111111,
+         c_____1_,
+         c_____1_ },                   /* 4 */
+
+       { c1111111,
+         c1______,
+         c1______,
+         c11111__,
+         c_____1_,
+         c______1,
+         c______1,
+         c1____1_,
+         c_1111__ },                   /* 5 */
+
+       { c__1111_,
+         c_1_____,
+         c1______,
+         c1______,
+         c1_1111_,
+         c11____1,
+         c1_____1,
+         c1_____1,
+         c_11111_ },                   /* 6 */
+
+       { c1111111,
+         c1_____1,
+         c_____1_,
+         c____1__,
+         c___1___,
+         c__1____,
+         c__1____,
+         c__1____,
+         c__1____ },                   /* 7 */
+
+       { c_11111_,
+         c1_____1,
+         c1_____1,
+         c1_____1,
+         c_11111_,
+         c1_____1,
+         c1_____1,
+         c1_____1,
+         c_11111_ },                   /* 8 */
+
+       { c_11111_,
+         c1_____1,
+         c1_____1,
+         c1_____1,
+         c_111111,
+         c______1,
+         c______1,
+         c1_____1,
+         c_1111__ },                   /* 9 */
+
+       { c_______,
+         c_______,
+         c_______,
+         c__11___,
+         c__11___,
+         c_______,
+         c_______,
+         c__11___,
+         c__11___ },                   /* : */
+
+
+       { c__11___,
+         c__11___,
+         c_______,
+         c_______,
+         c__11___,
+         c__11___,
+         c__1____,
+         c_1_____,
+         c_______ },                   /* ; */
+
+       { c____1__,
+         c___1___,
+         c__1____,
+         c_1_____,
+         c1______,
+         c_1_____,
+         c__1____,
+         c___1___,
+         c____1__ },                   /* < */
+
+       { c_______,
+         c_______,
+         c_______,
+         c1111111,
+         c_______,
+         c1111111,
+         c_______,
+         c_______,
+         c_______ },                   /* = */
+
+       { c__1____,
+         c___1___,
+         c____1__,
+         c_____1_,
+         c______1,
+         c_____1_,
+         c____1__,
+         c___1___,
+         c__1____ },                   /* > */
+
+       { c__1111_,
+         c_1____1,
+         c_1____1,
+         c______1,
+         c____11_,
+         c___1___,
+         c___1___,
+         c_______,
+         c___1___ },                   /* ? */
+
+       { c__1111_,
+         c_1____1,
+         c1__11_1,
+         c1_1_1_1,
+         c1_1_1_1,
+         c1_1111_,
+         c1______,
+         c_1____1,
+         c__1111_ },                   /* @ */
+
+       { c__111__,
+         c_1___1_,
+         c1_____1,
+         c1_____1,
+         c1111111,
+         c1_____1,
+         c1_____1,
+         c1_____1,
+         c1_____1 },                   /* A */
+
+       { c111111_,
+         c_1____1,
+         c_1____1,
+         c_1____1,
+         c_11111_,
+         c_1____1,
+         c_1____1,
+         c_1____1,
+         c111111_ },                   /* B */
+
+       { c__1111_,
+         c_1____1,
+         c1______,
+         c1______,
+         c1______,
+         c1______,
+         c1______,
+         c_1____1,
+         c__1111_ },                   /* C */
+
+       { c11111__,
+         c_1___1_,
+         c_1____1,
+         c_1____1,
+         c_1____1,
+         c_1____1,
+         c_1____1,
+         c_1___1_,
+         c11111__ },                   /* D */
+
+       { c1111111,
+         c1______,
+         c1______,
+         c1______,
+         c111111_,
+         c1______,
+         c1______,
+         c1______,
+         c1111111 },                   /* E */
+
+       { c1111111,
+         c1______,
+         c1______,
+         c1______,
+         c111111_,
+         c1______,
+         c1______,
+         c1______,
+         c1______ },                   /* F */
+
+       { c__1111_,
+         c_1____1,
+         c1______,
+         c1______,
+         c1______,
+         c1__1111,
+         c1_____1,
+         c_1____1,
+         c__1111_ },                   /* G */
+
+       { c1_____1,
+         c1_____1,
+         c1_____1,
+         c1_____1,
+         c1111111,
+         c1_____1,
+         c1_____1,
+         c1_____1,
+         c1_____1 },                   /* H */
+
+       { c_11111_,
+         c___1___,
+         c___1___,
+         c___1___,
+         c___1___,
+         c___1___,
+         c___1___,
+         c___1___,
+         c_11111_ },                   /* I */
+
+       { c__11111,
+         c____1__,
+         c____1__,
+         c____1__,
+         c____1__,
+         c____1__,
+         c____1__,
+         c1___1__,
+         c_111___ },                   /* J */
+
+       { c1_____1,
+         c1____1_,
+         c1___1__,
+         c1__1___,
+         c1_1____,
+         c11_1___,
+         c1___1__,
+         c1____1_,
+         c1_____1 },                   /* K */
+
+       { c1______,
+         c1______,
+         c1______,
+         c1______,
+         c1______,
+         c1______,
+         c1______,
+         c1______,
+         c1111111 },                   /* L */
+
+       { c1_____1,
+         c11___11,
+         c1_1_1_1,
+         c1__1__1,
+         c1_____1,
+         c1_____1,
+         c1_____1,
+         c1_____1,
+         c1_____1 },                   /* M */
+
+       { c1_____1,
+         c11____1,
+         c1_1___1,
+         c1__1__1,
+         c1___1_1,
+         c1____11,
+         c1_____1,
+         c1_____1,
+         c1_____1 },                   /* N */
+
+       { c__111__,
+         c_1___1_,
+         c1_____1,
+         c1_____1,
+         c1_____1,
+         c1_____1,
+         c1_____1,
+         c_1___1_,
+         c__111__ },                   /* O */
+
+       { c111111_,
+         c1_____1,
+         c1_____1,
+         c1_____1,
+         c111111_,
+         c1______,
+         c1______,
+         c1______,
+         c1______ },                   /* P */
+
+       { c__111__,
+         c_1___1_,
+         c1_____1,
+         c1_____1,
+         c1_____1,
+         c1__1__1,
+         c1___1_1,
+         c_1___1_,
+         c__111_1 },                   /* Q */
+
+       { c111111_,
+         c1_____1,
+         c1_____1,
+         c1_____1,
+         c111111_,
+         c1__1___,
+         c1___1__,
+         c1____1_,
+         c1_____1 },                   /* R */
+
+       { c_11111_,
+         c1_____1,
+         c1______,
+         c1______,
+         c_11111_,
+         c______1,
+         c______1,
+         c1_____1,
+         c_11111_ },                   /* S */
+
+       { c1111111,
+         c___1___,
+         c___1___,
+         c___1___,
+         c___1___,
+         c___1___,
+         c___1___,
+         c___1___,
+         c___1___ },                   /* T */
+
+       { c1_____1,
+         c1_____1,
+         c1_____1,
+         c1_____1,
+         c1_____1,
+         c1_____1,
+         c1_____1,
+         c1_____1,
+         c_11111_ },                   /* U */
+
+       { c1_____1,
+         c1_____1,
+         c1_____1,
+         c_1___1_,
+         c_1___1_,
+         c__1_1__,
+         c__1_1__,
+         c___1___,
+         c___1___ },                   /* V */
+
+       { c1_____1,
+         c1_____1,
+         c1_____1,
+         c1_____1,
+         c1__1__1,
+         c1__1__1,
+         c1_1_1_1,
+         c11___11,
+         c1_____1 },                   /* W */
+
+       { c1_____1,
+         c1_____1,
+         c_1___1_,
+         c__1_1__,
+         c___1___,
+         c__1_1__,
+         c_1___1_,
+         c1_____1,
+         c1_____1 },                   /* X */
+
+       { c1_____1,
+         c1_____1,
+         c_1___1_,
+         c__1_1__,
+         c___1___,
+         c___1___,
+         c___1___,
+         c___1___,
+         c___1___ },                   /* Y */
+
+       { c1111111,
+         c______1,
+         c_____1_,
+         c____1__,
+         c___1___,
+         c__1____,
+         c_1_____,
+         c1______,
+         c1111111 },                   /* Z */
+
+       { c_1111__,
+         c_1_____,
+         c_1_____,
+         c_1_____,
+         c_1_____,
+         c_1_____,
+         c_1_____,
+         c_1_____,
+         c_1111__ },                   /* [ */
+
+       { c_______,
+         c1______,
+         c_1_____,
+         c__1____,
+         c___1___,
+         c____1__,
+         c_____1_,
+         c______1,
+         c_______ },                   /* \ */
+
+       { c__1111_,
+         c_____1_,
+         c_____1_,
+         c_____1_,
+         c_____1_,
+         c_____1_,
+         c_____1_,
+         c_____1_,
+         c__1111_ },                   /* ] */
+
+       { c___1___,
+         c__1_1__,
+         c_1___1_,
+         c1_____1,
+         c_______,
+         c_______,
+         c_______,
+         c_______ },                   /* ^ */
+
+       { c_______,
+         c_______,
+         c_______,
+         c_______,
+         c_______,
+         c_______,
+         c_______,
+         c1111111,
+         c_______ },                   /* _ */
+
+       { c__11___,
+         c__11___,
+         c___1___,
+         c____1__,
+         c_______,
+         c_______,
+         c_______,
+         c_______,
+         c_______ },                   /* ` */
+
+       { c_______,
+         c_______,
+         c_______,
+         c_1111__,
+         c_____1_,
+         c_11111_,
+         c1_____1,
+         c1____11,
+         c_1111_1 },                   /* a */
+
+       { c1______,
+         c1______,
+         c1______,
+         c1_111__,
+         c11___1_,
+         c1_____1,
+         c1_____1,
+         c11___1_,
+         c1_111__ },                   /* b */
+
+       { c_______,
+         c_______,
+         c_______,
+         c_1111__,
+         c1____1_,
+         c1______,
+         c1______,
+         c1____1_,
+         c_1111__ },                   /* c */
+
+       { c_____1_,
+         c_____1_,
+         c_____1_,
+         c_111_1_,
+         c1___11_,
+         c1____1_,
+         c1____1_,
+         c1___11_,
+         c_111_1_ },                   /* d */
+
+       { c_______,
+         c_______,
+         c_______,
+         c_1111__,
+         c1____1_,
+         c111111_,
+         c1______,
+         c1____1_,
+         c_1111__ },                   /* e */
+
+       { c___11__,
+         c__1__1_,
+         c__1____,
+         c__1____,
+         c11111__,
+         c__1____,
+         c__1____,
+         c__1____,
+         c__1____ },                   /* f */
+
+       { c_111_1_,
+         c1___11_,
+         c1____1_,
+         c1____1_,
+         c1___11_,
+         c_111_1_,
+         c_____1_,
+         c1____1_,
+         c_1111__ },                   /* g */
+
+       { c1______,
+         c1______,
+         c1______,
+         c1_111__,
+         c11___1_,
+         c1____1_,
+         c1____1_,
+         c1____1_,
+         c1____1_ },                   /* h */
+
+       { c_______,
+         c___1___,
+         c_______,
+         c__11___,
+         c___1___,
+         c___1___,
+         c___1___,
+         c___1___,
+         c__111__ },                   /* i */
+
+       { c____11_,
+         c_____1_,
+         c_____1_,
+         c_____1_,
+         c_____1_,
+         c_____1_,
+         c_____1_,
+         c_1___1_,
+         c__111__ },                   /* j */
+
+       { c1______,
+         c1______,
+         c1______,
+         c1___1__,
+         c1__1___,
+         c1_1____,
+         c11_1___,
+         c1___1__,
+         c1____1_ },                   /* k */
+
+       { c__11___,
+         c___1___,
+         c___1___,
+         c___1___,
+         c___1___,
+         c___1___,
+         c___1___,
+         c___1___,
+         c__111__ },                   /* l */
+
+       { c_______,
+         c_______,
+         c_______,
+         c1_1_11_,
+         c11_1__1,
+         c1__1__1,
+         c1__1__1,
+         c1__1__1,
+         c1__1__1 },                   /* m */
+
+       { c_______,
+         c_______,
+         c_______,
+         c1_111__,
+         c11___1_,
+         c1____1_,
+         c1____1_,
+         c1____1_,
+         c1____1_ },                   /* n */
+
+       { c_______,
+         c_______,
+         c_______,
+         c_1111__,
+         c1____1_,
+         c1____1_,
+         c1____1_,
+         c1____1_,
+         c_1111__ },                   /* o */
+
+       { c1_111__,
+         c11___1_,
+         c1____1_,
+         c1____1_,
+         c11___1_,
+         c1_111__,
+         c1______,
+         c1______,
+         c1______ },                   /* p */
+
+       { c_111_1_,
+         c1___11_,
+         c1____1_,
+         c1____1_,
+         c1___11_,
+         c_111_1_,
+         c_____1_,
+         c_____1_,
+         c_____1_ },                   /* q */
+
+       { c_______,
+         c_______,
+         c_______,
+         c1_111__,
+         c11___1_,
+         c1______,
+         c1______,
+         c1______,
+         c1______ },                   /* r */
+
+       { c_______,
+         c_______,
+         c_______,
+         c_1111__,
+         c1____1_,
+         c_11____,
+         c___11__,
+         c1____1_,
+         c_1111__ },                   /* s */
+
+       { c_______,
+         c__1____,
+         c__1____,
+         c11111__,
+         c__1____,
+         c__1____,
+         c__1____,
+         c__1__1_,
+         c___11__ },                   /* t */
+
+       { c_______,
+         c_______,
+         c_______,
+         c1____1_,
+         c1____1_,
+         c1____1_,
+         c1____1_,
+         c1___11_,
+         c_111_1_ },                   /* u */
+
+       { c_______,
+         c_______,
+         c_______,
+         c1_____1,
+         c1_____1,
+         c1_____1,
+         c_1___1_,
+         c__1_1__,
+         c___1___ },                   /* v */
+
+       { c_______,
+         c_______,
+         c_______,
+         c1_____1,
+         c1__1__1,
+         c1__1__1,
+         c1__1__1,
+         c1__1__1,
+         c_11_11_ },                   /* w */
+
+       { c_______,
+         c_______,
+         c_______,
+         c1____1_,
+         c_1__1__,
+         c__11___,
+         c__11___,
+         c_1__1__,
+         c1____1_ },                   /* x */
+
+       { c1____1_,
+         c1____1_,
+         c1____1_,
+         c1____1_,
+         c1___11_,
+         c_111_1_,
+         c_____1_,
+         c1____1_,
+         c_1111__ },                   /* y */
+
+       { c_______,
+         c_______,
+         c_______,
+         c111111_,
+         c____1__,
+         c___1___,
+         c__1____,
+         c_1_____,
+         c111111_ },                   /* z */
+
+       { c___11__,
+         c__1____,
+         c__1____,
+         c__1____,
+         c_1_____,
+         c__1____,
+         c__1____,
+         c__1____,
+         c___11__ },                   /* } */
+
+       { c___1___,
+         c___1___,
+         c___1___,
+         c___1___,
+         c___1___,
+         c___1___,
+         c___1___,
+         c___1___,
+         c___1___ },                   /* | */
+
+       { c__11___,
+         c____1__,
+         c____1__,
+         c____1__,
+         c_____1_,
+         c____1__,
+         c____1__,
+         c____1__,
+         c__11___ },                   /* } */
+
+       { c_11____,
+         c1__1__1,
+         c____11_,
+         c_______,
+         c_______,
+         c_______,
+         c_______,
+         c_______,
+         c_______ },                   /* ~ */
+
+       { c_1__1__,
+         c1__1__1,
+         c__1__1_,
+         c_1__1__,
+         c1__1__1,
+         c__1__1_,
+         c_1__1__,
+         c1__1__1,
+         c__1__1_ }                    /* rub-out */
+};