mirror of
https://github.com/freebsd/freebsd-src
synced 2024-09-27 04:05:10 +00:00
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:
parent
edbfedac86
commit
0b561052df
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/vendor/CSRG/dist/; revision=15637
400
usr.sbin/lpr/common_source/aux.c
Normal file
400
usr.sbin/lpr/common_source/aux.c
Normal 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 */
|
67
usr.sbin/lpr/common_source/aux.h
Normal file
67
usr.sbin/lpr/common_source/aux.h
Normal 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
|
377
usr.sbin/lpr/common_source/common.c
Normal file
377
usr.sbin/lpr/common_source/common.c
Normal 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);
|
||||
}
|
450
usr.sbin/lpr/common_source/displayq.c
Normal file
450
usr.sbin/lpr/common_source/displayq.c
Normal 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);
|
||||
}
|
127
usr.sbin/lpr/common_source/lp.h
Normal file
127
usr.sbin/lpr/common_source/lp.h
Normal 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
|
551
usr.sbin/lpr/common_source/printcap.c
Normal file
551
usr.sbin/lpr/common_source/printcap.c
Normal 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);
|
||||
}
|
339
usr.sbin/lpr/common_source/rmjob.c
Normal file
339
usr.sbin/lpr/common_source/rmjob.c
Normal 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
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
175
usr.sbin/lpr/lpc/lpc.8
Normal 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
314
usr.sbin/lpr/lpc/lpc.c
Normal 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
542
usr.sbin/lpr/lpd/lpd.c
Normal 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
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
358
usr.sbin/lpr/lpd/recvjob.c
Normal 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
136
usr.sbin/lpr/lpq/lpq.1
Normal 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
173
usr.sbin/lpr/lpq/lpq.c
Normal 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
745
usr.sbin/lpr/lpr/lpr.c
Normal 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);
|
||||
}
|
Loading…
Reference in a new issue