Vendor-branch import of the 4.4BSD-Lite2 code for lpr. There are

several bugfixes in it that are worth considering.

Don't be alarmed about the import conflicts...

Obtained from: 4.4BSD-Lite2
This commit is contained in:
Joerg Wunsch 1996-05-05 14:04:33 +00:00
parent edbfedac86
commit 0b561052df
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/vendor/CSRG/dist/; revision=15637
16 changed files with 7355 additions and 0 deletions

View file

@ -0,0 +1,400 @@
/*
* Copyright (c) 1995
* 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.
*/
/*
* Auxillary functions to aid portability to other systems.
* These are 4.4BSD routines that are often not found on other systems.
*
* !!!USE THIS FILE ONLY IF YOU ARE NOT RUNNING 4.4BSD!!!
*/
#if __STDC__
#include <stdarg.h>
#else
#include <varargs.h>
#endif
#ifdef NO_SNPRINTF
#if __STDC__
snprintf(char *str, size_t n, const char *fmt, ...)
#else
snprintf(str, n, fmt, va_alist)
char *str;
size_t n;
char *fmt;
va_dcl
#endif
{
int ret;
va_list ap;
#if __STDC__
va_start(ap, fmt);
#else
va_start(ap);
#endif
ret = vsprintf(str, fmt, ap);
va_end(ap);
if (strlen(str) > n)
fatal("memory corrupted");
return (ret);
}
vsnprintf(str, n, fmt, ap)
char *str;
size_t n;
char *fmt;
va_list ap;
{
int ret;
ret = vsprintf(str, fmt, ap);
if (strlen(str) > n)
fatal("memory corrupted");
return (ret);
}
#endif
#ifdef NO_STRERROR
char *
strerror(num)
int num;
{
extern int sys_nerr;
extern char *sys_errlist[];
#define UPREFIX "Unknown error: "
static char ebuf[40] = UPREFIX; /* 64-bit number + slop */
register unsigned int errnum;
register char *p, *t;
char tmp[40];
errnum = num; /* convert to unsigned */
if (errnum < sys_nerr)
return(sys_errlist[errnum]);
/* Do this by hand, so we don't include stdio(3). */
t = tmp;
do {
*t++ = "0123456789"[errnum % 10];
} while (errnum /= 10);
for (p = ebuf + sizeof(UPREFIX) - 1;;) {
*p++ = *--t;
if (t <= tmp)
break;
}
return(ebuf);
}
#endif
#ifdef NO_STRDUP
char *
strdup(str)
char *str;
{
int n;
char *sp;
n = strlen(str) + 1;
if (sp = (char *) malloc(n))
memcpy(sp, str, n);
return (sp);
}
#endif
#ifdef NO_DAEMON
#include <fcntl.h>
#include <paths.h>
#include <unistd.h>
#include <sgtty.h>
#define STDIN_FILENO 0
#define STDOUT_FILENO 1
#define STDERR_FILENO 2
int
daemon(nochdir, noclose)
int nochdir, noclose;
{
int fd;
switch (fork()) {
case -1:
return (-1);
case 0:
break;
default:
_exit(0);
}
if (setsid() == -1)
return (-1);
if (!nochdir)
(void)chdir("/");
if (!noclose && (fd = open(_PATH_DEVNULL, O_RDWR, 0)) != -1) {
(void)dup2(fd, STDIN_FILENO);
(void)dup2(fd, STDOUT_FILENO);
(void)dup2(fd, STDERR_FILENO);
if (fd > 2)
(void)close (fd);
}
return (0);
}
#endif
#ifdef NO_SETSID
int
setsid()
{
int f;
f = open("/dev/tty", O_RDWR);
if (f > 0) {
ioctl(f, TIOCNOTTY, 0);
(void) close(f);
}
return f;
}
#endif
#ifdef NO_VSYSLOG
#include <stdio.h>
#include <errno.h>
#if __STDC__
#include <stdarg.h>
#else
#include <varargs.h>
#endif
vsyslog(pri, fmt, ap)
int pri;
const char *fmt;
va_list ap;
{
char buf[2048], fmt_cpy[1024];
/* substitute error message for %m */
{
register char ch, *t1, *t2;
char *strerror();
for (t1 = fmt_cpy; ch = *fmt; ++fmt)
if (ch == '%' && fmt[1] == 'm') {
++fmt;
for (t2 = strerror(errno);
*t1 = *t2++; ++t1);
}
else
*t1++ = ch;
*t1 = '\0';
}
vsprintf(buf, fmt_cpy, ap);
syslog(pri, "%s", buf);
}
#endif
#ifdef NO_IVALIDUSER
#include <stdio.h>
#include <ctype.h>
#include <netdb.h>
#include <netinet/in.h>
#include <sys/types.h>
#include <sys/param.h>
#include "pathnames.h"
/*
* Returns 0 if ok, -1 if not ok.
*/
int
__ivaliduser(hostf, raddr, luser, ruser)
FILE *hostf;
struct in_addr raddr;
const char *luser, *ruser;
{
register char *user, *p;
int ch;
char buf[MAXHOSTNAMELEN + 128]; /* host + login */
while (fgets(buf, sizeof(buf), hostf)) {
p = buf;
/* Skip lines that are too long. */
if (strchr(p, '\n') == NULL) {
while ((ch = getc(hostf)) != '\n' && ch != EOF);
continue;
}
while (*p != '\n' && *p != ' ' && *p != '\t' && *p != '\0') {
*p = isupper(*p) ? tolower(*p) : *p;
p++;
}
if (*p == ' ' || *p == '\t') {
*p++ = '\0';
while (*p == ' ' || *p == '\t')
p++;
user = p;
while (*p != '\n' && *p != ' ' &&
*p != '\t' && *p != '\0')
p++;
} else
user = p;
*p = '\0';
if (__icheckhost(raddr, buf) &&
strcmp(ruser, *user ? user : luser) == 0) {
return (0);
}
}
return (-1);
}
/*
* Returns "true" if match, 0 if no match.
*/
__icheckhost(raddr, lhost)
struct in_addr raddr;
register char *lhost;
{
register struct hostent *hp;
struct in_addr laddr;
register char **pp;
/* Try for raw ip address first. */
if (isdigit(*lhost) && (laddr.s_addr = inet_addr(lhost)) != INADDR_NONE)
return (raddr.s_addr == laddr.s_addr);
/* Better be a hostname. */
if ((hp = gethostbyname(lhost)) == NULL)
return (0);
/* Spin through ip addresses. */
for (pp = hp->h_addr_list; *pp; ++pp)
if (!bcmp(&raddr, *pp, sizeof(struct in_addr)))
return (1);
/* No match. */
return (0);
}
#endif /* NO_IVALIDUSER */
#ifdef NO_STATFS
#include <sys/types.h>
#include <sys/file.h>
#include <sys/stat.h>
#include <sys/dir.h>
#include <sys/param.h>
#include <ufs/fs.h>
/*
* Check to see if there is enough space on the disk for size bytes.
* 1 == OK, 0 == Not OK.
*/
static int
chksize(size)
int size;
{
struct stat stb;
int spacefree;
struct fs fs;
static int dfd;
static char *find_dev();
#ifndef SBOFF
#define SBOFF ((off_t)(BBSIZE))
#endif
if (dfd <= 0) {
char *ddev;
if (stat(".", &stb) < 0) {
syslog(LOG_ERR, "%s: %m", "statfs(\".\")");
return (1);
}
ddev = find_dev(stb.st_dev, S_IFBLK);
if ((dfd = open(ddev, O_RDONLY)) < 0) {
syslog(LOG_WARNING, "%s: %s: %m", printer, ddev);
return (1);
}
}
if (lseek(dfd, (off_t)(SBOFF), 0) < 0)
return(1);
if (read(dfd, (char *)&fs, sizeof fs) != sizeof fs
|| fs.fs_magic != FS_MAGIC) {
syslog(LOG_ERR, "Can't calculate free space on spool device");
return(1);
}
spacefree = freespace(&fs, fs.fs_minfree) * fs.fs_fsize / 512;
size = (size + 511) / 512;
if (minfree + size > spacefree)
return(0);
return(1);
}
static char *
find_dev(dev, type)
register dev_t dev;
register int type;
{
register DIR *dfd;
struct direct *dir;
struct stat stb;
char devname[MAXNAMLEN+6];
char *dp;
int n;
strcpy(devname, "/dev/dsk");
if ((dfd = opendir(devname)) == NULL) {
strcpy(devname, "/dev");
dfd = opendir(devname);
}
strcat(devname, "/");
n = strlen(devname);
while ((dir = readdir(dfd))) {
strcpy(devname + n, dir->d_name);
if (stat(devname, &stb))
continue;
if ((stb.st_mode & S_IFMT) != type)
continue;
if (dev == stb.st_rdev) {
closedir(dfd);
dp = (char *)malloc(strlen(devname)+1);
strcpy(dp, devname);
return(dp);
}
}
closedir(dfd);
frecverr("cannot find device %d, %d", major(dev), minor(dev));
/*NOTREACHED*/
}
#endif /* NOSTATFS */

View file

@ -0,0 +1,67 @@
/*
* Copyright (c) 1995
* 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.
*/
/*
* Auxillary functions to aid portability to other systems.
* These are 4.4BSD routines that are often not found on other systems.
*
* !!!USE THIS FILE ONLY IF YOU ARE NOT RUNNING 4.4BSD!!!
*/
#ifdef PREPOSIX
#define dirent direct
extern int errno;
#endif
#ifdef NO_RINDEX
#define index strchr
#define rindex strrchr
#endif
#ifdef BSDWAIT
#define WAITARG_T(a) ((int *)(a))
#else
#define WAITARG_T(a) (a)
#endif
#ifdef SETPGID
#define setpgrp(a, b) setpgid((pid_t)(a), (pid_t)(b))
#endif
#ifndef FD_COPY
#define FD_COPY(f, t) memcpy((char *)t, (char *)f, sizeof(*(f)))
#endif
#ifdef NO_SNPRINTF
int snprintf __P((char *str, size_t n, const char *fmt, ...));
#endif

View file

@ -0,0 +1,377 @@
/*
* Copyright (c) 1983, 1993
* The Regents of the University of California. All rights reserved.
* (c) UNIX System Laboratories, Inc.
* All or some portions of this file are derived from material licensed
* to the University of California by American Telephone and Telegraph
* Co. or Unix System Laboratories, Inc. and are reproduced herein with
* the permission of UNIX System Laboratories, Inc.
*
* 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 8.5 (Berkeley) 4/28/95";
#endif /* not lint */
#include <sys/param.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <dirent.h>
#include <errno.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "lp.h"
#include "pathnames.h"
/*
* Routines and data common to all the line printer functions.
*/
char *AF; /* accounting file */
long BR; /* baud rate if lp is a tty */
char *CF; /* name of cifplot filter (per job) */
char *DF; /* name of tex filter (per job) */
long DU; /* daeomon user-id */
long FC; /* flags to clear if lp is a tty */
char *FF; /* form feed string */
long FS; /* flags to set if lp is a tty */
char *GF; /* name of graph(1G) filter (per job) */
long HL; /* print header last */
char *IF; /* name of input filter (created per job) */
char *LF; /* log file for error messages */
char *LO; /* lock file name */
char *LP; /* line printer device name */
long MC; /* maximum number of copies allowed */
long MX; /* maximum number of blocks to copy */
char *NF; /* name of ditroff filter (per job) */
char *OF; /* name of output filter (created once) */
char *PF; /* name of vrast filter (per job) */
long PL; /* page length */
long PW; /* page width */
long PX; /* page width in pixels */
long PY; /* page length in pixels */
char *RF; /* name of fortran text filter (per job) */
char *RG; /* resricted group */
char *RM; /* remote machine name */
char *RP; /* remote printer name */
long RS; /* restricted to those with local accounts */
long RW; /* open LP for reading and writing */
long SB; /* short banner instead of normal header */
long SC; /* suppress multiple copies */
char *SD; /* spool directory */
long SF; /* suppress FF on each print job */
long SH; /* suppress header page */
char *ST; /* status file name */
char *TF; /* name of troff filter (per job) */
char *TR; /* trailer string to be output when Q empties */
char *VF; /* name of vplot filter (per job) */
long XC; /* flags to clear for local mode */
long XS; /* flags to set for local mode */
char line[BUFSIZ];
char *bp; /* pointer into printcap buffer. */
char *name; /* program name */
char *printer; /* printer name */
/* host machine name */
char host[MAXHOSTNAMELEN];
char *from = host; /* client's machine name */
int remote; /* true if sending files to a remote host */
char *printcapdb[2] = { _PATH_PRINTCAP, 0 };
static int compar __P((const void *, const void *));
/*
* Create a TCP connection to host "rhost" at port "rport".
* If rport == 0, then use the printer service port.
* Most of this code comes from rcmd.c.
*/
int
getport(rhost, rport)
char *rhost;
int rport;
{
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");
bzero((char *)&sin, sizeof(sin));
sin.sin_addr.s_addr = inet_addr(rhost);
if (sin.sin_addr.s_addr != INADDR_NONE)
sin.sin_family = AF_INET;
else {
hp = gethostbyname(rhost);
if (hp == NULL)
fatal("unknown host %s", rhost);
bcopy(hp->h_addr, (caddr_t)&sin.sin_addr, hp->h_length);
sin.sin_family = hp->h_addrtype;
}
if (rport == 0) {
sp = getservbyname("printer", "tcp");
if (sp == NULL)
fatal("printer/tcp: unknown service");
sin.sin_port = sp->s_port;
} else
sin.sin_port = htons(rport);
/*
* 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.
*/
int
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.
*/
int
getq(namelist)
struct queue *(*namelist[]);
{
register struct dirent *d;
register struct queue *q, **queue;
register int nitems;
struct stat stbuf;
DIR *dirp;
int arraysz;
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) {
arraysz *= 2;
queue = (struct queue **)realloc((char *)queue,
arraysz * 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 int
compar(p1, p2)
const void *p1, *p2;
{
if ((*(struct queue **)p1)->q_time < (*(struct queue **)p2)->q_time)
return(-1);
if ((*(struct queue **)p1)->q_time > (*(struct queue **)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];
remote = 0; /* assume printer is local */
if (RM != 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) snprintf(errbuf, sizeof(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) snprintf(errbuf, sizeof(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 (strcasecmp(name, hp->h_name) != 0)
remote = 1;
}
return NULL;
}
/* sleep n milliseconds */
void
delay(n)
{
struct timeval tdelay;
if (n <= 0 || n > 10000)
fatal("unreasonable delay period (%d)", n);
tdelay.tv_sec = n / 1000;
tdelay.tv_usec = n * 1000 % 1000000;
(void) select(0, (fd_set *)0, (fd_set *)0, (fd_set *)0, &tdelay);
}
#if __STDC__
#include <stdarg.h>
#else
#include <varargs.h>
#endif
void
#if __STDC__
fatal(const char *msg, ...)
#else
fatal(msg, va_alist)
char *msg;
va_dcl
#endif
{
va_list ap;
#if __STDC__
va_start(ap, msg);
#else
va_start(ap);
#endif
if (from != host)
(void)printf("%s: ", host);
(void)printf("%s: ", name);
if (printer)
(void)printf("%s: ", printer);
(void)vprintf(msg, ap);
va_end(ap);
(void)putchar('\n');
exit(1);
}

View file

@ -0,0 +1,450 @@
/*
* Copyright (c) 1983, 1993
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#ifndef lint
static char sccsid[] = "@(#)displayq.c 8.4 (Berkeley) 4/28/95";
#endif /* not lint */
#include <sys/param.h>
#include <sys/stat.h>
#include <sys/file.h>
#include <signal.h>
#include <fcntl.h>
#include <dirent.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include "lp.h"
#include "lp.local.h"
#include "pathnames.h"
/*
* Routines to display the state of the queue.
*/
#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 int requ[]; /* job number of spool entries */
extern int requests; /* # of spool requests */
extern char *user[]; /* users to process */
extern int users; /* # of users in user array */
static int col; /* column on screen */
static char current[40]; /* current file being printed */
static char file[132]; /* print file name */
static int first; /* first file in ``files'' column? */
static int garbage; /* # of garbage cf files */
static int lflag; /* long output option */
static int rank; /* order to be printed (-1=none, 0=active) */
static long totsize; /* total print job size in bytes */
static char *head0 = "Rank Owner Job Files";
static char *head1 = "Total Size\n";
/*
* Display the current state of the queue. Format = 1 if long format.
*/
void
displayq(format)
int format;
{
register struct queue *q;
register int i, nitems, fd;
register char *cp;
struct queue **queue;
struct stat statb;
FILE *fp;
lflag = format;
totsize = 0;
rank = -1;
if ((i = cgetent(&bp, printcapdb, printer)) == -2)
fatal("can't open printer description file");
else if (i == -1)
fatal("unknown printer");
else if (i == -3)
fatal("potential reference loop detected in printcap file");
if (cgetstr(bp, "lp", &LP) < 0)
LP = _PATH_DEFDEVLP;
if (cgetstr(bp, "rp", &RP) < 0)
RP = DEFLP;
if (cgetstr(bp, "sd", &SD) < 0)
SD = _PATH_DEFSPOOL;
if (cgetstr(bp,"lo", &LO) < 0)
LO = DEFLOCK;
if (cgetstr(bp, "st", &ST) < 0)
ST = DEFSTAT;
cgetstr(bp, "rm", &RM);
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 (remote)
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 (remote)
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 ((i = getc(fp)) != EOF && i != '\n')
*cp++ = i;
*cp = '\0';
i = atoi(current);
if (i <= 0 || kill(i, 0) < 0)
warn();
else {
/* read current file name */
cp = current;
while ((i = getc(fp)) != EOF && i != '\n')
*cp++ = i;
*cp = '\0';
/*
* Print the status file.
*/
if (remote)
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 (!remote) {
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, 0);
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.
*/
void
warn()
{
if (remote)
printf("\n%s: ", host);
puts("Warning: no daemon present");
current[0] = '\0';
}
/*
* Print the header for the short listing format
*/
void
header()
{
printf(head0);
col = strlen(head0)+1;
blankfill(SIZCOL);
printf(head1);
}
void
inform(cf)
char *cf;
{
register int j;
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 (remote || 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;
}
}
int
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);
}
void
show(nfile, file, copies)
register char *nfile, *file;
int copies;
{
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
*/
void
blankfill(n)
register int n;
{
while (col++ < n)
putchar(' ');
}
/*
* Give the abbreviated dump of the file names
*/
void
dump(nfile, file, copies)
char *nfile, *file;
int copies;
{
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
*/
void
ldump(nfile, file, copies)
char *nfile, *file;
int copies;
{
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", (long)lbuf.st_size);
else
printf(" ??? bytes");
putchar('\n');
}
/*
* Print the job's rank in the queue,
* update col for screen management
*/
void
prank(n)
int n;
{
char rline[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)snprintf(rline, sizeof(rline), "%dth", n);
else
(void)snprintf(rline, sizeof(rline), "%d%s", n, r[n%10]);
col += strlen(rline);
printf("%s", rline);
}

View file

@ -0,0 +1,127 @@
/*
* Copyright (c) 1983, 1993
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* @(#)lp.h 8.2 (Berkeley) 4/28/95
*/
/*
* Global definitions for the line printer system.
*/
extern char *AF; /* accounting file */
extern long BR; /* baud rate if lp is a tty */
extern char *CF; /* name of cifplot filter (per job) */
extern char *DF; /* name of tex filter (per job) */
extern long DU; /* daeomon user-id */
extern long FC; /* flags to clear if lp is a tty */
extern char *FF; /* form feed string */
extern long FS; /* flags to set if lp is a tty */
extern char *GF; /* name of graph(1G) filter (per job) */
extern long HL; /* print header last */
extern char *IF; /* name of input filter (created per job) */
extern char *LF; /* log file for error messages */
extern char *LO; /* lock file name */
extern char *LP; /* line printer device name */
extern long MC; /* maximum number of copies allowed */
extern long MX; /* maximum number of blocks to copy */
extern char *NF; /* name of ditroff(1) filter (per job) */
extern char *OF; /* name of output filter (created once) */
extern long PL; /* page length */
extern long PW; /* page width */
extern long PX; /* page width in pixels */
extern long PY; /* page length in pixels */
extern char *RF; /* name of fortran text filter (per job) */
extern char *RG; /* restricted group */
extern char *RM; /* remote machine name */
extern char *RP; /* remote printer name */
extern long RS; /* restricted to those with local accounts */
extern long RW; /* open LP for reading and writing */
extern long SB; /* short banner instead of normal header */
extern long SC; /* suppress multiple copies */
extern char *SD; /* spool directory */
extern long SF; /* suppress FF on each print job */
extern long SH; /* suppress header page */
extern char *ST; /* status file name */
extern char *TF; /* name of troff(1) filter (per job) */
extern char *TR; /* trailer string to be output when Q empties */
extern char *VF; /* name of raster filter (per job) */
extern long XC; /* flags to clear for local mode */
extern long XS; /* flags to set for local mode */
extern char line[BUFSIZ];
extern char *bp; /* pointer into printcap buffer */
extern char *name; /* program name */
extern char *printer; /* printer name */
/* host machine name */
extern char host[MAXHOSTNAMELEN];
extern char *from; /* client's machine name */
extern int remote; /* true if sending files to a remote host */
extern char *printcapdb[]; /* printcap database array */
/*
* 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 */
};
#include <sys/cdefs.h>
__BEGIN_DECLS
struct dirent;
void blankfill __P((int));
char *checkremote __P((void));
int chk __P((char *));
void displayq __P((int));
void dump __P((char *, char *, int));
void fatal __P((const char *, ...));
int getline __P((FILE *));
int getport __P((char *, int));
int getq __P((struct queue *(*[])));
void header __P((void));
void inform __P((char *));
int inlist __P((char *, char *));
int iscf __P((struct dirent *));
int isowner __P((char *, char *));
void ldump __P((char *, char *, int));
int lockchk __P((char *));
void prank __P((int));
void process __P((char *));
void rmjob __P((void));
void rmremote __P((void));
void show __P((char *, char *, int));
int startdaemon __P((char *));
void warn __P((void));
void delay __P((int));
__END_DECLS

View file

@ -0,0 +1,551 @@
/*
* Copyright (c) 1983, 1993
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#ifndef lint
static char sccsid[] = "@(#)printcap.c 8.2 (Berkeley) 4/28/95";
#endif /* not lint */
#include <sys/param.h>
#include <fcntl.h>
#include <dirent.h>
#include <unistd.h>
#include <stdio.h>
#include <ctype.h>
#include <string.h>
#include "lp.h"
#include "pathnames.h"
#ifndef BUFSIZ
#define BUFSIZ 1024
#endif
#define MAXHOP 32 /* max number of tc= indirections */
/*
* getcap-style interface for the old printcap routines.
*
* !!!USE THIS INTERFACE ONLY IF YOU DON'T HAVE THE REAL GETCAP!!!
*/
static char *pbp; /* pointer into pbuf for pgetstr() */
static char pbuf[BUFSIZ]; /* buffer for capability strings */
extern char line[]; /* buffer for printcap entries */
int
cgetnext(bp, db_array)
register char **bp;
char **db_array;
{
int ret;
char *strdup();
pbp = pbuf;
ret = getprent(line);
*bp = strdup(line);
return (ret);
}
int
cgetent(bp, db_array, name)
char **bp, **db_array, *name;
{
int i;
*bp = line;
pbp = pbuf;
i = pgetent(*bp, name);
if (i < 0)
return (-2);
else if (i == 0)
return (-1);
else
return (0);
}
char *
cgetcap(buf, cap, type)
char *buf, *cap;
int type;
{
return ((char *) pgetflag(cap));
}
int
cgetstr(buf, cap, str)
char *buf, *cap;
char **str;
{
char *pgetstr __P((char *, char **));
if (pbp >= pbuf+BUFSIZ) {
write(2, "Capability string buffer overflow\n", 34);
return (-1);
}
return ((*str = pgetstr(cap, &pbp)) == NULL ? -1 : 0);
}
int
cgetnum(buf, cap, num)
char *buf, *cap;
long *num;
{
return ((*num = pgetnum(cap)) < 0 ? -1 : 0);
}
int
cgetclose()
{
void endprent __P((void));
endprent();
return (0);
}
/*
* 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 */
static int tf;
char *tgetstr __P((char *, char **));
static char *tskip __P((char *));
static char *tdecode __P((char *, char **));
/*
* Similar to tgetent except it returns the next enrty instead of
* doing a lookup.
*/
int
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;
}
}
}
void
endprent()
{
if (pfp != NULL) {
/*
* Can't use fclose here because on POSIX-compliant
* systems, fclose() causes the file pointer of the
* underlying file descriptor (which is possibly shared
* with a parent process) to be adjusted, and this
* reeks havoc in the parent because it doesn't know
* the file pointer has changed.
*/
(void) close(fileno(pfp));
pfp = NULL;
}
}
/*
* Get an entry for terminal name in buffer bp,
* from the termcap file. Parse is very rudimentary;
* we just notice escaped newlines.
*/
int
tgetent(bp, name)
char *bp, *name;
{
register char *cp;
register int c;
register int i = 0, cnt = 0;
char ibuf[BUFSIZ];
tbuf = bp;
#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);
}
#endif
if (tf==0)
tf = open(_PATH_PRINTCAP, 0);
if (tf < 0)
return (-1);
for (;;) {
cp = bp;
for (;;) {
if (i == cnt) {
cnt = read(tf, ibuf, BUFSIZ);
if (cnt <= 0) {
close(tf);
tf = 0;
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)) {
lseek(tf, 0L, 0);
i = tnchktc();
if (tf) {
close(tf);
tf = 0;
}
return(i);
}
}
}
/*
* 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.
*/
int
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.
*/
int
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.
*/
int
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.
*/
int
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);
}

View file

@ -0,0 +1,339 @@
/*
* Copyright (c) 1983, 1993
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#ifndef lint
static char sccsid[] = "@(#)rmjob.c 8.2 (Berkeley) 4/28/95";
#endif /* not lint */
#include <sys/param.h>
#include <signal.h>
#include <errno.h>
#include <dirent.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include "lp.h"
#include "lp.local.h"
#include "pathnames.h"
/*
* rmjob - remove the specified jobs from the queue.
*/
/*
* 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 */
static char root[] = "root";
static int all = 0; /* eliminate all files (root only) */
static int cur_daemon; /* daemon's pid */
static char current[40]; /* active control file name */
void
rmjob()
{
register int i, nitems;
int assasinated = 0;
struct dirent **files;
char *cp;
if ((i = cgetent(&bp, printcapdb, printer)) == -2)
fatal("can't open printer description file");
else if (i == -1)
fatal("unknown printer");
else if (i == -3)
fatal("potential reference loop detected in printcap file");
if (cgetstr(bp, "lp", &LP) < 0)
LP = _PATH_DEFDEVLP;
if (cgetstr(bp, "rp", &RP) < 0)
RP = DEFLP;
if (cgetstr(bp, "sd", &SD) < 0)
SD = _PATH_DEFSPOOL;
if (cgetstr(bp,"lo", &LO) < 0)
LO = DEFLOCK;
cgetstr(bp, "rm", &RM);
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.
*/
int
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.
*/
void
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
*/
int
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.
*/
int
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.
*/
void
rmremote()
{
register char *cp;
register int i, rem;
char buf[BUFSIZ];
if (!remote)
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);
(void)snprintf(buf, sizeof(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, 0);
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'
*/
int
iscf(d)
struct dirent *d;
{
return(d->d_name[0] == 'c' && d->d_name[1] == 'f');
}

1108
usr.sbin/lpr/lpc/cmds.c Normal file

File diff suppressed because it is too large Load diff

175
usr.sbin/lpr/lpc/lpc.8 Normal file
View file

@ -0,0 +1,175 @@
.\" Copyright (c) 1983, 1991, 1993
.\" The Regents of the University of California. All rights reserved.
.\"
.\" Redistribution and use in source and binary forms, with or without
.\" modification, are permitted provided that the following conditions
.\" are met:
.\" 1. Redistributions of source code must retain the above copyright
.\" notice, this list of conditions and the following disclaimer.
.\" 2. Redistributions in binary form must reproduce the above copyright
.\" notice, this list of conditions and the following disclaimer in the
.\" documentation and/or other materials provided with the distribution.
.\" 3. All advertising materials mentioning features or use of this software
.\" must display the following acknowledgement:
.\" This product includes software developed by the University of
.\" California, Berkeley and its contributors.
.\" 4. Neither the name of the University nor the names of its contributors
.\" may be used to endorse or promote products derived from this software
.\" without specific prior written permission.
.\"
.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
.\" @(#)lpc.8 8.5 (Berkeley) 4/28/95
.\"
.Dd April 28, 1995
.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 daemons.
.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 abbreviated;
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 argument is 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.
.ne 1i
.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"
abbreviation matches more than one command
.It Sy "?Invalid command"
no match was found
.It Sy "?Privileged command"
you must be a member of group "operator" or root to execute this command
.El
.Sh HISTORY
The
.Nm
command appeared in
.Bx 4.2 .

314
usr.sbin/lpr/lpc/lpc.c Normal file
View file

@ -0,0 +1,314 @@
/*
* Copyright (c) 1983, 1993
* The Regents of the University of California. All rights reserved.
*
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#ifndef lint
static char copyright[] =
"@(#) Copyright (c) 1983, 1993\n\
The Regents of the University of California. All rights reserved.\n";
#endif /* not lint */
#ifndef lint
static char sccsid[] = "@(#)lpc.c 8.3 (Berkeley) 4/28/95";
#endif /* not lint */
#include <sys/param.h>
#include <dirent.h>
#include <signal.h>
#include <setjmp.h>
#include <syslog.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <ctype.h>
#include <string.h>
#include <grp.h>
#include <sys/param.h>
#include "lp.h"
#include "lpc.h"
#include "extern.h"
#ifndef LPR_OPER
#define LPR_OPER "operator" /* group name of lpr operators */
#endif
/*
* lpc -- line printer control program
*/
int fromatty;
char cmdline[200];
int margc;
char *margv[20];
int top;
jmp_buf toplevel;
static void cmdscanner __P((int));
static struct cmd *getcmd __P((char *));
static void intr __P((int));
static void makeargv __P((void));
static int ingroup __P((char *));
int
main(argc, argv)
int argc;
char *argv[];
{
register struct cmd *c;
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() && ingroup(LPR_OPER) == 0) {
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;
}
}
static void
intr(signo)
int signo;
{
if (!fromatty)
exit(0);
longjmp(toplevel, 1);
}
/*
* Command parser.
*/
static void
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(0, NULL);
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() && ingroup(LPR_OPER) == 0) {
printf("?Privileged command\n");
continue;
}
(*c->c_handler)(margc, margv);
}
longjmp(toplevel, 0);
}
static 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.
*/
static void
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.
*/
void
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);
}
}
/*
* return non-zero if the user is a member of the given group
*/
static int
ingroup(grname)
char *grname;
{
static struct group *gptr=NULL;
static gid_t groups[NGROUPS];
register gid_t gid;
register int i;
if (gptr == NULL) {
if ((gptr = getgrnam(grname)) == NULL) {
fprintf(stderr, "Warning: unknown group '%s'\n",
grname);
return(0);
}
if (getgroups(NGROUPS, groups) < 0) {
perror("getgroups");
exit(1);
}
}
gid = gptr->gr_gid;
for (i = 0; i < NGROUPS; i++)
if (gid == groups[i])
return(1);
return(0);
}

542
usr.sbin/lpr/lpd/lpd.c Normal file
View file

@ -0,0 +1,542 @@
/*
* Copyright (c) 1983, 1993, 1994
* The Regents of the University of California. All rights reserved.
*
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#ifndef lint
static char copyright[] =
"@(#) Copyright (c) 1983, 1993, 1994\n\
The Regents of the University of California. All rights reserved.\n";
#endif /* not lint */
#ifndef lint
static char sccsid[] = "@(#)lpd.c 8.7 (Berkeley) 5/10/95";
#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 <sys/param.h>
#include <sys/wait.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <sys/stat.h>
#include <sys/file.h>
#include <netinet/in.h>
#include <netdb.h>
#include <unistd.h>
#include <syslog.h>
#include <signal.h>
#include <errno.h>
#include <fcntl.h>
#include <dirent.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include "lp.h"
#include "lp.local.h"
#include "pathnames.h"
#include "extern.h"
int lflag; /* log requests flag */
int from_remote; /* from remote socket */
static void reapchild __P((int));
static void mcleanup __P((int));
static void doit __P((void));
static void startup __P((void));
static void chkhost __P((struct sockaddr_in *));
static int ckqueue __P((char *));
int
main(argc, argv)
int argc;
char **argv;
{
int f, funix, finet, options, fromlen;
fd_set defreadfds;
struct sockaddr_un un, fromunix;
struct sockaddr_in sin, frominet;
int omask, lfd;
options = 0;
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);
syslog(LOG_INFO, "restarted");
(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);
memset(&un, 0, sizeof(un));
un.sun_family = AF_UNIX;
strcpy(un.sun_path, _PATH_SOCKETNAME);
#ifndef SUN_LEN
#define SUN_LEN(unp) (strlen((unp)->sun_path) + 2)
#endif
if (bind(funix, (struct sockaddr *)&un, SUN_LEN(&un)) < 0) {
syslog(LOG_ERR, "ubind: %m");
exit(1);
}
sigsetmask(omask);
FD_ZERO(&defreadfds);
FD_SET(funix, &defreadfds);
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(0);
}
sp = getservbyname("printer", "tcp");
if (sp == NULL) {
syslog(LOG_ERR, "printer/tcp: unknown service");
mcleanup(0);
}
memset(&sin, 0, sizeof(sin));
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(0);
}
FD_SET(finet, &defreadfds);
listen(finet, 5);
}
/*
* Main loop: accept, do a request, continue.
*/
memset(&frominet, 0, sizeof(frominet));
memset(&fromunix, 0, sizeof(fromunix));
for (;;) {
int domain, nfds, s;
fd_set readfds;
FD_COPY(&defreadfds, &readfds);
nfds = select(20, &readfds, 0, 0, 0);
if (nfds <= 0) {
if (nfds < 0 && errno != EINTR)
syslog(LOG_WARNING, "select: %m");
continue;
}
if (FD_ISSET(funix, &readfds)) {
domain = AF_UNIX, fromlen = sizeof(fromunix);
s = accept(funix,
(struct sockaddr *)&fromunix, &fromlen);
} else /* if (FD_ISSET(finet, &readfds)) */ {
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);
}
}
static void
reapchild(signo)
int signo;
{
union wait status;
while (wait3((int *)&status, WNOHANG, 0) > 0)
;
}
static void
mcleanup(signo)
int signo;
{
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[MAXHOSTNAMELEN]; /* buffer for client's machine name */
char cbuf[BUFSIZ]; /* command line buffer */
char *cmdnames[] = {
"null",
"printjob",
"recvjob",
"displayq short",
"displayq long",
"rmjob"
};
static void
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.
*/
static void
startup()
{
char *buf;
register char *cp;
int pid;
/*
* Restart the daemons.
*/
while (cgetnext(&buf, printcapdb) > 0) {
if (ckqueue(buf) <= 0) {
free(buf);
continue; /* no work to do for this printer */
}
for (cp = buf; *cp; cp++)
if (*cp == '|' || *cp == ':') {
*cp = '\0';
break;
}
if (lflag)
syslog(LOG_INFO, "work for %s", buf);
if ((pid = fork()) < 0) {
syslog(LOG_WARNING, "startup: cannot fork");
mcleanup(0);
}
if (!pid) {
printer = buf;
cgetclose();
printjob();
/* NOTREACHED */
}
else free(buf);
}
}
/*
* Make sure there's some work to do before forking off a child
*/
static int
ckqueue(cap)
char *cap;
{
register struct dirent *d;
DIR *dirp;
char *spooldir;
if (cgetstr(cap, "sd", &spooldir) == -1)
spooldir = _PATH_DEFSPOOL;
if ((dirp = opendir(spooldir)) == NULL)
return (-1);
while ((d = readdir(dirp)) != NULL) {
if (d->d_name[0] != 'c' || d->d_name[1] != 'f')
continue; /* daemon control files only */
closedir(dirp);
return (1); /* found something */
}
closedir(dirp);
return (0);
}
#define DUMMY ":nobody::"
/*
* Check to see if the from host has access to the line printer.
*/
static void
chkhost(f)
struct sockaddr_in *f;
{
register struct hostent *hp;
register FILE *hostf;
int first = 1;
extern char *inet_ntoa();
f->sin_port = ntohs(f->sin_port);
if (f->sin_family != AF_INET || f->sin_port >= IPPORT_RESERVED)
fatal("Malformed from address");
/* Need real hostname for temporary filenames */
hp = gethostbyaddr((char *)&f->sin_addr,
sizeof(struct in_addr), f->sin_family);
if (hp == NULL)
fatal("Host name for your address (%s) unknown",
inet_ntoa(f->sin_addr));
(void) strncpy(fromb, hp->h_name, sizeof(fromb));
from[sizeof(fromb) - 1] = '\0';
from = fromb;
hostf = fopen(_PATH_HOSTSEQUIV, "r");
again:
if (hostf) {
if (__ivaliduser(hostf, f->sin_addr.s_addr,
DUMMY, DUMMY) == 0) {
(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");
/*NOTREACHED*/
}

1493
usr.sbin/lpr/lpd/printjob.c Normal file

File diff suppressed because it is too large Load diff

358
usr.sbin/lpr/lpd/recvjob.c Normal file
View file

@ -0,0 +1,358 @@
/*
* Copyright (c) 1983, 1993
* The Regents of the University of California. All rights reserved.
*
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#ifndef lint
static char copyright[] =
"@(#) Copyright (c) 1983, 1993\n\
The Regents of the University of California. All rights reserved.\n";
#endif /* not lint */
#ifndef lint
static char sccsid[] = "@(#)recvjob.c 8.2 (Berkeley) 4/27/95";
#endif /* not lint */
/*
* Receive printer jobs from the network, queue them and
* start the printer daemon.
*/
#include <sys/param.h>
#include <sys/mount.h>
#include <sys/stat.h>
#include <unistd.h>
#include <signal.h>
#include <fcntl.h>
#include <dirent.h>
#include <syslog.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "lp.h"
#include "lp.local.h"
#include "extern.h"
#include "pathnames.h"
#define ack() (void) write(1, sp, 1);
static char dfname[40]; /* data files */
static int minfree; /* keep at least minfree blocks available */
static char *sp = "";
static char tfname[40]; /* tmp copy of cf before linking */
static int chksize __P((int));
static void frecverr __P((const char *, ...));
static int noresponse __P((void));
static void rcleanup __P((int));
static int read_number __P((char *));
static int readfile __P((char *, int));
static int readjob __P((void));
void
recvjob()
{
struct stat stb;
int status;
/*
* Perform lookup for printer name or abbreviation
*/
if ((status = cgetent(&bp, printcapdb, printer)) == -2)
frecverr("cannot open printer description file");
else if (status == -1)
frecverr("unknown printer %s", printer);
else if (status == -3)
fatal("potential reference loop detected in printcap file");
if (cgetstr(bp, "lf", &LF) == -1)
LF = _PATH_CONSOLE;
if (cgetstr(bp, "sd", &SD) == -1)
SD = _PATH_DEFSPOOL;
if (cgetstr(bp, "lo", &LO) == -1)
LO = DEFLOCK;
(void) close(2); /* set up log file */
if (open(LF, O_WRONLY|O_APPEND, 0664) < 0) {
syslog(LOG_ERR, "%s: %m", LF);
(void) open(_PATH_DEVNULL, O_WRONLY);
}
if (chdir(SD) < 0)
frecverr("%s: %s: %m", printer, SD);
if (stat(LO, &stb) == 0) {
if (stb.st_mode & 010) {
/* queue is disabled */
putchar('\1'); /* return error code */
exit(1);
}
} else if (stat(SD, &stb) < 0)
frecverr("%s: %s: %m", printer, SD);
minfree = 2 * read_number("minfree"); /* scale KB to 512 blocks */
signal(SIGTERM, rcleanup);
signal(SIGPIPE, rcleanup);
if (readjob())
printjob();
}
/*
* Read printer jobs sent by lpd and copy them to the spooling directory.
* Return the number of jobs successfully transfered.
*/
static int
readjob()
{
register int size, nfiles;
register char *cp;
ack();
nfiles = 0;
for (;;) {
/*
* Read a command to tell us what to do
*/
cp = line;
do {
if ((size = read(1, cp, 1)) != 1) {
if (size < 0)
frecverr("%s: Lost connection",printer);
return(nfiles);
}
} while (*cp++ != '\n');
*--cp = '\0';
cp = line;
switch (*cp++) {
case '\1': /* cleanup because data sent was bad */
rcleanup(0);
continue;
case '\2': /* read cf file */
size = 0;
while (*cp >= '0' && *cp <= '9')
size = size * 10 + (*cp++ - '0');
if (*cp++ != ' ')
break;
/*
* host name has been authenticated, we use our
* view of the host name since we may be passed
* something different than what gethostbyaddr()
* returns
*/
strcpy(cp + 6, from);
strcpy(tfname, cp);
tfname[0] = 't';
if (!chksize(size)) {
(void) write(1, "\2", 1);
continue;
}
if (!readfile(tfname, size)) {
rcleanup(0);
continue;
}
if (link(tfname, cp) < 0)
frecverr("%s: %m", tfname);
(void) unlink(tfname);
tfname[0] = '\0';
nfiles++;
continue;
case '\3': /* read df file */
size = 0;
while (*cp >= '0' && *cp <= '9')
size = size * 10 + (*cp++ - '0');
if (*cp++ != ' ')
break;
if (!chksize(size)) {
(void) write(1, "\2", 1);
continue;
}
(void) strcpy(dfname, cp);
if (index(dfname, '/'))
frecverr("readjob: %s: illegal path name",
dfname);
(void) readfile(dfname, size);
continue;
}
frecverr("protocol screwup: %s", line);
}
}
/*
* Read files send by lpd and copy them to the spooling directory.
*/
static int
readfile(file, size)
char *file;
int size;
{
register char *cp;
char buf[BUFSIZ];
register int i, j, amt;
int fd, err;
fd = open(file, O_CREAT|O_EXCL|O_WRONLY, FILMOD);
if (fd < 0)
frecverr("readfile: %s: illegal path name: %m", file);
ack();
err = 0;
for (i = 0; i < size; i += BUFSIZ) {
amt = BUFSIZ;
cp = buf;
if (i + amt > size)
amt = size - i;
do {
j = read(1, cp, amt);
if (j <= 0)
frecverr("Lost connection");
amt -= j;
cp += j;
} while (amt > 0);
amt = BUFSIZ;
if (i + amt > size)
amt = size - i;
if (write(fd, buf, amt) != amt) {
err++;
break;
}
}
(void) close(fd);
if (err)
frecverr("%s: write error", file);
if (noresponse()) { /* file sent had bad data in it */
(void) unlink(file);
return(0);
}
ack();
return(1);
}
static int
noresponse()
{
char resp;
if (read(1, &resp, 1) != 1)
frecverr("Lost connection");
if (resp == '\0')
return(0);
return(1);
}
/*
* Check to see if there is enough space on the disk for size bytes.
* 1 == OK, 0 == Not OK.
*/
static int
chksize(size)
int size;
{
int spacefree;
struct statfs sfb;
if (statfs(".", &sfb) < 0) {
syslog(LOG_ERR, "%s: %m", "statfs(\".\")");
return (1);
}
spacefree = sfb.f_bavail * (sfb.f_bsize / 512);
size = (size + 511) / 512;
if (minfree + size > spacefree)
return(0);
return(1);
}
static int
read_number(fn)
char *fn;
{
char lin[80];
register FILE *fp;
if ((fp = fopen(fn, "r")) == NULL)
return (0);
if (fgets(lin, 80, fp) == NULL) {
fclose(fp);
return (0);
}
fclose(fp);
return (atoi(lin));
}
/*
* Remove all the files associated with the current job being transfered.
*/
static void
rcleanup(signo)
int signo;
{
if (tfname[0])
(void) unlink(tfname);
if (dfname[0])
do {
do
(void) unlink(dfname);
while (dfname[2]-- != 'A');
dfname[2] = 'z';
} while (dfname[0]-- != 'd');
dfname[0] = '\0';
}
#if __STDC__
#include <stdarg.h>
#else
#include <varargs.h>
#endif
static void
#if __STDC__
frecverr(const char *msg, ...)
#else
frecverr(msg, va_alist)
char *msg;
va_dcl
#endif
{
extern char fromb[];
va_list ap;
#if __STDC__
va_start(ap, msg);
#else
va_start(ap);
#endif
rcleanup(0);
syslog(LOG_ERR, "%s", fromb);
vsyslog(LOG_ERR, msg, ap);
va_end(ap);
putchar('\1'); /* return error code */
exit(1);
}

136
usr.sbin/lpr/lpq/lpq.1 Normal file
View file

@ -0,0 +1,136 @@
.\" Copyright (c) 1983, 1990, 1993
.\" The Regents of the University of California. All rights reserved.
.\"
.\" Redistribution and use in source and binary forms, with or without
.\" modification, are permitted provided that the following conditions
.\" are met:
.\" 1. Redistributions of source code must retain the above copyright
.\" notice, this list of conditions and the following disclaimer.
.\" 2. Redistributions in binary form must reproduce the above copyright
.\" notice, this list of conditions and the following disclaimer in the
.\" documentation and/or other materials provided with the distribution.
.\" 3. All advertising materials mentioning features or use of this software
.\" must display the following acknowledgement:
.\" This product includes software developed by the University of
.\" California, Berkeley and its contributors.
.\" 4. Neither the name of the University nor the names of its contributors
.\" may be used to endorse or promote products derived from this software
.\" without specific prior written permission.
.\"
.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
.\" @(#)lpq.1 8.2 (Berkeley) 4/28/95
.\"
.Dd April 28, 1995
.Dt LPQ 1
.Os BSD 4.2
.Sh NAME
.Nm lpq
.Nd spool queue examination program
.Sh SYNOPSIS
.Nm lpq
.OP Fl a
.Op Fl l
.Op Fl P Ns Ar printer
.Op job # ...
.Op user ...
.Sh DESCRIPTION
.Nm Lpq
examines the spooling area used by
.Xr lpd 8
for printing files on the line printer, and reports the status of the
specified jobs or all jobs associated with a user.
.Nm Lpq
invoked
without any arguments reports on any jobs currently in the queue.
.Pp
Options:
.Pp
.Bl -tag -width indent
.It Fl P
Specify a particular printer, otherwise the default
line printer is used (or the value of the
.Ev PRINTER
variable in the
environment). All other arguments supplied are interpreted as user
names or job numbers to filter out only those jobs of interest.
.It Fl l
Information about each of the files comprising the job entry
is printed.
Normally, only as much information as will fit on one line is displayed.
.It Fl a
Report on the local queues for all printers,
rather than just the specified printer.
.El
.Pp
For each job submitted (i.e. invocation of
.Xr lpr 1 )
.Nm lpq
reports the user's name, current rank in the queue, the
names of files comprising the job, the job identifier (a number which
may be supplied to
.Xr lprm 1
for removing a specific job), and the total size in bytes.
Job ordering is dependent on
the algorithm used to scan the spooling directory and is supposed
to be
.Tn FIFO
(First in First Out).
File names comprising a job may be unavailable
(when
.Xr lpr 1
is used as a sink in a pipeline) in which case the file
is indicated as ``(standard input)''.
.Pp
If
.Nm lpq
warns that there is no daemon present (i.e. due to some malfunction),
the
.Xr lpc 8
command can be used to restart the printer daemon.
.Sh ENVIRONMENT
If the following environment variable exists, it is used by
.Nm lpq :
.Bl -tag -width PRINTER
.It Ev PRINTER
Specifies an alternate default printer.
.El
.Sh FILES
.Bl -tag -width "/var/spool/*/lock" -compact
.It Pa /etc/printcap
To determine printer characteristics.
.It Pa /var/spool/*
The spooling directory, as determined from printcap.
.It Pa /var/spool/*/cf*
Control files specifying jobs.
.It Pa /var/spool/*/lock
The lock file to obtain the currently active job.
.El
.Sh SEE ALSO
.Xr lpr 1 ,
.Xr lprm 1 ,
.Xr lpc 8 ,
.Xr lpd 8
.Sh HISTORY
.Nm Lpq
appeared in
.Bx 3 .
.Sh BUGS
Due to the dynamic nature of the information in the spooling directory
.Nm lpq
may report unreliably.
Output formatting is sensitive to the line length of the terminal;
this can results in widely spaced columns.
.Sh DIAGNOSTICS
Unable to open various files. The lock file being malformed. Garbage
files when there is no daemon active, but files in the spooling directory.

173
usr.sbin/lpr/lpq/lpq.c Normal file
View file

@ -0,0 +1,173 @@
/*
* Copyright (c) 1983, 1993
* The Regents of the University of California. All rights reserved.
*
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#ifndef lint
static char copyright[] =
"@(#) Copyright (c) 1983, 1993\n\
The Regents of the University of California. All rights reserved.\n";
#endif /* not lint */
#ifndef lint
static char sccsid[] = "@(#)lpq.c 8.3 (Berkeley) 5/10/95";
#endif /* not lint */
/*
* Spool Queue examination program
*
* lpq [-a] [-l] [-Pprinter] [user...] [job...]
*
* -a show all non-null queues on the local machine
* -l long output
* -P used to identify printer as per lpr/lprm
*/
#include <sys/param.h>
#include <syslog.h>
#include <dirent.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <ctype.h>
#include "lp.h"
#include "lp.local.h"
#include "pathnames.h"
int requ[MAXREQUESTS]; /* job number of spool entries */
int requests; /* # of spool requests */
char *user[MAXUSERS]; /* users to process */
int users; /* # of users in user array */
static int ckqueue __P((char *));
void usage __P((void));
int
main(argc, argv)
register int argc;
register char **argv;
{
extern char *optarg;
extern int optind;
int ch, aflag, lflag;
char *buf, *cp;
name = *argv;
if (gethostname(host, sizeof(host))) {
perror("lpq: gethostname");
exit(1);
}
openlog("lpd", 0, LOG_LPR);
aflag = lflag = 0;
while ((ch = getopt(argc, argv, "alP:")) != EOF)
switch((char)ch) {
case 'a':
++aflag;
break;
case 'l': /* long output */
++lflag;
break;
case 'P': /* printer name */
printer = optarg;
break;
case '?':
default:
usage();
}
if (!aflag && printer == NULL && (printer = getenv("PRINTER")) == NULL)
printer = DEFLP;
for (argc -= optind, argv += optind; argc; --argc, ++argv)
if (isdigit(argv[0][0])) {
if (requests >= MAXREQUESTS)
fatal("too many requests");
requ[requests++] = atoi(*argv);
}
else {
if (users >= MAXUSERS)
fatal("too many users");
user[users++] = *argv;
}
if (aflag) {
while (cgetnext(&buf, printcapdb) > 0) {
if (ckqueue(buf) <= 0) {
free(buf);
continue; /* no jobs */
}
for (cp = buf; *cp; cp++)
if (*cp == '|' || *cp == ':') {
*cp = '\0';
break;
}
printer = buf;
printf("%s:\n", printer);
displayq(lflag);
free(buf);
printf("\n");
}
} else
displayq(lflag);
exit(0);
}
static int
ckqueue(cap)
char *cap;
{
register struct dirent *d;
DIR *dirp;
char *spooldir;
if (cgetstr(cap, "sd", &spooldir) == -1)
spooldir = _PATH_DEFSPOOL;
if ((dirp = opendir(spooldir)) == NULL)
return (-1);
while ((d = readdir(dirp)) != NULL) {
if (d->d_name[0] != 'c' || d->d_name[1] != 'f')
continue; /* daemon control files only */
closedir(dirp);
return (1); /* found something */
}
closedir(dirp);
return (0);
}
void
usage()
{
puts("usage: lpq [-a] [-l] [-Pprinter] [user ...] [job ...]");
exit(1);
}

745
usr.sbin/lpr/lpr/lpr.c Normal file
View file

@ -0,0 +1,745 @@
/*
* Copyright (c) 1983, 1989, 1993
* The Regents of the University of California. All rights reserved.
* (c) UNIX System Laboratories, Inc.
* All or some portions of this file are derived from material licensed
* to the University of California by American Telephone and Telegraph
* Co. or Unix System Laboratories, Inc. and are reproduced herein with
* the permission of UNIX System Laboratories, Inc.
*
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#ifndef lint
static char copyright[] =
"@(#) Copyright (c) 1983, 1989, 1993\n\
The Regents of the University of California. All rights reserved.\n";
#endif /* not lint */
#ifndef lint
static char sccsid[] = "@(#)lpr.c 8.4 (Berkeley) 4/28/95";
#endif /* not lint */
/*
* lpr -- off line print
*
* Allows multiple printers and printers on remote machines by
* using information from a printer data base.
*/
#include <sys/param.h>
#include <sys/stat.h>
#include <sys/file.h>
#include <dirent.h>
#include <fcntl.h>
#include <a.out.h>
#include <signal.h>
#include <syslog.h>
#include <pwd.h>
#include <grp.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <ctype.h>
#include <string.h>
#include "lp.h"
#include "lp.local.h"
#include "pathnames.h"
static char *cfname; /* daemon control files, linked from tf's */
static char *class = host; /* class title on header page */
static char *dfname; /* data files */
static char *fonts[4]; /* troff font names */
static char format = 'f'; /* format char for printing files */
static int hdr = 1; /* print header or not (default is yes) */
static int iflag; /* indentation wanted */
static int inchar; /* location to increment char in file names */
static int indent; /* amount to indent */
static char *jobname; /* job name on header page */
static int mailflg; /* send mail */
static int nact; /* number of jobs to act on */
static int ncopies = 1; /* # of copies to make */
static char *person; /* user name */
static int qflag; /* q job, but don't exec daemon */
static int rflag; /* remove files upon completion */
static int sflag; /* symbolic link flag */
static int tfd; /* control file descriptor */
static char *tfname; /* tmp copy of cf before linking */
static char *title; /* pr'ing title */
static int userid; /* user id */
static char *width; /* width for versatec printing */
static struct stat statb;
static void card __P((int, char *));
static void chkprinter __P((char *));
static void cleanup __P((int));
static void copy __P((int, char []));
static void fatal2 __P((const char *, ...));
static char *itoa __P((int));
static char *linked __P((char *));
static char *lmktemp __P((char *, int, int));
static void mktemps __P((void));
static int nfile __P((char *));
static int test __P((char *));
void
main(argc, argv)
int argc;
char *argv[];
{
struct passwd *pw;
struct group *gptr;
extern char *itoa();
register char *arg, *cp;
char buf[BUFSIZ];
int i, f;
struct stat stb;
if (signal(SIGHUP, SIG_IGN) != SIG_IGN)
signal(SIGHUP, cleanup);
if (signal(SIGINT, SIG_IGN) != SIG_IGN)
signal(SIGINT, cleanup);
if (signal(SIGQUIT, SIG_IGN) != SIG_IGN)
signal(SIGQUIT, cleanup);
if (signal(SIGTERM, SIG_IGN) != SIG_IGN)
signal(SIGTERM, cleanup);
name = argv[0];
gethostname(host, sizeof (host));
openlog("lpd", 0, LOG_LPR);
while (argc > 1 && argv[1][0] == '-') {
argc--;
arg = *++argv;
switch (arg[1]) {
case 'P': /* specifiy printer name */
if (arg[2])
printer = &arg[2];
else if (argc > 1) {
argc--;
printer = *++argv;
}
break;
case 'C': /* classification spec */
hdr++;
if (arg[2])
class = &arg[2];
else if (argc > 1) {
argc--;
class = *++argv;
}
break;
case 'U': /* user name */
hdr++;
if (arg[2])
person = &arg[2];
else if (argc > 1) {
argc--;
person = *++argv;
}
break;
case 'J': /* job name */
hdr++;
if (arg[2])
jobname = &arg[2];
else if (argc > 1) {
argc--;
jobname = *++argv;
}
break;
case 'T': /* pr's title line */
if (arg[2])
title = &arg[2];
else if (argc > 1) {
argc--;
title = *++argv;
}
break;
case 'l': /* literal output */
case 'p': /* print using ``pr'' */
case 't': /* print troff output (cat files) */
case 'n': /* print ditroff output */
case 'd': /* print tex output (dvi files) */
case 'g': /* print graph(1G) output */
case 'c': /* print cifplot output */
case 'v': /* print vplot output */
format = arg[1];
break;
case 'f': /* print fortran output */
format = 'r';
break;
case '4': /* troff fonts */
case '3':
case '2':
case '1':
if (argc > 1) {
argc--;
fonts[arg[1] - '1'] = *++argv;
}
break;
case 'w': /* versatec page width */
width = arg+2;
break;
case 'r': /* remove file when done */
rflag++;
break;
case 'm': /* send mail when done */
mailflg++;
break;
case 'h': /* toggle want of header page */
hdr = !hdr;
break;
case 's': /* try to link files */
sflag++;
break;
case 'q': /* just q job */
qflag++;
break;
case 'i': /* indent output */
iflag++;
indent = arg[2] ? atoi(&arg[2]) : 8;
break;
case '#': /* n copies */
if (isdigit(arg[2])) {
i = atoi(&arg[2]);
if (i > 0)
ncopies = i;
}
}
}
if (printer == NULL && (printer = getenv("PRINTER")) == NULL)
printer = DEFLP;
chkprinter(printer);
if (SC && ncopies > 1)
fatal2("multiple copies are not allowed");
if (MC > 0 && ncopies > MC)
fatal2("only %d copies are allowed", MC);
/*
* Get the identity of the person doing the lpr using the same
* algorithm as lprm.
*/
userid = getuid();
if (userid != DU || person == 0) {
if ((pw = getpwuid(userid)) == NULL)
fatal2("Who are you?");
person = pw->pw_name;
}
/*
* Check for restricted group access.
*/
if (RG != NULL && userid != DU) {
if ((gptr = getgrnam(RG)) == NULL)
fatal2("Restricted group specified incorrectly");
if (gptr->gr_gid != getgid()) {
while (*gptr->gr_mem != NULL) {
if ((strcmp(person, *gptr->gr_mem)) == 0)
break;
gptr->gr_mem++;
}
if (*gptr->gr_mem == NULL)
fatal2("Not a member of the restricted group");
}
}
/*
* Check to make sure queuing is enabled if userid is not root.
*/
(void) sprintf(buf, "%s/%s", SD, LO);
if (userid && stat(buf, &stb) == 0 && (stb.st_mode & 010))
fatal2("Printer queue is disabled");
/*
* Initialize the control file.
*/
mktemps();
tfd = nfile(tfname);
(void) fchown(tfd, DU, -1); /* owned by daemon for protection */
card('H', host);
card('P', person);
if (hdr) {
if (jobname == NULL) {
if (argc == 1)
jobname = "stdin";
else
jobname = (arg = rindex(argv[1], '/')) ? arg+1 : argv[1];
}
card('J', jobname);
card('C', class);
card('L', person);
}
if (iflag)
card('I', itoa(indent));
if (mailflg)
card('M', person);
if (format == 't' || format == 'n' || format == 'd')
for (i = 0; i < 4; i++)
if (fonts[i] != NULL)
card('1'+i, fonts[i]);
if (width != NULL)
card('W', width);
/*
* Read the files and spool them.
*/
if (argc == 1)
copy(0, " ");
else while (--argc) {
if ((f = test(arg = *++argv)) < 0)
continue; /* file unreasonable */
if (sflag && (cp = linked(arg)) != NULL) {
(void) sprintf(buf, "%d %d", statb.st_dev, statb.st_ino);
card('S', buf);
if (format == 'p')
card('T', title ? title : arg);
for (i = 0; i < ncopies; i++)
card(format, &dfname[inchar-2]);
card('U', &dfname[inchar-2]);
if (f)
card('U', cp);
card('N', arg);
dfname[inchar]++;
nact++;
continue;
}
if (sflag)
printf("%s: %s: not linked, copying instead\n", name, arg);
if ((i = open(arg, O_RDONLY)) < 0) {
printf("%s: cannot open %s\n", name, arg);
continue;
}
copy(i, arg);
(void) close(i);
if (f && unlink(arg) < 0)
printf("%s: %s: not removed\n", name, arg);
}
if (nact) {
(void) close(tfd);
tfname[inchar]--;
/*
* Touch the control file to fix position in the queue.
*/
if ((tfd = open(tfname, O_RDWR)) >= 0) {
char c;
if (read(tfd, &c, 1) == 1 &&
lseek(tfd, (off_t)0, 0) == 0 &&
write(tfd, &c, 1) != 1) {
printf("%s: cannot touch %s\n", name, tfname);
tfname[inchar]++;
cleanup(0);
}
(void) close(tfd);
}
if (link(tfname, cfname) < 0) {
printf("%s: cannot rename %s\n", name, cfname);
tfname[inchar]++;
cleanup(0);
}
unlink(tfname);
if (qflag) /* just q things up */
exit(0);
if (!startdaemon(printer))
printf("jobs queued, but cannot start daemon.\n");
exit(0);
}
cleanup(0);
/* NOTREACHED */
}
/*
* Create the file n and copy from file descriptor f.
*/
static void
copy(f, n)
int f;
char n[];
{
register int fd, i, nr, nc;
char buf[BUFSIZ];
if (format == 'p')
card('T', title ? title : n);
for (i = 0; i < ncopies; i++)
card(format, &dfname[inchar-2]);
card('U', &dfname[inchar-2]);
card('N', n);
fd = nfile(dfname);
nr = nc = 0;
while ((i = read(f, buf, BUFSIZ)) > 0) {
if (write(fd, buf, i) != i) {
printf("%s: %s: temp file write error\n", name, n);
break;
}
nc += i;
if (nc >= BUFSIZ) {
nc -= BUFSIZ;
nr++;
if (MX > 0 && nr > MX) {
printf("%s: %s: copy file is too large\n", name, n);
break;
}
}
}
(void) close(fd);
if (nc==0 && nr==0)
printf("%s: %s: empty input file\n", name, f ? n : "stdin");
else
nact++;
}
/*
* Try and link the file to dfname. Return a pointer to the full
* path name if successful.
*/
static char *
linked(file)
register char *file;
{
register char *cp;
static char buf[BUFSIZ];
if (*file != '/') {
if (getwd(buf) == NULL)
return(NULL);
while (file[0] == '.') {
switch (file[1]) {
case '/':
file += 2;
continue;
case '.':
if (file[2] == '/') {
if ((cp = rindex(buf, '/')) != NULL)
*cp = '\0';
file += 3;
continue;
}
}
break;
}
strcat(buf, "/");
strcat(buf, file);
file = buf;
}
return(symlink(file, dfname) ? NULL : file);
}
/*
* Put a line into the control file.
*/
static void
card(c, p2)
register int c;
register char *p2;
{
char buf[BUFSIZ];
register char *p1 = buf;
register int len = 2;
*p1++ = c;
while ((c = *p2++) != '\0') {
*p1++ = (c == '\n') ? ' ' : c;
len++;
}
*p1++ = '\n';
write(tfd, buf, len);
}
/*
* Create a new file in the spool directory.
*/
static int
nfile(n)
char *n;
{
register int f;
int oldumask = umask(0); /* should block signals */
f = open(n, O_WRONLY | O_EXCL | O_CREAT, FILMOD);
(void) umask(oldumask);
if (f < 0) {
printf("%s: cannot create %s\n", name, n);
cleanup(0);
}
if (fchown(f, userid, -1) < 0) {
printf("%s: cannot chown %s\n", name, n);
cleanup(0);
}
if (++n[inchar] > 'z') {
if (++n[inchar-2] == 't') {
printf("too many files - break up the job\n");
cleanup(0);
}
n[inchar] = 'A';
} else if (n[inchar] == '[')
n[inchar] = 'a';
return(f);
}
/*
* Cleanup after interrupts and errors.
*/
static void
cleanup(signo)
int signo;
{
register i;
signal(SIGHUP, SIG_IGN);
signal(SIGINT, SIG_IGN);
signal(SIGQUIT, SIG_IGN);
signal(SIGTERM, SIG_IGN);
i = inchar;
if (tfname)
do
unlink(tfname);
while (tfname[i]-- != 'A');
if (cfname)
do
unlink(cfname);
while (cfname[i]-- != 'A');
if (dfname)
do {
do
unlink(dfname);
while (dfname[i]-- != 'A');
dfname[i] = 'z';
} while (dfname[i-2]-- != 'd');
exit(1);
}
/*
* Test to see if this is a printable file.
* Return -1 if it is not, 0 if its printable, and 1 if
* we should remove it after printing.
*/
static int
test(file)
char *file;
{
struct exec execb;
register int fd;
register char *cp;
if (access(file, 4) < 0) {
printf("%s: cannot access %s\n", name, file);
return(-1);
}
if (stat(file, &statb) < 0) {
printf("%s: cannot stat %s\n", name, file);
return(-1);
}
if ((statb.st_mode & S_IFMT) == S_IFDIR) {
printf("%s: %s is a directory\n", name, file);
return(-1);
}
if (statb.st_size == 0) {
printf("%s: %s is an empty file\n", name, file);
return(-1);
}
if ((fd = open(file, O_RDONLY)) < 0) {
printf("%s: cannot open %s\n", name, file);
return(-1);
}
if (read(fd, &execb, sizeof(execb)) == sizeof(execb) &&
!N_BADMAG(execb)) {
printf("%s: %s is an executable program", name, file);
goto error1;
}
(void) close(fd);
if (rflag) {
if ((cp = rindex(file, '/')) == NULL) {
if (access(".", 2) == 0)
return(1);
} else {
if (cp == file) {
fd = access("/", 2);
} else {
*cp = '\0';
fd = access(file, 2);
*cp = '/';
}
if (fd == 0)
return(1);
}
printf("%s: %s: is not removable by you\n", name, file);
}
return(0);
error1:
printf(" and is unprintable\n");
(void) close(fd);
return(-1);
}
/*
* itoa - integer to string conversion
*/
static char *
itoa(i)
register int i;
{
static char b[10] = "########";
register char *p;
p = &b[8];
do
*p-- = i%10 + '0';
while (i /= 10);
return(++p);
}
/*
* Perform lookup for printer name or abbreviation --
*/
static void
chkprinter(s)
char *s;
{
int status;
if ((status = cgetent(&bp, printcapdb, s)) == -2)
fatal2("cannot open printer description file");
else if (status == -1)
fatal2("%s: unknown printer", s);
if (cgetstr(bp, "sd", &SD) == -1)
SD = _PATH_DEFSPOOL;
if (cgetstr(bp, "lo", &LO) == -1)
LO = DEFLOCK;
cgetstr(bp, "rg", &RG);
if (cgetnum(bp, "mx", &MX) < 0)
MX = DEFMX;
if (cgetnum(bp,"mc", &MC) < 0)
MC = DEFMAXCOPIES;
if (cgetnum(bp, "du", &DU) < 0)
DU = DEFUID;
SC = (cgetcap(bp, "sc", ':') != NULL);
}
/*
* Make the temp files.
*/
static void
mktemps()
{
register int len, fd, n;
register char *cp;
char buf[BUFSIZ];
char *lmktemp();
(void) sprintf(buf, "%s/.seq", SD);
if ((fd = open(buf, O_RDWR|O_CREAT, 0661)) < 0) {
printf("%s: cannot create %s\n", name, buf);
exit(1);
}
if (flock(fd, LOCK_EX)) {
printf("%s: cannot lock %s\n", name, buf);
exit(1);
}
n = 0;
if ((len = read(fd, buf, sizeof(buf))) > 0) {
for (cp = buf; len--; ) {
if (*cp < '0' || *cp > '9')
break;
n = n * 10 + (*cp++ - '0');
}
}
len = strlen(SD) + strlen(host) + 8;
tfname = lmktemp("tf", n, len);
cfname = lmktemp("cf", n, len);
dfname = lmktemp("df", n, len);
inchar = strlen(SD) + 3;
n = (n + 1) % 1000;
(void) lseek(fd, (off_t)0, 0);
sprintf(buf, "%03d\n", n);
(void) write(fd, buf, strlen(buf));
(void) close(fd); /* unlocks as well */
}
/*
* Make a temp file name.
*/
static char *
lmktemp(id, num, len)
char *id;
int num, len;
{
register char *s;
if ((s = malloc(len)) == NULL)
fatal2("out of memory");
(void) sprintf(s, "%s/%sA%03d%s", SD, id, num, host);
return(s);
}
#if __STDC__
#include <stdarg.h>
#else
#include <varargs.h>
#endif
static void
#if __STDC__
fatal2(const char *msg, ...)
#else
fatal2(msg, va_alist)
char *msg;
va_dcl
#endif
{
va_list ap;
#if __STDC__
va_start(ap, msg);
#else
va_start(ap);
#endif
printf("%s: ", name);
vprintf(msg, ap);
putchar('\n');
va_end(ap);
exit(1);
}