From: William F. Jolitz Date: Fri, 19 Apr 1991 20:06:33 +0000 (-0800) Subject: 386BSD 0.1 development X-Git-Tag: 386BSD-0.1~1694 X-Git-Url: https://git.subgeniuskitty.com/unix-history/.git/commitdiff_plain/a31f3663fbb7d7079711fbb5a55a57d7f8126de9?ds=sidebyside 386BSD 0.1 development 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 Synthesized-from: 386BSD-0.1 --- 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 index 0000000000..d7b97cd429 --- /dev/null +++ b/usr/src/usr.sbin/lpr/common_source/common.c @@ -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 index 0000000000..df58c00baf --- /dev/null +++ b/usr/src/usr.sbin/lpr/common_source/displayq.c @@ -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 index 0000000000..1f57657842 --- /dev/null +++ b/usr/src/usr.sbin/lpr/common_source/lp.h @@ -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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#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 index 0000000000..56db34ad7e --- /dev/null +++ b/usr/src/usr.sbin/lpr/common_source/lp.local.h @@ -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 +#include + +#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 index 0000000000..7104d95fab --- /dev/null +++ b/usr/src/usr.sbin/lpr/common_source/lpc.h @@ -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 index 0000000000..907a6dfc8a --- /dev/null +++ b/usr/src/usr.sbin/lpr/common_source/pathnames.h @@ -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 + +#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 index 0000000000..47b1b80c49 --- /dev/null +++ b/usr/src/usr.sbin/lpr/common_source/printcap.c @@ -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 +#include +#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 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 index 0000000000..989c68291f --- /dev/null +++ b/usr/src/usr.sbin/lpr/common_source/rmjob.c @@ -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 index 0000000000..3b3e865363 --- /dev/null +++ b/usr/src/usr.sbin/lpr/common_source/startdaemon.c @@ -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 +#include +#include +#include +#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 index 0000000000..862832b687 --- /dev/null +++ b/usr/src/usr.sbin/lpr/filters/lpf.c @@ -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 +#include + +#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 index 0000000000..471a9c9019 --- /dev/null +++ b/usr/src/usr.sbin/lpr/lpc/cmds.c @@ -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 +#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 index 0000000000..ad52316cca --- /dev/null +++ b/usr/src/usr.sbin/lpr/lpc/cmdtab.c @@ -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 index 0000000000..f69169ac4e --- /dev/null +++ b/usr/src/usr.sbin/lpr/lpc/lpc.8 @@ -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 index 0000000000..0f38315107 --- /dev/null +++ b/usr/src/usr.sbin/lpr/lpc/lpc.c @@ -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 +#include +#include +#include +#include + +#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 index 0000000000..e4a96dd661 --- /dev/null +++ b/usr/src/usr.sbin/lpr/lpd/lpd.8 @@ -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 index 0000000000..edfda93329 --- /dev/null +++ b/usr/src/usr.sbin/lpr/lpd/lpd.c @@ -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 index 0000000000..74ac467bec --- /dev/null +++ b/usr/src/usr.sbin/lpr/lpd/lpdchar.c @@ -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 */ +};