--- /dev/null
+/*
+ * 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);
+}
--- /dev/null
+/*
+ * 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);
+}
--- /dev/null
+/*
+ * Copyright (c) 1983 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)lp.h 5.5 (Berkeley) 6/1/90
+ */
+
+/*
+ * Global definitions for the line printer system.
+ */
+
+#include <stdio.h>
+#include <sys/param.h>
+#include <sys/file.h>
+#include <sys/dir.h>
+#include <sys/stat.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <netinet/in.h>
+#include <netdb.h>
+#include <pwd.h>
+#include <syslog.h>
+#include <signal.h>
+#include <sys/wait.h>
+#include <sgtty.h>
+#include <ctype.h>
+#include <errno.h>
+#include "lp.local.h"
+
+extern int DU; /* daeomon user-id */
+extern int MX; /* maximum number of blocks to copy */
+extern int MC; /* maximum number of copies allowed */
+extern char *LP; /* line printer device name */
+extern char *RM; /* remote machine name */
+extern char *RG; /* restricted group */
+extern char *RP; /* remote printer name */
+extern char *LO; /* lock file name */
+extern char *ST; /* status file name */
+extern char *SD; /* spool directory */
+extern char *AF; /* accounting file */
+extern char *LF; /* log file for error messages */
+extern char *OF; /* name of output filter (created once) */
+extern char *IF; /* name of input filter (created per job) */
+extern char *RF; /* name of fortran text filter (per job) */
+extern char *TF; /* name of troff(1) filter (per job) */
+extern char *NF; /* name of ditroff(1) filter (per job) */
+extern char *DF; /* name of tex filter (per job) */
+extern char *GF; /* name of graph(1G) filter (per job) */
+extern char *VF; /* name of raster filter (per job) */
+extern char *CF; /* name of cifplot filter (per job) */
+extern char *FF; /* form feed string */
+extern char *TR; /* trailer string to be output when Q empties */
+extern short SC; /* suppress multiple copies */
+extern short SF; /* suppress FF on each print job */
+extern short SH; /* suppress header page */
+extern short SB; /* short banner instead of normal header */
+extern short HL; /* print header last */
+extern short RW; /* open LP for reading and writing */
+extern short PW; /* page width */
+extern short PX; /* page width in pixels */
+extern short PY; /* page length in pixels */
+extern short PL; /* page length */
+extern short BR; /* baud rate if lp is a tty */
+extern int FC; /* flags to clear if lp is a tty */
+extern int FS; /* flags to set if lp is a tty */
+extern int XC; /* flags to clear for local mode */
+extern int XS; /* flags to set for local mode */
+extern short RS; /* restricted to those with local accounts */
+
+extern char line[BUFSIZ];
+extern char pbuf[]; /* buffer for printcap entry */
+extern char *bp; /* pointer into ebuf for pgetent() */
+extern char *name; /* program name */
+extern char *printer; /* printer name */
+extern char host[32]; /* host machine name */
+extern char *from; /* client's machine name */
+extern int sendtorem; /* are we sending to a remote? */
+extern int errno;
+
+/*
+ * Structure used for building a sorted list of control files.
+ */
+struct queue {
+ time_t q_time; /* modification time */
+ char q_name[MAXNAMLEN+1]; /* control file name */
+};
+
+char *pgetstr();
+char *malloc();
+char *getenv();
+char *index();
+char *rindex();
+char *checkremote();
--- /dev/null
+/*
+ * Copyright (c) 1983 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)lp.local.h 5.5 (Berkeley) 6/1/90
+ */
+
+/*
+ * Possibly, local parameters to the spooling system
+ */
+
+/*
+ * Magic number mapping for binary files, used by lpr to avoid
+ * printing objects files.
+ */
+
+#include <a.out.h>
+#include <ar.h>
+
+#ifndef A_MAGIC1 /* must be a VM/UNIX system */
+# define A_MAGIC1 OMAGIC
+# define A_MAGIC2 NMAGIC
+# define A_MAGIC3 ZMAGIC
+# undef ARMAG
+# define ARMAG 0177545
+#endif
+
+/*
+ * Defaults for line printer capabilities data base
+ */
+#define DEFLP "lp"
+#define DEFLOCK "lock"
+#define DEFSTAT "status"
+#define DEFMX 1000
+#define DEFMAXCOPIES 0
+#define DEFFF "\f"
+#define DEFWIDTH 132
+#define DEFLENGTH 66
+#define DEFUID 1
+
+/*
+ * When files are created in the spooling area, they are normally
+ * readable only by their owner and the spooling group. If you
+ * want otherwise, change this mode.
+ */
+#define FILMOD 0660
+
+/*
+ * Printer is assumed to support LINELEN (for block chars)
+ * and background character (blank) is a space
+ */
+#define LINELEN 132
+#define BACKGND ' '
+
+#define HEIGHT 9 /* height of characters */
+#define WIDTH 8 /* width of characters */
+#define DROP 3 /* offset to drop characters with descenders */
+
+/*
+ * Define TERMCAP if the terminal capabilites are to be used for lpq.
+ */
+#define TERMCAP
+
+/*
+ * Maximum number of user and job requests for lpq and lprm.
+ */
+#define MAXUSERS 50
+#define MAXREQUESTS 50
--- /dev/null
+/*
+ * 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 */
+};
--- /dev/null
+/*
+ * Copyright (c) 1989 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)pathnames.h 5.4 (Berkeley) 6/1/90
+ */
+
+#include <paths.h>
+
+#define _PATH_DEFDEVLP "/dev/lp"
+#define _PATH_DEFSPOOL "/var/spool/output/lpd"
+#define _PATH_HOSTSEQUIV "/etc/hosts.equiv"
+#define _PATH_HOSTSLPD "/etc/hosts.lpd"
+#define _PATH_MASTERLOCK "/var/spool/output/lpd.lock"
+#define _PATH_PR "/usr/bin/pr"
+#define _PATH_PRINTCAP "/etc/printcap"
+#define _PATH_SOCKETNAME "/var/run/printer"
+#define _PATH_VFONT "/usr/libdata/vfont/"
+#define _PATH_VFONTB "/usr/libdata/vfont/B"
+#define _PATH_VFONTI "/usr/libdata/vfont/I"
+#define _PATH_VFONTR "/usr/libdata/vfont/R"
+#define _PATH_VFONTS "/usr/libdata/vfont/S"
--- /dev/null
+/*
+ * Copyright (c) 1983 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)printcap.c 5.7 (Berkeley) 3/4/91";
+#endif /* not lint */
+
+#include <ctype.h>
+#include <stdio.h>
+#include "pathnames.h"
+
+#ifndef BUFSIZ
+#define BUFSIZ 1024
+#endif
+#define MAXHOP 32 /* max number of tc= indirections */
+
+/*
+ * termcap - routines for dealing with the terminal capability data base
+ *
+ * BUG: Should use a "last" pointer in tbuf, so that searching
+ * for capabilities alphabetically would not be a n**2/2
+ * process when large numbers of capabilities are given.
+ * Note: If we add a last pointer now we will screw up the
+ * tc capability. We really should compile termcap.
+ *
+ * Essentially all the work here is scanning and decoding escapes
+ * in string capabilities. We don't use stdio because the editor
+ * doesn't, and because living w/o it is not hard.
+ */
+
+#define PRINTCAP
+
+#ifdef PRINTCAP
+#define tgetent pgetent
+#define tskip pskip
+#define tgetstr pgetstr
+#define tdecode pdecode
+#define tgetnum pgetnum
+#define tgetflag pgetflag
+#define tdecode pdecode
+#define tnchktc pnchktc
+#define tnamatch pnamatch
+#define V6
+#endif
+
+static FILE *pfp = NULL; /* printcap data base file pointer */
+static char *tbuf;
+static int hopcount; /* detect infinite loops in termcap, init 0 */
+char *tskip();
+char *tgetstr();
+char *tdecode();
+char *getenv();
+
+/*
+ * Similar to tgetent except it returns the next enrty instead of
+ * doing a lookup.
+ */
+getprent(bp)
+ register char *bp;
+{
+ register int c, skip = 0;
+
+ if (pfp == NULL && (pfp = fopen(_PATH_PRINTCAP, "r")) == NULL)
+ return(-1);
+ tbuf = bp;
+ for (;;) {
+ switch (c = getc(pfp)) {
+ case EOF:
+ fclose(pfp);
+ pfp = NULL;
+ return(0);
+ case '\n':
+ if (bp == tbuf) {
+ skip = 0;
+ continue;
+ }
+ if (bp[-1] == '\\') {
+ bp--;
+ continue;
+ }
+ *bp = '\0';
+ return(1);
+ case '#':
+ if (bp == tbuf)
+ skip++;
+ default:
+ if (skip)
+ continue;
+ if (bp >= tbuf+BUFSIZ) {
+ write(2, "Termcap entry too long\n", 23);
+ *bp = '\0';
+ return(1);
+ }
+ *bp++ = c;
+ }
+ }
+}
+
+endprent()
+{
+ if (pfp != NULL)
+ fclose(pfp);
+}
+
+/*
+ * Get an entry for terminal name in buffer bp,
+ * from the termcap file. Parse is very rudimentary;
+ * we just notice escaped newlines.
+ */
+tgetent(bp, name)
+ char *bp, *name;
+{
+ register char *cp;
+ register int c;
+ register int i = 0, cnt = 0;
+ char ibuf[BUFSIZ];
+ char *cp2;
+ int tf;
+
+ tbuf = bp;
+ tf = 0;
+#ifndef V6
+ cp = getenv("TERMCAP");
+ /*
+ * TERMCAP can have one of two things in it. It can be the
+ * name of a file to use instead of /etc/termcap. In this
+ * case it better start with a "/". Or it can be an entry to
+ * use so we don't have to read the file. In this case it
+ * has to already have the newlines crunched out.
+ */
+ if (cp && *cp) {
+ if (*cp!='/') {
+ cp2 = getenv("TERM");
+ if (cp2==(char *) 0 || strcmp(name,cp2)==0) {
+ strcpy(bp,cp);
+ return(tnchktc());
+ } else {
+ tf = open(_PATH_PRINTCAP, 0);
+ }
+ } else
+ tf = open(cp, 0);
+ }
+ if (tf==0)
+ tf = open(_PATH_PRINTCAP, 0);
+#else
+ tf = open(_PATH_PRINTCAP, 0);
+#endif
+ if (tf < 0)
+ return (-1);
+ for (;;) {
+ cp = bp;
+ for (;;) {
+ if (i == cnt) {
+ cnt = read(tf, ibuf, BUFSIZ);
+ if (cnt <= 0) {
+ close(tf);
+ return (0);
+ }
+ i = 0;
+ }
+ c = ibuf[i++];
+ if (c == '\n') {
+ if (cp > bp && cp[-1] == '\\'){
+ cp--;
+ continue;
+ }
+ break;
+ }
+ if (cp >= bp+BUFSIZ) {
+ write(2,"Termcap entry too long\n", 23);
+ break;
+ } else
+ *cp++ = c;
+ }
+ *cp = 0;
+
+ /*
+ * The real work for the match.
+ */
+ if (tnamatch(name)) {
+ close(tf);
+ return(tnchktc());
+ }
+ }
+}
+
+/*
+ * tnchktc: check the last entry, see if it's tc=xxx. If so,
+ * recursively find xxx and append that entry (minus the names)
+ * to take the place of the tc=xxx entry. This allows termcap
+ * entries to say "like an HP2621 but doesn't turn on the labels".
+ * Note that this works because of the left to right scan.
+ */
+tnchktc()
+{
+ register char *p, *q;
+ char tcname[16]; /* name of similar terminal */
+ char tcbuf[BUFSIZ];
+ char *holdtbuf = tbuf;
+ int l;
+
+ p = tbuf + strlen(tbuf) - 2; /* before the last colon */
+ while (*--p != ':')
+ if (p<tbuf) {
+ write(2, "Bad termcap entry\n", 18);
+ return (0);
+ }
+ p++;
+ /* p now points to beginning of last field */
+ if (p[0] != 't' || p[1] != 'c')
+ return(1);
+ strcpy(tcname,p+3);
+ q = tcname;
+ while (q && *q != ':')
+ q++;
+ *q = 0;
+ if (++hopcount > MAXHOP) {
+ write(2, "Infinite tc= loop\n", 18);
+ return (0);
+ }
+ if (tgetent(tcbuf, tcname) != 1)
+ return(0);
+ for (q=tcbuf; *q != ':'; q++)
+ ;
+ l = p - holdtbuf + strlen(q);
+ if (l > BUFSIZ) {
+ write(2, "Termcap entry too long\n", 23);
+ q[BUFSIZ - (p-tbuf)] = 0;
+ }
+ strcpy(p, q+1);
+ tbuf = holdtbuf;
+ return(1);
+}
+
+/*
+ * Tnamatch deals with name matching. The first field of the termcap
+ * entry is a sequence of names separated by |'s, so we compare
+ * against each such name. The normal : terminator after the last
+ * name (before the first field) stops us.
+ */
+tnamatch(np)
+ char *np;
+{
+ register char *Np, *Bp;
+
+ Bp = tbuf;
+ if (*Bp == '#')
+ return(0);
+ for (;;) {
+ for (Np = np; *Np && *Bp == *Np; Bp++, Np++)
+ continue;
+ if (*Np == 0 && (*Bp == '|' || *Bp == ':' || *Bp == 0))
+ return (1);
+ while (*Bp && *Bp != ':' && *Bp != '|')
+ Bp++;
+ if (*Bp == 0 || *Bp == ':')
+ return (0);
+ Bp++;
+ }
+}
+
+/*
+ * Skip to the next field. Notice that this is very dumb, not
+ * knowing about \: escapes or any such. If necessary, :'s can be put
+ * into the termcap file in octal.
+ */
+static char *
+tskip(bp)
+ register char *bp;
+{
+
+ while (*bp && *bp != ':')
+ bp++;
+ if (*bp == ':')
+ bp++;
+ return (bp);
+}
+
+/*
+ * Return the (numeric) option id.
+ * Numeric options look like
+ * li#80
+ * i.e. the option string is separated from the numeric value by
+ * a # character. If the option is not found we return -1.
+ * Note that we handle octal numbers beginning with 0.
+ */
+tgetnum(id)
+ char *id;
+{
+ register int i, base;
+ register char *bp = tbuf;
+
+ for (;;) {
+ bp = tskip(bp);
+ if (*bp == 0)
+ return (-1);
+ if (*bp++ != id[0] || *bp == 0 || *bp++ != id[1])
+ continue;
+ if (*bp == '@')
+ return(-1);
+ if (*bp != '#')
+ continue;
+ bp++;
+ base = 10;
+ if (*bp == '0')
+ base = 8;
+ i = 0;
+ while (isdigit(*bp))
+ i *= base, i += *bp++ - '0';
+ return (i);
+ }
+}
+
+/*
+ * Handle a flag option.
+ * Flag options are given "naked", i.e. followed by a : or the end
+ * of the buffer. Return 1 if we find the option, or 0 if it is
+ * not given.
+ */
+tgetflag(id)
+ char *id;
+{
+ register char *bp = tbuf;
+
+ for (;;) {
+ bp = tskip(bp);
+ if (!*bp)
+ return (0);
+ if (*bp++ == id[0] && *bp != 0 && *bp++ == id[1]) {
+ if (!*bp || *bp == ':')
+ return (1);
+ else if (*bp == '@')
+ return(0);
+ }
+ }
+}
+
+/*
+ * Get a string valued option.
+ * These are given as
+ * cl=^Z
+ * Much decoding is done on the strings, and the strings are
+ * placed in area, which is a ref parameter which is updated.
+ * No checking on area overflow.
+ */
+char *
+tgetstr(id, area)
+ char *id, **area;
+{
+ register char *bp = tbuf;
+
+ for (;;) {
+ bp = tskip(bp);
+ if (!*bp)
+ return (0);
+ if (*bp++ != id[0] || *bp == 0 || *bp++ != id[1])
+ continue;
+ if (*bp == '@')
+ return(0);
+ if (*bp != '=')
+ continue;
+ bp++;
+ return (tdecode(bp, area));
+ }
+}
+
+/*
+ * Tdecode does the grung work to decode the
+ * string capability escapes.
+ */
+static char *
+tdecode(str, area)
+ register char *str;
+ char **area;
+{
+ register char *cp;
+ register int c;
+ register char *dp;
+ int i;
+
+ cp = *area;
+ while ((c = *str++) && c != ':') {
+ switch (c) {
+
+ case '^':
+ c = *str++ & 037;
+ break;
+
+ case '\\':
+ dp = "E\033^^\\\\::n\nr\rt\tb\bf\f";
+ c = *str++;
+nextc:
+ if (*dp++ == c) {
+ c = *dp++;
+ break;
+ }
+ dp++;
+ if (*dp)
+ goto nextc;
+ if (isdigit(c)) {
+ c -= '0', i = 2;
+ do
+ c <<= 3, c |= *str++ - '0';
+ while (--i && isdigit(*str));
+ }
+ break;
+ }
+ *cp++ = c;
+ }
+ *cp++ = 0;
+ str = *area;
+ *area = cp;
+ return (str);
+}
--- /dev/null
+/*
+ * 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');
+}
--- /dev/null
+/*
+ * Copyright (c) 1983 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)startdaemon.c 5.7 (Berkeley) 3/2/91";
+#endif /* not lint */
+
+/*
+ * Tell the printer daemon that there are new files in the spool directory.
+ */
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <stdio.h>
+#include "lp.local.h"
+#include "pathnames.h"
+
+startdaemon(printer)
+ char *printer;
+{
+ struct sockaddr_un sun;
+ register int s, n;
+ char buf[BUFSIZ];
+ static void perr();
+
+ s = socket(AF_UNIX, SOCK_STREAM, 0);
+ if (s < 0) {
+ perr("socket");
+ return(0);
+ }
+ sun.sun_family = AF_UNIX;
+ strcpy(sun.sun_path, _PATH_SOCKETNAME);
+ if (connect(s, (struct sockaddr *)&sun, strlen(sun.sun_path) + 2) < 0) {
+ perr("connect");
+ (void) close(s);
+ return(0);
+ }
+ (void) sprintf(buf, "\1%s\n", printer);
+ n = strlen(buf);
+ if (write(s, buf, n) != n) {
+ perr("write");
+ (void) close(s);
+ return(0);
+ }
+ if (read(s, buf, 1) == 1) {
+ if (buf[0] == '\0') { /* everything is OK */
+ (void) close(s);
+ return(1);
+ }
+ putchar(buf[0]);
+ }
+ while ((n = read(s, buf, sizeof(buf))) > 0)
+ fwrite(buf, 1, n, stdout);
+ (void) close(s);
+ return(0);
+}
+
+static void
+perr(msg)
+ char *msg;
+{
+ extern int errno;
+ extern char *name;
+ char *strerror();
+
+ (void)printf("%s: %s: %s\n", name, msg, strerror(errno));
+}
--- /dev/null
+/*
+ * Copyright (c) 1983 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+char copyright[] =
+"@(#) Copyright (c) 1983 Regents of the University of California.\n\
+ All rights reserved.\n";
+#endif /* not lint */
+
+#ifndef lint
+static char sccsid[] = "@(#)lpf.c 5.4 (Berkeley) 6/1/90";
+#endif /* not lint */
+
+/*
+ * filter which reads the output of nroff and converts lines
+ * with ^H's to overwritten lines. Thus this works like 'ul'
+ * but is much better: it can handle more than 2 overwrites
+ * and it is written with some style.
+ * modified by kls to use register references instead of arrays
+ * to try to gain a little speed.
+ */
+
+#include <stdio.h>
+#include <signal.h>
+
+#define MAXWIDTH 132
+#define MAXREP 10
+
+char buf[MAXREP][MAXWIDTH];
+int maxcol[MAXREP] = {-1};
+int lineno;
+int width = 132; /* default line length */
+int length = 66; /* page length */
+int indent; /* indentation length */
+int npages = 1;
+int literal; /* print control characters */
+char *name; /* user's login name */
+char *host; /* user's machine name */
+char *acctfile; /* accounting information file */
+
+main(argc, argv)
+ int argc;
+ char *argv[];
+{
+ register FILE *p = stdin, *o = stdout;
+ register int i, col;
+ register char *cp;
+ int done, linedone, maxrep;
+ char ch, *limit;
+
+ while (--argc) {
+ if (*(cp = *++argv) == '-') {
+ switch (cp[1]) {
+ case 'n':
+ argc--;
+ name = *++argv;
+ break;
+
+ case 'h':
+ argc--;
+ host = *++argv;
+ break;
+
+ case 'w':
+ if ((i = atoi(&cp[2])) > 0 && i <= MAXWIDTH)
+ width = i;
+ break;
+
+ case 'l':
+ length = atoi(&cp[2]);
+ break;
+
+ case 'i':
+ indent = atoi(&cp[2]);
+ break;
+
+ case 'c': /* Print control chars */
+ literal++;
+ break;
+ }
+ } else
+ acctfile = cp;
+ }
+
+ for (cp = buf[0], limit = buf[MAXREP]; cp < limit; *cp++ = ' ');
+ done = 0;
+
+ while (!done) {
+ col = indent;
+ maxrep = -1;
+ linedone = 0;
+ while (!linedone) {
+ switch (ch = getc(p)) {
+ case EOF:
+ linedone = done = 1;
+ ch = '\n';
+ break;
+
+ case '\f':
+ lineno = length;
+ case '\n':
+ if (maxrep < 0)
+ maxrep = 0;
+ linedone = 1;
+ break;
+
+ case '\b':
+ if (--col < indent)
+ col = indent;
+ break;
+
+ case '\r':
+ col = indent;
+ break;
+
+ case '\t':
+ col = ((col - indent) | 07) + indent + 1;
+ break;
+
+ case '\031':
+ /*
+ * lpd needs to use a different filter to
+ * print data so stop what we are doing and
+ * wait for lpd to restart us.
+ */
+ if ((ch = getchar()) == '\1') {
+ fflush(stdout);
+ kill(getpid(), SIGSTOP);
+ break;
+ } else {
+ ungetc(ch, stdin);
+ ch = '\031';
+ }
+
+ default:
+ if (col >= width || !literal && ch < ' ') {
+ col++;
+ break;
+ }
+ cp = &buf[0][col];
+ for (i = 0; i < MAXREP; i++) {
+ if (i > maxrep)
+ maxrep = i;
+ if (*cp == ' ') {
+ *cp = ch;
+ if (col > maxcol[i])
+ maxcol[i] = col;
+ break;
+ }
+ cp += MAXWIDTH;
+ }
+ col++;
+ break;
+ }
+ }
+
+ /* print out lines */
+ for (i = 0; i <= maxrep; i++) {
+ for (cp = buf[i], limit = cp+maxcol[i]; cp <= limit;) {
+ putc(*cp, o);
+ *cp++ = ' ';
+ }
+ if (i < maxrep)
+ putc('\r', o);
+ else
+ putc(ch, o);
+ if (++lineno >= length) {
+ fflush(o);
+ npages++;
+ lineno = 0;
+ }
+ maxcol[i] = -1;
+ }
+ }
+ if (lineno) { /* be sure to end on a page boundary */
+ putchar('\f');
+ npages++;
+ }
+ if (name && acctfile && access(acctfile, 02) >= 0 &&
+ freopen(acctfile, "a", stdout) != NULL) {
+ printf("%7.2f\t%s:%s\n", (float)npages, host, name);
+ }
+ exit(0);
+}
--- /dev/null
+/*
+ * Copyright (c) 1983 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)cmds.c 5.7 (Berkeley) 6/1/90";
+#endif /* not lint */
+
+/*
+ * lpc -- line printer control program -- commands:
+ */
+
+#include "lp.h"
+#include <sys/time.h>
+#include "pathnames.h"
+
+/*
+ * kill an existing daemon and disable printing.
+ */
+abort(argc, argv)
+ char *argv[];
+{
+ register int c, status;
+ register char *cp1, *cp2;
+ char prbuf[100];
+
+ if (argc == 1) {
+ printf("Usage: abort {all | printer ...}\n");
+ return;
+ }
+ if (argc == 2 && !strcmp(argv[1], "all")) {
+ printer = prbuf;
+ while (getprent(line) > 0) {
+ cp1 = prbuf;
+ cp2 = line;
+ while ((c = *cp2++) && c != '|' && c != ':')
+ *cp1++ = c;
+ *cp1 = '\0';
+ abortpr(1);
+ }
+ return;
+ }
+ while (--argc) {
+ printer = *++argv;
+ if ((status = pgetent(line, printer)) < 0) {
+ printf("cannot open printer description file\n");
+ continue;
+ } else if (status == 0) {
+ printf("unknown printer %s\n", printer);
+ continue;
+ }
+ abortpr(1);
+ }
+}
+
+abortpr(dis)
+{
+ register FILE *fp;
+ struct stat stbuf;
+ int pid, fd;
+
+ bp = pbuf;
+ if ((SD = pgetstr("sd", &bp)) == NULL)
+ SD = _PATH_DEFSPOOL;
+ if ((LO = pgetstr("lo", &bp)) == NULL)
+ LO = DEFLOCK;
+ (void) sprintf(line, "%s/%s", SD, LO);
+ printf("%s:\n", printer);
+
+ /*
+ * Turn on the owner execute bit of the lock file to disable printing.
+ */
+ if (dis) {
+ if (stat(line, &stbuf) >= 0) {
+ if (chmod(line, (stbuf.st_mode & 0777) | 0100) < 0)
+ printf("\tcannot disable printing\n");
+ else {
+ upstat("printing disabled\n");
+ printf("\tprinting disabled\n");
+ }
+ } else if (errno == ENOENT) {
+ if ((fd = open(line, O_WRONLY|O_CREAT, 0760)) < 0)
+ printf("\tcannot create lock file\n");
+ else {
+ (void) close(fd);
+ upstat("printing disabled\n");
+ printf("\tprinting disabled\n");
+ printf("\tno daemon to abort\n");
+ }
+ return;
+ } else {
+ printf("\tcannot stat lock file\n");
+ return;
+ }
+ }
+ /*
+ * Kill the current daemon to stop printing now.
+ */
+ if ((fp = fopen(line, "r")) == NULL) {
+ printf("\tcannot open lock file\n");
+ return;
+ }
+ if (!getline(fp) || flock(fileno(fp), LOCK_SH|LOCK_NB) == 0) {
+ (void) fclose(fp); /* unlocks as well */
+ printf("\tno daemon to abort\n");
+ return;
+ }
+ (void) fclose(fp);
+ if (kill(pid = atoi(line), SIGTERM) < 0)
+ printf("\tWarning: daemon (pid %d) not killed\n", pid);
+ else
+ printf("\tdaemon (pid %d) killed\n", pid);
+}
+
+/*
+ * Write a message into the status file.
+ */
+upstat(msg)
+ char *msg;
+{
+ register int fd;
+ char statfile[BUFSIZ];
+
+ bp = pbuf;
+ if ((ST = pgetstr("st", &bp)) == NULL)
+ ST = DEFSTAT;
+ (void) sprintf(statfile, "%s/%s", SD, ST);
+ umask(0);
+ fd = open(statfile, O_WRONLY|O_CREAT, 0664);
+ if (fd < 0 || flock(fd, LOCK_EX) < 0) {
+ printf("\tcannot create status file\n");
+ return;
+ }
+ (void) ftruncate(fd, 0);
+ if (msg == (char *)NULL)
+ (void) write(fd, "\n", 1);
+ else
+ (void) write(fd, msg, strlen(msg));
+ (void) close(fd);
+}
+
+/*
+ * Remove all spool files and temporaries from the spooling area.
+ */
+clean(argc, argv)
+ char *argv[];
+{
+ register int c, status;
+ register char *cp1, *cp2;
+ char prbuf[100];
+
+ if (argc == 1) {
+ printf("Usage: clean {all | printer ...}\n");
+ return;
+ }
+ if (argc == 2 && !strcmp(argv[1], "all")) {
+ printer = prbuf;
+ while (getprent(line) > 0) {
+ cp1 = prbuf;
+ cp2 = line;
+ while ((c = *cp2++) && c != '|' && c != ':')
+ *cp1++ = c;
+ *cp1 = '\0';
+ cleanpr();
+ }
+ return;
+ }
+ while (--argc) {
+ printer = *++argv;
+ if ((status = pgetent(line, printer)) < 0) {
+ printf("cannot open printer description file\n");
+ continue;
+ } else if (status == 0) {
+ printf("unknown printer %s\n", printer);
+ continue;
+ }
+ cleanpr();
+ }
+}
+
+select(d)
+struct direct *d;
+{
+ int c = d->d_name[0];
+
+ if ((c == 't' || c == 'c' || c == 'd') && d->d_name[1] == 'f')
+ return(1);
+ return(0);
+}
+
+/*
+ * Comparison routine for scandir. Sort by job number and machine, then
+ * by `cf', `tf', or `df', then by the sequence letter A-Z, a-z.
+ */
+sortq(d1, d2)
+struct direct **d1, **d2;
+{
+ int c1, c2;
+
+ if (c1 = strcmp((*d1)->d_name + 3, (*d2)->d_name + 3))
+ return(c1);
+ c1 = (*d1)->d_name[0];
+ c2 = (*d2)->d_name[0];
+ if (c1 == c2)
+ return((*d1)->d_name[2] - (*d2)->d_name[2]);
+ if (c1 == 'c')
+ return(-1);
+ if (c1 == 'd' || c2 == 'c')
+ return(1);
+ return(-1);
+}
+
+/*
+ * Remove incomplete jobs from spooling area.
+ */
+cleanpr()
+{
+ register int i, n;
+ register char *cp, *cp1, *lp;
+ struct direct **queue;
+ int nitems;
+
+ bp = pbuf;
+ if ((SD = pgetstr("sd", &bp)) == NULL)
+ SD = _PATH_DEFSPOOL;
+ printf("%s:\n", printer);
+
+ for (lp = line, cp = SD; *lp++ = *cp++; )
+ ;
+ lp[-1] = '/';
+
+ nitems = scandir(SD, &queue, select, sortq);
+ if (nitems < 0) {
+ printf("\tcannot examine spool directory\n");
+ return;
+ }
+ if (nitems == 0)
+ return;
+ i = 0;
+ do {
+ cp = queue[i]->d_name;
+ if (*cp == 'c') {
+ n = 0;
+ while (i + 1 < nitems) {
+ cp1 = queue[i + 1]->d_name;
+ if (*cp1 != 'd' || strcmp(cp + 3, cp1 + 3))
+ break;
+ i++;
+ n++;
+ }
+ if (n == 0) {
+ strcpy(lp, cp);
+ unlinkf(line);
+ }
+ } else {
+ /*
+ * Must be a df with no cf (otherwise, it would have
+ * been skipped above) or a tf file (which can always
+ * be removed).
+ */
+ strcpy(lp, cp);
+ unlinkf(line);
+ }
+ } while (++i < nitems);
+}
+
+unlinkf(name)
+ char *name;
+{
+ if (unlink(name) < 0)
+ printf("\tcannot remove %s\n", name);
+ else
+ printf("\tremoved %s\n", name);
+}
+
+/*
+ * Enable queuing to the printer (allow lpr's).
+ */
+enable(argc, argv)
+ char *argv[];
+{
+ register int c, status;
+ register char *cp1, *cp2;
+ char prbuf[100];
+
+ if (argc == 1) {
+ printf("Usage: enable {all | printer ...}\n");
+ return;
+ }
+ if (argc == 2 && !strcmp(argv[1], "all")) {
+ printer = prbuf;
+ while (getprent(line) > 0) {
+ cp1 = prbuf;
+ cp2 = line;
+ while ((c = *cp2++) && c != '|' && c != ':')
+ *cp1++ = c;
+ *cp1 = '\0';
+ enablepr();
+ }
+ return;
+ }
+ while (--argc) {
+ printer = *++argv;
+ if ((status = pgetent(line, printer)) < 0) {
+ printf("cannot open printer description file\n");
+ continue;
+ } else if (status == 0) {
+ printf("unknown printer %s\n", printer);
+ continue;
+ }
+ enablepr();
+ }
+}
+
+enablepr()
+{
+ struct stat stbuf;
+
+ bp = pbuf;
+ if ((SD = pgetstr("sd", &bp)) == NULL)
+ SD = _PATH_DEFSPOOL;
+ if ((LO = pgetstr("lo", &bp)) == NULL)
+ LO = DEFLOCK;
+ (void) sprintf(line, "%s/%s", SD, LO);
+ printf("%s:\n", printer);
+
+ /*
+ * Turn off the group execute bit of the lock file to enable queuing.
+ */
+ if (stat(line, &stbuf) >= 0) {
+ if (chmod(line, stbuf.st_mode & 0767) < 0)
+ printf("\tcannot enable queuing\n");
+ else
+ printf("\tqueuing enabled\n");
+ }
+}
+
+/*
+ * Disable queuing.
+ */
+disable(argc, argv)
+ char *argv[];
+{
+ register int c, status;
+ register char *cp1, *cp2;
+ char prbuf[100];
+
+ if (argc == 1) {
+ printf("Usage: disable {all | printer ...}\n");
+ return;
+ }
+ if (argc == 2 && !strcmp(argv[1], "all")) {
+ printer = prbuf;
+ while (getprent(line) > 0) {
+ cp1 = prbuf;
+ cp2 = line;
+ while ((c = *cp2++) && c != '|' && c != ':')
+ *cp1++ = c;
+ *cp1 = '\0';
+ disablepr();
+ }
+ return;
+ }
+ while (--argc) {
+ printer = *++argv;
+ if ((status = pgetent(line, printer)) < 0) {
+ printf("cannot open printer description file\n");
+ continue;
+ } else if (status == 0) {
+ printf("unknown printer %s\n", printer);
+ continue;
+ }
+ disablepr();
+ }
+}
+
+disablepr()
+{
+ register int fd;
+ struct stat stbuf;
+
+ bp = pbuf;
+ if ((SD = pgetstr("sd", &bp)) == NULL)
+ SD = _PATH_DEFSPOOL;
+ if ((LO = pgetstr("lo", &bp)) == NULL)
+ LO = DEFLOCK;
+ (void) sprintf(line, "%s/%s", SD, LO);
+ printf("%s:\n", printer);
+ /*
+ * Turn on the group execute bit of the lock file to disable queuing.
+ */
+ if (stat(line, &stbuf) >= 0) {
+ if (chmod(line, (stbuf.st_mode & 0777) | 010) < 0)
+ printf("\tcannot disable queuing\n");
+ else
+ printf("\tqueuing disabled\n");
+ } else if (errno == ENOENT) {
+ if ((fd = open(line, O_WRONLY|O_CREAT, 0670)) < 0)
+ printf("\tcannot create lock file\n");
+ else {
+ (void) close(fd);
+ printf("\tqueuing disabled\n");
+ }
+ return;
+ } else
+ printf("\tcannot stat lock file\n");
+}
+
+/*
+ * Disable queuing and printing and put a message into the status file
+ * (reason for being down).
+ */
+down(argc, argv)
+ char *argv[];
+{
+ register int c, status;
+ register char *cp1, *cp2;
+ char prbuf[100];
+
+ if (argc == 1) {
+ printf("Usage: down {all | printer} [message ...]\n");
+ return;
+ }
+ if (!strcmp(argv[1], "all")) {
+ printer = prbuf;
+ while (getprent(line) > 0) {
+ cp1 = prbuf;
+ cp2 = line;
+ while ((c = *cp2++) && c != '|' && c != ':')
+ *cp1++ = c;
+ *cp1 = '\0';
+ putmsg(argc - 2, argv + 2);
+ }
+ return;
+ }
+ printer = argv[1];
+ if ((status = pgetent(line, printer)) < 0) {
+ printf("cannot open printer description file\n");
+ return;
+ } else if (status == 0) {
+ printf("unknown printer %s\n", printer);
+ return;
+ }
+ putmsg(argc - 2, argv + 2);
+}
+
+putmsg(argc, argv)
+ char **argv;
+{
+ register int fd;
+ register char *cp1, *cp2;
+ char buf[1024];
+ struct stat stbuf;
+
+ bp = pbuf;
+ if ((SD = pgetstr("sd", &bp)) == NULL)
+ SD = _PATH_DEFSPOOL;
+ if ((LO = pgetstr("lo", &bp)) == NULL)
+ LO = DEFLOCK;
+ if ((ST = pgetstr("st", &bp)) == NULL)
+ ST = DEFSTAT;
+ printf("%s:\n", printer);
+ /*
+ * Turn on the group execute bit of the lock file to disable queuing and
+ * turn on the owner execute bit of the lock file to disable printing.
+ */
+ (void) sprintf(line, "%s/%s", SD, LO);
+ if (stat(line, &stbuf) >= 0) {
+ if (chmod(line, (stbuf.st_mode & 0777) | 0110) < 0)
+ printf("\tcannot disable queuing\n");
+ else
+ printf("\tprinter and queuing disabled\n");
+ } else if (errno == ENOENT) {
+ if ((fd = open(line, O_WRONLY|O_CREAT, 0770)) < 0)
+ printf("\tcannot create lock file\n");
+ else {
+ (void) close(fd);
+ printf("\tprinter and queuing disabled\n");
+ }
+ return;
+ } else
+ printf("\tcannot stat lock file\n");
+ /*
+ * Write the message into the status file.
+ */
+ (void) sprintf(line, "%s/%s", SD, ST);
+ fd = open(line, O_WRONLY|O_CREAT, 0664);
+ if (fd < 0 || flock(fd, LOCK_EX) < 0) {
+ printf("\tcannot create status file\n");
+ return;
+ }
+ (void) ftruncate(fd, 0);
+ if (argc <= 0) {
+ (void) write(fd, "\n", 1);
+ (void) close(fd);
+ return;
+ }
+ cp1 = buf;
+ while (--argc >= 0) {
+ cp2 = *argv++;
+ while (*cp1++ = *cp2++)
+ ;
+ cp1[-1] = ' ';
+ }
+ cp1[-1] = '\n';
+ *cp1 = '\0';
+ (void) write(fd, buf, strlen(buf));
+ (void) close(fd);
+}
+
+/*
+ * Exit lpc
+ */
+quit(argc, argv)
+ char *argv[];
+{
+ exit(0);
+}
+
+/*
+ * Kill and restart the daemon.
+ */
+restart(argc, argv)
+ char *argv[];
+{
+ register int c, status;
+ register char *cp1, *cp2;
+ char prbuf[100];
+
+ if (argc == 1) {
+ printf("Usage: restart {all | printer ...}\n");
+ return;
+ }
+ if (argc == 2 && !strcmp(argv[1], "all")) {
+ printer = prbuf;
+ while (getprent(line) > 0) {
+ cp1 = prbuf;
+ cp2 = line;
+ while ((c = *cp2++) && c != '|' && c != ':')
+ *cp1++ = c;
+ *cp1 = '\0';
+ abortpr(0);
+ startpr(0);
+ }
+ return;
+ }
+ while (--argc) {
+ printer = *++argv;
+ if ((status = pgetent(line, printer)) < 0) {
+ printf("cannot open printer description file\n");
+ continue;
+ } else if (status == 0) {
+ printf("unknown printer %s\n", printer);
+ continue;
+ }
+ abortpr(0);
+ startpr(0);
+ }
+}
+
+/*
+ * Enable printing on the specified printer and startup the daemon.
+ */
+start(argc, argv)
+ char *argv[];
+{
+ register int c, status;
+ register char *cp1, *cp2;
+ char prbuf[100];
+
+ if (argc == 1) {
+ printf("Usage: start {all | printer ...}\n");
+ return;
+ }
+ if (argc == 2 && !strcmp(argv[1], "all")) {
+ printer = prbuf;
+ while (getprent(line) > 0) {
+ cp1 = prbuf;
+ cp2 = line;
+ while ((c = *cp2++) && c != '|' && c != ':')
+ *cp1++ = c;
+ *cp1 = '\0';
+ startpr(1);
+ }
+ return;
+ }
+ while (--argc) {
+ printer = *++argv;
+ if ((status = pgetent(line, printer)) < 0) {
+ printf("cannot open printer description file\n");
+ continue;
+ } else if (status == 0) {
+ printf("unknown printer %s\n", printer);
+ continue;
+ }
+ startpr(1);
+ }
+}
+
+startpr(enable)
+{
+ struct stat stbuf;
+
+ bp = pbuf;
+ if ((SD = pgetstr("sd", &bp)) == NULL)
+ SD = _PATH_DEFSPOOL;
+ if ((LO = pgetstr("lo", &bp)) == NULL)
+ LO = DEFLOCK;
+ (void) sprintf(line, "%s/%s", SD, LO);
+ printf("%s:\n", printer);
+
+ /*
+ * Turn off the owner execute bit of the lock file to enable printing.
+ */
+ if (enable && stat(line, &stbuf) >= 0) {
+ if (chmod(line, stbuf.st_mode & (enable==2 ? 0666 : 0677)) < 0)
+ printf("\tcannot enable printing\n");
+ else
+ printf("\tprinting enabled\n");
+ }
+ if (!startdaemon(printer))
+ printf("\tcouldn't start daemon\n");
+ else
+ printf("\tdaemon started\n");
+}
+
+/*
+ * Print the status of each queue listed or all the queues.
+ */
+status(argc, argv)
+ char *argv[];
+{
+ register int c, status;
+ register char *cp1, *cp2;
+ char prbuf[100];
+
+ if (argc == 1) {
+ printer = prbuf;
+ while (getprent(line) > 0) {
+ cp1 = prbuf;
+ cp2 = line;
+ while ((c = *cp2++) && c != '|' && c != ':')
+ *cp1++ = c;
+ *cp1 = '\0';
+ prstat();
+ }
+ return;
+ }
+ while (--argc) {
+ printer = *++argv;
+ if ((status = pgetent(line, printer)) < 0) {
+ printf("cannot open printer description file\n");
+ continue;
+ } else if (status == 0) {
+ printf("unknown printer %s\n", printer);
+ continue;
+ }
+ prstat();
+ }
+}
+
+/*
+ * Print the status of the printer queue.
+ */
+prstat()
+{
+ struct stat stbuf;
+ register int fd, i;
+ register struct direct *dp;
+ DIR *dirp;
+
+ bp = pbuf;
+ if ((SD = pgetstr("sd", &bp)) == NULL)
+ SD = _PATH_DEFSPOOL;
+ if ((LO = pgetstr("lo", &bp)) == NULL)
+ LO = DEFLOCK;
+ if ((ST = pgetstr("st", &bp)) == NULL)
+ ST = DEFSTAT;
+ printf("%s:\n", printer);
+ (void) sprintf(line, "%s/%s", SD, LO);
+ if (stat(line, &stbuf) >= 0) {
+ printf("\tqueuing is %s\n",
+ (stbuf.st_mode & 010) ? "disabled" : "enabled");
+ printf("\tprinting is %s\n",
+ (stbuf.st_mode & 0100) ? "disabled" : "enabled");
+ } else {
+ printf("\tqueuing is enabled\n");
+ printf("\tprinting is enabled\n");
+ }
+ if ((dirp = opendir(SD)) == NULL) {
+ printf("\tcannot examine spool directory\n");
+ return;
+ }
+ i = 0;
+ while ((dp = readdir(dirp)) != NULL) {
+ if (*dp->d_name == 'c' && dp->d_name[1] == 'f')
+ i++;
+ }
+ closedir(dirp);
+ if (i == 0)
+ printf("\tno entries\n");
+ else if (i == 1)
+ printf("\t1 entry in spool area\n");
+ else
+ printf("\t%d entries in spool area\n", i);
+ fd = open(line, O_RDONLY);
+ if (fd < 0 || flock(fd, LOCK_SH|LOCK_NB) == 0) {
+ (void) close(fd); /* unlocks as well */
+ printf("\tno daemon present\n");
+ return;
+ }
+ (void) close(fd);
+ putchar('\t');
+ (void) sprintf(line, "%s/%s", SD, ST);
+ fd = open(line, O_RDONLY);
+ if (fd >= 0) {
+ (void) flock(fd, LOCK_SH);
+ while ((i = read(fd, line, sizeof(line))) > 0)
+ (void) fwrite(line, 1, i, stdout);
+ (void) close(fd); /* unlocks as well */
+ }
+}
+
+/*
+ * Stop the specified daemon after completing the current job and disable
+ * printing.
+ */
+stop(argc, argv)
+ char *argv[];
+{
+ register int c, status;
+ register char *cp1, *cp2;
+ char prbuf[100];
+
+ if (argc == 1) {
+ printf("Usage: stop {all | printer ...}\n");
+ return;
+ }
+ if (argc == 2 && !strcmp(argv[1], "all")) {
+ printer = prbuf;
+ while (getprent(line) > 0) {
+ cp1 = prbuf;
+ cp2 = line;
+ while ((c = *cp2++) && c != '|' && c != ':')
+ *cp1++ = c;
+ *cp1 = '\0';
+ stoppr();
+ }
+ return;
+ }
+ while (--argc) {
+ printer = *++argv;
+ if ((status = pgetent(line, printer)) < 0) {
+ printf("cannot open printer description file\n");
+ continue;
+ } else if (status == 0) {
+ printf("unknown printer %s\n", printer);
+ continue;
+ }
+ stoppr();
+ }
+}
+
+stoppr()
+{
+ register int fd;
+ struct stat stbuf;
+
+ bp = pbuf;
+ if ((SD = pgetstr("sd", &bp)) == NULL)
+ SD = _PATH_DEFSPOOL;
+ if ((LO = pgetstr("lo", &bp)) == NULL)
+ LO = DEFLOCK;
+ (void) sprintf(line, "%s/%s", SD, LO);
+ printf("%s:\n", printer);
+
+ /*
+ * Turn on the owner execute bit of the lock file to disable printing.
+ */
+ if (stat(line, &stbuf) >= 0) {
+ if (chmod(line, (stbuf.st_mode & 0777) | 0100) < 0)
+ printf("\tcannot disable printing\n");
+ else {
+ upstat("printing disabled\n");
+ printf("\tprinting disabled\n");
+ }
+ } else if (errno == ENOENT) {
+ if ((fd = open(line, O_WRONLY|O_CREAT, 0760)) < 0)
+ printf("\tcannot create lock file\n");
+ else {
+ (void) close(fd);
+ upstat("printing disabled\n");
+ printf("\tprinting disabled\n");
+ }
+ } else
+ printf("\tcannot stat lock file\n");
+}
+
+struct queue **queue;
+int nitems;
+time_t mtime;
+
+/*
+ * Put the specified jobs at the top of printer queue.
+ */
+topq(argc, argv)
+ char *argv[];
+{
+ register int n, i;
+ struct stat stbuf;
+ register char *cfname;
+ int status, changed;
+
+ if (argc < 3) {
+ printf("Usage: topq printer [jobnum ...] [user ...]\n");
+ return;
+ }
+
+ --argc;
+ printer = *++argv;
+ status = pgetent(line, printer);
+ if (status < 0) {
+ printf("cannot open printer description file\n");
+ return;
+ } else if (status == 0) {
+ printf("%s: unknown printer\n", printer);
+ return;
+ }
+ bp = pbuf;
+ if ((SD = pgetstr("sd", &bp)) == NULL)
+ SD = _PATH_DEFSPOOL;
+ if ((LO = pgetstr("lo", &bp)) == NULL)
+ LO = DEFLOCK;
+ printf("%s:\n", printer);
+
+ if (chdir(SD) < 0) {
+ printf("\tcannot chdir to %s\n", SD);
+ return;
+ }
+ nitems = getq(&queue);
+ if (nitems == 0)
+ return;
+ changed = 0;
+ mtime = queue[0]->q_time;
+ for (i = argc; --i; ) {
+ if (doarg(argv[i]) == 0) {
+ printf("\tjob %s is not in the queue\n", argv[i]);
+ continue;
+ } else
+ changed++;
+ }
+ for (i = 0; i < nitems; i++)
+ free(queue[i]);
+ free(queue);
+ if (!changed) {
+ printf("\tqueue order unchanged\n");
+ return;
+ }
+ /*
+ * Turn on the public execute bit of the lock file to
+ * get lpd to rebuild the queue after the current job.
+ */
+ if (changed && stat(LO, &stbuf) >= 0)
+ (void) chmod(LO, (stbuf.st_mode & 0777) | 01);
+}
+
+/*
+ * Reposition the job by changing the modification time of
+ * the control file.
+ */
+touch(q)
+ struct queue *q;
+{
+ struct timeval tvp[2];
+
+ tvp[0].tv_sec = tvp[1].tv_sec = --mtime;
+ tvp[0].tv_usec = tvp[1].tv_usec = 0;
+ return(utimes(q->q_name, tvp));
+}
+
+/*
+ * Checks if specified job name is in the printer's queue.
+ * Returns: negative (-1) if argument name is not in the queue.
+ */
+doarg(job)
+ char *job;
+{
+ register struct queue **qq;
+ register int jobnum, n;
+ register char *cp, *machine;
+ int cnt = 0;
+ FILE *fp;
+
+ /*
+ * Look for a job item consisting of system name, colon, number
+ * (example: ucbarpa:114)
+ */
+ if ((cp = index(job, ':')) != NULL) {
+ machine = job;
+ *cp++ = '\0';
+ job = cp;
+ } else
+ machine = NULL;
+
+ /*
+ * Check for job specified by number (example: 112 or 235ucbarpa).
+ */
+ if (isdigit(*job)) {
+ jobnum = 0;
+ do
+ jobnum = jobnum * 10 + (*job++ - '0');
+ while (isdigit(*job));
+ for (qq = queue + nitems; --qq >= queue; ) {
+ n = 0;
+ for (cp = (*qq)->q_name+3; isdigit(*cp); )
+ n = n * 10 + (*cp++ - '0');
+ if (jobnum != n)
+ continue;
+ if (*job && strcmp(job, cp) != 0)
+ continue;
+ if (machine != NULL && strcmp(machine, cp) != 0)
+ continue;
+ if (touch(*qq) == 0) {
+ printf("\tmoved %s\n", (*qq)->q_name);
+ cnt++;
+ }
+ }
+ return(cnt);
+ }
+ /*
+ * Process item consisting of owner's name (example: henry).
+ */
+ for (qq = queue + nitems; --qq >= queue; ) {
+ if ((fp = fopen((*qq)->q_name, "r")) == NULL)
+ continue;
+ while (getline(fp) > 0)
+ if (line[0] == 'P')
+ break;
+ (void) fclose(fp);
+ if (line[0] != 'P' || strcmp(job, line+1) != 0)
+ continue;
+ if (touch(*qq) == 0) {
+ printf("\tmoved %s\n", (*qq)->q_name);
+ cnt++;
+ }
+ }
+ return(cnt);
+}
+
+/*
+ * Enable everything and start printer (undo `down').
+ */
+up(argc, argv)
+ char *argv[];
+{
+ register int c, status;
+ register char *cp1, *cp2;
+ char prbuf[100];
+
+ if (argc == 1) {
+ printf("Usage: up {all | printer ...}\n");
+ return;
+ }
+ if (argc == 2 && !strcmp(argv[1], "all")) {
+ printer = prbuf;
+ while (getprent(line) > 0) {
+ cp1 = prbuf;
+ cp2 = line;
+ while ((c = *cp2++) && c != '|' && c != ':')
+ *cp1++ = c;
+ *cp1 = '\0';
+ startpr(2);
+ }
+ return;
+ }
+ while (--argc) {
+ printer = *++argv;
+ if ((status = pgetent(line, printer)) < 0) {
+ printf("cannot open printer description file\n");
+ continue;
+ } else if (status == 0) {
+ printf("unknown printer %s\n", printer);
+ continue;
+ }
+ startpr(2);
+ }
+}
--- /dev/null
+/*
+ * 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]);
--- /dev/null
+.\" 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 .
--- /dev/null
+/*
+ * Copyright (c) 1983 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+char copyright[] =
+"@(#) Copyright (c) 1983 Regents of the University of California.\n\
+ All rights reserved.\n";
+#endif /* not lint */
+
+#ifndef lint
+static char sccsid[] = "@(#)lpc.c 5.11 (Berkeley) 3/2/91";
+#endif /* not lint */
+
+/*
+ * lpc -- line printer control program
+ */
+#include <stdio.h>
+#include <signal.h>
+#include <ctype.h>
+#include <setjmp.h>
+#include <syslog.h>
+
+#include "lpc.h"
+
+int fromatty;
+
+char cmdline[200];
+int margc;
+char *margv[20];
+int top;
+void intr();
+struct cmd *getcmd();
+
+jmp_buf toplevel;
+
+main(argc, argv)
+ char *argv[];
+{
+ register struct cmd *c;
+ extern char *name;
+
+ name = argv[0];
+ openlog("lpd", 0, LOG_LPR);
+
+ if (--argc > 0) {
+ c = getcmd(*++argv);
+ if (c == (struct cmd *)-1) {
+ printf("?Ambiguous command\n");
+ exit(1);
+ }
+ if (c == 0) {
+ printf("?Invalid command\n");
+ exit(1);
+ }
+ if (c->c_priv && getuid()) {
+ printf("?Privileged command\n");
+ exit(1);
+ }
+ (*c->c_handler)(argc, argv);
+ exit(0);
+ }
+ fromatty = isatty(fileno(stdin));
+ top = setjmp(toplevel) == 0;
+ if (top)
+ signal(SIGINT, intr);
+ for (;;) {
+ cmdscanner(top);
+ top = 1;
+ }
+}
+
+void
+intr()
+{
+ if (!fromatty)
+ exit(0);
+ longjmp(toplevel, 1);
+}
+
+/*
+ * Command parser.
+ */
+cmdscanner(top)
+ int top;
+{
+ register struct cmd *c;
+
+ if (!top)
+ putchar('\n');
+ for (;;) {
+ if (fromatty) {
+ printf("lpc> ");
+ fflush(stdout);
+ }
+ if (fgets(cmdline, sizeof(cmdline), stdin) == 0)
+ quit();
+ if (cmdline[0] == 0 || cmdline[0] == '\n')
+ break;
+ makeargv();
+ c = getcmd(margv[0]);
+ if (c == (struct cmd *)-1) {
+ printf("?Ambiguous command\n");
+ continue;
+ }
+ if (c == 0) {
+ printf("?Invalid command\n");
+ continue;
+ }
+ if (c->c_priv && getuid()) {
+ printf("?Privileged command\n");
+ continue;
+ }
+ (*c->c_handler)(margc, margv);
+ }
+ longjmp(toplevel, 0);
+}
+
+extern struct cmd cmdtab[];
+
+struct cmd *
+getcmd(name)
+ register char *name;
+{
+ register char *p, *q;
+ register struct cmd *c, *found;
+ register int nmatches, longest;
+
+ longest = 0;
+ nmatches = 0;
+ found = 0;
+ for (c = cmdtab; p = c->c_name; c++) {
+ for (q = name; *q == *p++; q++)
+ if (*q == 0) /* exact match? */
+ return(c);
+ if (!*q) { /* the name was a prefix */
+ if (q - name > longest) {
+ longest = q - name;
+ nmatches = 1;
+ found = c;
+ } else if (q - name == longest)
+ nmatches++;
+ }
+ }
+ if (nmatches > 1)
+ return((struct cmd *)-1);
+ return(found);
+}
+
+/*
+ * Slice a string up into argc/argv.
+ */
+makeargv()
+{
+ register char *cp;
+ register char **argp = margv;
+
+ margc = 0;
+ for (cp = cmdline; *cp;) {
+ while (isspace(*cp))
+ cp++;
+ if (*cp == '\0')
+ break;
+ *argp++ = cp;
+ margc += 1;
+ while (*cp != '\0' && !isspace(*cp))
+ cp++;
+ if (*cp == '\0')
+ break;
+ *cp++ = '\0';
+ }
+ *argp++ = 0;
+}
+
+#define HELPINDENT (sizeof ("directory"))
+
+/*
+ * Help command.
+ */
+help(argc, argv)
+ int argc;
+ char *argv[];
+{
+ register struct cmd *c;
+
+ if (argc == 1) {
+ register int i, j, w;
+ int columns, width = 0, lines;
+ extern int NCMDS;
+
+ printf("Commands may be abbreviated. Commands are:\n\n");
+ for (c = cmdtab; c->c_name; c++) {
+ int len = strlen(c->c_name);
+
+ if (len > width)
+ width = len;
+ }
+ width = (width + 8) &~ 7;
+ columns = 80 / width;
+ if (columns == 0)
+ columns = 1;
+ lines = (NCMDS + columns - 1) / columns;
+ for (i = 0; i < lines; i++) {
+ for (j = 0; j < columns; j++) {
+ c = cmdtab + j * lines + i;
+ if (c->c_name)
+ printf("%s", c->c_name);
+ if (c + lines >= &cmdtab[NCMDS]) {
+ printf("\n");
+ break;
+ }
+ w = strlen(c->c_name);
+ while (w < width) {
+ w = (w + 8) &~ 7;
+ putchar('\t');
+ }
+ }
+ }
+ return;
+ }
+ while (--argc > 0) {
+ register char *arg;
+ arg = *++argv;
+ c = getcmd(arg);
+ if (c == (struct cmd *)-1)
+ printf("?Ambiguous help command %s\n", arg);
+ else if (c == (struct cmd *)0)
+ printf("?Invalid help command %s\n", arg);
+ else
+ printf("%-*s\t%s\n", HELPINDENT,
+ c->c_name, c->c_help);
+ }
+}
--- /dev/null
+.\" 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.
--- /dev/null
+/*
+ * 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");
+}
--- /dev/null
+/*
+ * 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 */
+};