v16i018: Public lineprinter spooler package, Part05/16

Rich Salz rsalz at uunet.uu.net
Thu Sep 15 06:16:45 AEST 1988


Submitted-by: papowell at julius.cs.umn.edu
Posting-number: Volume 16, Issue 18
Archive-name: plp/part05

#! /bin/sh
# This is a shell archive.  Remove anything before this line, then unpack
# it by saving it into a file and typing "sh file".  To overwrite existing
# files, type "sh file -c".  You can also feed this as standard input via
# unshar, or by typing "sh <file", e.g..  If this archive is complete, you
# will see the following message at the end:
#		"End of archive 5 (of 16)."
# Contents:  doc/PLP/05.t doc/PLP/09.t filters/lpf.c man/lpd.8
#   man/lpr.1 src/mexecv.c src/rmjob.c
# Wrapped by papowell at attila on Wed Aug 10 10:44:53 1988
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f 'doc/PLP/05.t' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'doc/PLP/05.t'\"
else
echo shar: Extracting \"'doc/PLP/05.t'\" \(7584 characters\)
sed "s/^X//" >'doc/PLP/05.t' <<'END_OF_FILE'
X.ig
X$Header: 05.t,v 1.1 88/05/21 18:39:40 papowell Locked $
X$log$
X..
X.bp
X.NH 1
Remote Spool Queue
X.PP
XEntries in a remote spool queue are transfered to the remote host
by a server process forked by the
X.I lpd
daemon.
The server process checks the spool queue for entries
and then initiates communication with the remote host and the 
line printer daemon on the remote end.
The following section discusses the protocol used to transfer files
to the remote hosts.
X.NH 2
XEstablishing Communication
X.PP
Interhost job transfer is done by using the Internet (Inet)
interprocess communication facilities.
XFor an excellent tutorial on this,
see the 4.3BSD Advanced Tutorial On Interprocess Communications.
The client or process that wishes to send files to a remote host
establishes communication using the following procedure.
X.IP 1). 3
The client opens an AF_INET socket,
using the SOCK_STREAM protocol.
The socket will use a reliable message delivery method for
communication.
Note that the socket is written to send a message,
read to receive a message.
X.IP 2). 3
The client socket is bound to a reserved port on the local host,
that is,
a port on the local host whose port number is less than 1024.
These are reserved ports and can only be bound to by
root processes or a process which
is SUID root.
The server on the remote machine will check to ensure that the
client originated his request from a reserved port.
X.IP 3). 3
The client determines the remote host addressing information using the
X.IR gethostbynam (3)
facility.
This returns the network address of the remote host.
X.IP 4). 3
The client determines the port number that the remote
X.I lpd
server is listening on by using the
X.IR getservent (3)
facility;
for example,
X.L getservent("printer","tcp")
will return the port number and other needed information.
X.IP 5). 3
Using the above information,
the client process will use
X.IR connect (2)
to establish a connection to the remote host.
If the connect call fails,
then the client may retry a couple of times until successful,
or terminate with an error condition.
X.NH 2
Sending Requests
X.PP
After establishing connection with the remote host,
the
X.I lpd
daemon will fork a server process to deal with the request.
The format of the requests is specified in
Table 1.1.
Requests consist of a simple message consisting of a flag
X(unsigned character value) followed by a string terminated with a
new line character.
XFor example,
the request to transfer files to the remote host consists of a line of the
form:
X.ti +5n
X\&^Bprinter
X.PP
The remote server process uses network supplied information to
determine the name of the client host machine,
and the port that originated the message.
It will check the local
printer permissions file to determine if the host is allowed to access
the specified printer spool queue.
After checking this basic permission,
the remote host will then perform any requested actions.
X.NH 2
XFile Transfers
X.PP
A job is transferred between the local and remote hosts by using one
of two methods.
The first method is to send the data files of a job first,
followed by the control file (Berkeley Protocol);
the second method is to send the control file,
followed by the data files (PLP Protocol).
The
X.B fj
flag is used to select the PLP (control file first) protocol to be used
in sending jobs.
The default protocol is the Berkeley (data files first) protocol.
X.PP
The file transfer protocol consists of sending a line identifying
the type of protocol being used,
the size of the file (in bytes),
and the name of the file.
The remote host will return a single
X0 (zero)
confirmation byte if it agrees to accept the file;
any other value is a fatal error.
After confirmation,
the file is transferred to the other end,
followed by a single
X0 (zero) byte.
If the remote end receives the file and the terminating 0 byte,
it will return a confirming
X0 (zero) byte.
The next file may then be transferred.
After all files have been transferred,
a single
X0 (zero) byte will terminate the file transfer.
X.PP
The file transferred to the remote site will be placed in the
remote site spool queue directory,
with the same path name it had at the local site.
Both the local and remote sites will lock any files being
transfered in order to prevent other PLP processes from
manipulating them.
Table 5.1 specifies the values of the flags used in the protocol.
X.KF
X.TS
tab(:) box center;
l | l | l.
Protocol:Flag:Meaning
X_
Berkeley:2 (^B):control file
Both:3 (^C):data file
PLP:4 (^D):control file
PLP:5 (^E):last file
X.TE
X.ce
Table 5.1. File Transfer Protocol Flags
X.KE
X.PP
To use the Berkeley Protocol,
the data files would be transferred first using the 3 (^B) flag,
followed by the control file using the 2 (^C) flag.
To use the PLP Protocol,
the control file would be transferred first
using the 4 (^D) flag,
followed by the data files.
When all of the data files had been transferred,
a confirming message would be sent using the 5 (^E) flag,
indicating that the job had been transferred.
X.PP
XFor example,
assume that we have a job with a control file
X.L cfA123attila.cs.umn.edu ,
and a data file
X.L dfA123attila.cs.umn.edu .
Using the Berkeley Protocol,
the client would first send the message
X.ti +5n
X.L "^C1293 dfA123attila.cs.umn.edu" ,
X.br
requesting transfer of a 1293 byte data file,
whose name is
X.L dfA123attila .
After confirmation,
the data file followed by a single 0 byte would be sent,
and a confirmation should be received.
Next,
the message
X.L "^B343 cfA123attila.cs.umn.edu" ,
would be sent,
and then the control file followed by a single 0 byte would be sent.
Having received the control file,
the remote end would acknowledge the reception of the job,
allowing the client to delete the job and send another one.
When control file is transferred,
the remote host will check the job to make sure that all data files have
been transferred,
and enable it for printing or further processing.
If anything happens to disturb this communication,
the connection is terminated and any partially transferred jobs are
removed.
X.PP
To prevent interaction between an unspooler server and a file
transfer server,
the job control file is locked by the file transfer server until it
has been completely transferred.
X.NH 2
XError Recovery and Retry
X.PP
When either end of the file transfer protocol detects an error,
they will shut down the link.
It is the responsibility of the client process to retry sending jobs.
X.NH 2
Security Checks and Authorizations
X.PP
The PLP file transfer protocol restricts the names of control and
data files to a fixed format.
In addition,
the
X.B U
X(unlink) flag has no effect on a remote host.
The enforcement of the fixed format of data and control file names
makes it simple to remove all files associated with a job on
completion.
X.PP
Before placing a job in the spool queue,
the user name and hostname are checked to see if permissions are
acceptible.
The security of this check is based on the assumption that the client
host is a trusted originator of PLP jobs.
In a networked environment with many different users,
this may not be the case,
as it is possible to forge information in a control file.
The
X.B fd
X(no forward)
flag in a printcap entry prevents the acceptance of jobs from other than
the current client.
This is intended to prevent clients from attempting to transfer control
files that would appear to have originated from another
host.
While this will provide verification at the host level,
assuming that network level software will uniquely identify a host,
it still does not provide a secure user identification.
END_OF_FILE
if test 7584 -ne `wc -c <'doc/PLP/05.t'`; then
    echo shar: \"'doc/PLP/05.t'\" unpacked with wrong size!
fi
# end of 'doc/PLP/05.t'
fi
if test -f 'doc/PLP/09.t' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'doc/PLP/09.t'\"
else
echo shar: Extracting \"'doc/PLP/09.t'\" \(6569 characters\)
sed "s/^X//" >'doc/PLP/09.t' <<'END_OF_FILE'
X.ig
X$Header: 09.t,v 1.1 88/05/21 18:39:48 papowell Locked $
X$log$
X..
X.NH 1
Line Printer Spooler Administration
X.PP
Most of the administration of PLP commands consists of
printcap entries,
permissions entries,
and spooler queue management.
In addition,
killing and restarting the
X.I lpd
daemon is sometimes needed.
X.NH 2
Printcap File Management
X.PP
XEach spool queue or printer must have an entry in a printcap file.
In a single,
non-networked environment,
this is usually a simple and easily managed system,
but in a highly networked environment it may be a difficult procedure.
In order to simply the generation of printcap files,
the PLP distribution has a set of programs that allow a simple printcap
data base to be set up,
and a set of programs to generate printcaps for different hosts.
X.NH 3
Printer Names
X.PP
Printer names and aliases are a major problem faced by administrators.
The convention adopted by many sites is to make the primary (first)
name of the printer correspond to the physical printer type and its
location.
XFor exmple,
X.L lw_lind23
is the name of the Apple LaserWriter in Lind Hall 23.
Additional aliases or names can then be added.
X.PP
In performing permissions checking,
the name supplied by the user is checked against the information in the
printer permissions file,
and also checked in the printcap database.
XFor this reason,
the name used in the printer permissions file and the
name of the printer should be identical.
When sending files to a remote site,
the printer name found in the printcap entry and not the
alias provided by a user is used to determine permissions.
X.NH 3
Printcap File Generation
X.PP
XEach printer usually has three forms of printcap entries:
remote,
forward,
and actual device.
The remote entry is used by a system that will treat the spool queue
as a remote site and forward all jobs to a remote site.
The forwarding entry is usually used for sites that accept jobs
from other sites,
and then forward them to a remote site.
The forwarding is usually done by a specialized file transfer program.
XFinally,
a local or actual device entry is used for the host which has the
actual printer attached.
XFiles with the appropriate form printcap entry can be prepared.
As part of the PLP software,
a set of programs to generate printcap files tailored to a
particular host has been developed,
and is available in the
X.L printcap
directory.
X.NH 3
Printer Permissions File
X.PP
The main printer permissions file is intended to act as a filter for
general user permissions.
As described elsewhere,
each line is checked for a matching set of user permissions,
and the first matching line determines the available permissions.
It is strongly suggested that the set of entries in the printcap
file be used to filter out unauthorized users,
and the remaining set of entries used to determine the appropriate
permissions.
X.PP
If restrictions on the number of pages are desired,
the printer permissions file can be used on a global or local basis.
The current page count field is compared against the maximum
field at the time a job is spooled or printed.
In order to keep this file concurrent,
some form of simple permissions file updating must be done.
This can be done by using the
X.I pac
X(printer accounting) program and a suitable shell script.
Due to the wide divergence of different sites,
an accounting package to do this automatically has not been
provided.
X.NH 2
Using LPC
X.PP
The
X.I lpc
program provides control over line printer activity.
The major commands and their intended use are described in this section.
See 
X.IR lpc (8)
for details.
X.LP
X.B
status and lpq
X.R
X.IP
Status is used to display the current status of various line printers.
The lpq function invokes lpq with various parameters.
This is useful to monitor various printer activities.
X.LP
X.B
start, abort, kill
X.R
X.IP
X.I Start
enables printing and requests 
X.I lpd
to start printing jobs.
X.sp
X.I Abort
disables unspooling and terminates an active server and its
filters.
This is normally used to kill a
catatonic filter or spooler process
X(i.e.,
X.I lpq
reports that there is a daemon present but nothing is
happening).
It does not remove any jobs from the queue.
X.sp
X.I Kill
does an abort followed by a start.
This is handy to kill a server and start another.
Note that there is an upper limit on the numbers of times a server will
attempt to print a job.
X.B
enable and disable
X.R
X.IP
X.I Enable
and 
X.I disable
control spooling to a queue.
This is used to prevent
X.I lpr
from putting new jobs in the spool queue.
The main use is to prevent users from putting jobs in the queue
when the printer is expected to be unavailable for a long time.
X.LP
X.B restart
X.IP
X.I Restart
allows mere mortals users to restart printer daemons when
X.I lpq
reports that there is no daemon present.
X.LP
X.B stop
X.IP
X.I Stop
disables unspooling,
but does not kill off the server.
This is a clean way to shutdown a printer in order to perform
maintenence, etc.
Note that users can still enter jobs in a
spool queue while a printer is
X.IR stopped .
X.LP
X.B topq
X.IP
X.I Topq
places jobs at the top of a printer queue.
This can be used to reorder high priority jobs.
X.LP
X.B
remote (command)
X.R
X.IP
X.I remote
is used to send a command to the remote site for processing.
This is useful to control remote line printer queues.
X.LP
X.B clean
X.IP
X.I clean
totally purges a queue.
This functionality is needed very infrequently,
and perhaps should be removed.
X.NH 2
Starting the LPD Daemon
X.PP
Under various circumstances it may be necessary to kill and/or
restart the
X.I lpd
daemon.
The currently executing daemon writes
its process ID and the time it was started in the
X.L /usr/spool/lock.lpd 
file.
The
program in Figure 9.1,
usually stored in
X.L /usr/etc/lpd.kill ,
can be used to kill and restart the LPD daemon.
X.KF
X.in +1i
X.SM
X.L
X.nf
X.ta 4n +4n +4n +4n +4n +4n +4n +4n +4n +4n +4n +4n +4n 8i
X#!/bin/csh -f
set p=`head -1 /usr/spool/lpd.lock`
set h=`hostname`
if ( "$p" == "" ) then
X	echo $h - no lpd daemon
else
X	echo $h - daemon $p
X	kill $p
X	sleep 1
X	/usr/lib/lpd
endif
X.fi
X.LG
X.R
X.in -1i
X.ce
XFigure 9.1 lpd.kill Program
X.KE
X.PP
In a heavily networked system,
it may be desirable to kill and restart daemons on a set of machines.
The
program in Figure 9.2,
usually stored in
X.L /usr/etc/lpd.all ,
can be used to kill and restart remote daemons.
X.KF
X.in +1i
X.SM
X.L
X.nf
X.ta 4n +4n +4n +4n +4n +4n +4n +4n +4n +4n +4n +4n +4n 8i
X#!/bin/csh -f
set l=(`cat /etc/remote.lpd`)
foreach  i ($l)
X	rsh $i /usr/etc/lpd.kill
X	echo done $i
endfor
X.LG
X.R
X.in -1i
X.ce
XFigure 9.2 lpd.all Program
X.KE
END_OF_FILE
if test 6569 -ne `wc -c <'doc/PLP/09.t'`; then
    echo shar: \"'doc/PLP/09.t'\" unpacked with wrong size!
fi
# end of 'doc/PLP/09.t'
fi
if test -f 'filters/lpf.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'filters/lpf.c'\"
else
echo shar: Extracting \"'filters/lpf.c'\" \(6527 characters\)
sed "s/^X//" >'filters/lpf.c' <<'END_OF_FILE'
X/***************************************************************************
X * U. Minnesota LPD Software * Copyright 1987, 1988, Patrick Powell
X ***************************************************************************
X * MODULE:  lpf.c
X ***************************************************************************
X * Revision History: Created Fri Mar  4 19:05:43 CST 1988
X * $Log:	lpf.c,v $
X * Revision 2.2  88/05/19  07:35:38  papowell
X * fixed minor bug with overstrikes
X * 
X * Revision 2.1  88/05/09  10:12:08  papowell
X * *** empty log message ***
X * 
X ***************************************************************************/
X#ifndef lint
static char id_str1[] =
X	"$Header: lpf.c,v 2.2 88/05/19 07:35:38 papowell Locked $ PLP Copyright 1988 Patrick Powell";
X#endif lint
X/***************************************************************************
X *	LPF and VPF filters.
X * 	Filter which converts lines with ^H's to overwritten lines.
X *	Thus this works like 'ul' but is much better; it can handle
X *	more than 2 overwrites and it is written with some style.
X *
X *	Also used as the versatec driver, with the VERSATEC defined
X *  Original source for this was the 4.2BSD release,  but there have
X *	been substantial modifications since.  This version has been derived 
X *	from a total rewrite done in 1985.
X ***************************************************************************/
X
X#include <stdio.h>
X#include <ctype.h>
X#include <signal.h>
X#include <sys/types.h>
X#include <sys/time.h>
X
extern int errorcode;
X/* set from flags */
extern int debug, width, length, xwidth, ylength, literal, indent;
extern char *zopts, *class, *job, *login, *accntname, *host, *accntfile;
extern char *printer, *format, *name;
extern int npages;	/* number of pages */
extern char *calloc();	/* memory allocation */
X
X#ifdef VERSATEC
X#include <sys/vcmd.h>
X
X
int	pltmode[] = {VPLOT};
int	prtmode[] = {VPRINT};
X#define MAXREP		10
X
X#else  VERSATEC
X/* line printer */
X
X#define MAXREP		10
X#endif VERSATEC
X
X#define	TIMEOUT		(5*60)	/*	5 minute time out	*/
X
char	*buf;
int	*maxcol;
int	lineno;
X
X
int	timeout();
X
filter(stop)
X	char *stop;
X{
X	register FILE *p = stdin, *o = stdout;
X	register int i, j, col;
X	register char *cp;
X	int done, linedone, maxrep;
X	unsigned int bufsize;
X	char ch, *limit;
X	int state, partial;
X
X	partial = 0;
X	state = 0;
X	if( xwidth <= 0 ){
X		xwidth = width;
X		/* fatal( "bad xwidth value %d", xwidth ); */
X	}
X	if( width > xwidth || width <= 0 ){
X		fatal( "width (%d) out of range, max %d", width, xwidth );
X	}
X	/*
X	 * check on width 
X	 */
X	bufsize =  (unsigned)( MAXREP * xwidth );
X	if( (buf = calloc( bufsize, sizeof(char) )) == 0 
X		|| (maxcol = (int *)calloc( (unsigned)( MAXREP ), sizeof(int) )) == 0 ){
X		fatal( "malloc failed");
X	}
X	maxcol[0] = -1;
X	state = 0;
X	/*
X	 * set up timeout
X	 */
X
X#	ifdef VERSATEC
X	(void) signal( SIGALRM, timeout );
X	errorcode = 1;	/* set retry on failure */
X	if( ioctl(1, VSETSTATE, prtmode) < 0 ){
X		logerr_die( "ioctl failed" );
X	}
X#	endif VERSATEC
X
X
X	for( i = 0; i < MAXREP; ++i ){
X		maxcol[i] = -1;
X	}
X	for( i = 0; i < bufsize; ++i ){
X		buf[i] = ' ';
X	}
X	done = 0;
X
X	while (!done) {
X		col = indent;
X		maxrep = -1;
X		linedone = 0;
X		while (!linedone) {
X			if( state ){
X				/* we read a partial stop and want to process it normally */
X				ch = stop[partial];
X				++partial;
X				if( partial == state ){
X					state = 0;
X				}
X			} else {
X				ch = getc(p);
X				if( stop && ch == *stop){
X					/* we have hit the first character in the stop sequence */
X					for(state = 1;
X						stop[state] && (ch = getc(p)) == stop[state];
X						++state );
X					/* we either have last, or we have a bad character */
X					if( stop[state] == 0 ){
X						state = 0; /* suspend yourself!! */
X						/*
X						 * if this filter is running as the OF
X						 * filter, it is used only for banners.
X						 * lpd needs to use a different filter to
X						 * print data so stop what we are doing and
X						 * wait for lpd to restart us.
X						 */
X						(void)alarm( TIMEOUT );
X						if( fflush(stdout) < 0 ){
X							logerr_die( "fflush failed" );
X						}
X						(void)alarm( 0 );
X						suspend();
X#						ifdef VERSATEC
X						if( ioctl(1, VSETSTATE, prtmode) < 0 ){
X							logerr_die( "ioctl failed" );
X						}
X#						endif VERSATEC
X					} else {
X						/* we don't have all of the characters */
X						partial = 0;
X						if( ch != EOF ){
X							(void)ungetc(ch, stdin);
X						}
X					}
X					/* we want to iterate, using new characters */
X					continue;
X				}
X			}
X			switch (ch) {
X			case EOF:
X				linedone = done = 1;
X				ch = '\n';
X				break;
X
X			case '\f':
X				lineno = length;
X			case '\n':
X				if (maxrep < 0)
X					maxrep = 0;
X				linedone = 1;
X				break;
X
X			case '\b':
X				--col;
X				if( col < indent)
X					col = indent;
X				break;
X
X			case '\r':
X				col = indent;
X				break;
X
X			case '\t':
X				col = ((col - indent) | 07) + indent + 1;
X				break;
X
X			default:
X				if (col >= width || !literal && !isprint(ch)) {
X					col++;
X					break;
X				}
X				if(debug)fprintf(stderr,"ch '%c', col %d\n", ch, col );
X				cp = buf+col;
X				for (i = 0; i < MAXREP; i++) {
X					if (i > maxrep)
X						maxrep = i;
X					if (*cp == ' ') {
X						*cp = ch;
X						if (col > maxcol[i])
X							maxcol[i] = col;
X						break;
X					}
X					cp += xwidth;
X				}
X				col++;
X			}
X		}
X
X		/* print out lines */
X		(void)alarm( TIMEOUT );
X		/* print out the lines in order of last to first */
X		if(debug){
X			fprintf(stderr,"maxrep %d\n");
X		}
X		for (i = maxrep; i >= 0;  --i) {
X			cp = buf+i*xwidth;
X			if(debug){
X				fprintf(stderr,"line %d, col %d, '%s'\n",i,
X					maxcol[i], cp);
X			}
X			if( (col = maxcol[i]+1) > 0 ){
X				if(col != fwrite(cp,1,col,o)){
X					logerr_die( "write failed" );
X				}
X			}
X			for( j = 0; j < xwidth; ++j ){
X				cp[j] = ' ';
X			}
X			maxcol[i] = -1;
X#			ifdef PRINTRONIX
X			if( putc('\r', o) < 0 ){
X				logerr_die( "putc failed" );
X			}
X#			else  PRINTRONIX
X			if( i > 0 ){
X				if( putc('\r', o) < 0 ){
X					logerr_die( "putc failed" );
X				}
X			}
X#			endif PRINTRONIX
X		}
X		if( putc(ch, o) < 0 ){
X			logerr_die( "write failed" );
X		}
X		(void)alarm( 0 );
X
X		/*
X		 * update page count
X		 */
X		if(++lineno >= length){
X			npages++;
X			lineno = 0;
X		}
X	}
X
X	(void)alarm( TIMEOUT );	/* set up timeout */
X	if (lineno) {		/* be sure to end on a page boundary */
X		if( putc('\f', o) < 0 ){
X			logerr_die( "putc failed" );
X		}
X		npages++;
X	}
X	(void)fflush( o );
X	if( ferror(o) ){
X		logerr_die( "write failed" );
X	}
X	(void)alarm( 0 );
X    }
X
X
timeout()
X    {
X	fatal( "timeout" );
X    }
X
X/*
X * do nothing on cleanup
X */
X
cleanup()
X    {}
END_OF_FILE
if test 6527 -ne `wc -c <'filters/lpf.c'`; then
    echo shar: \"'filters/lpf.c'\" unpacked with wrong size!
fi
# end of 'filters/lpf.c'
fi
if test -f 'man/lpd.8' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'man/lpd.8'\"
else
echo shar: Extracting \"'man/lpd.8'\" \(6781 characters\)
sed "s/^X//" >'man/lpd.8' <<'END_OF_FILE'
X.TH LPD 8 "19 Mar 1988" "U-MN PLP"
X.ig
X$Header: lpd.8,v 2.1 88/05/09 10:08:31 papowell Exp $
X$Log:	lpd.8,v $
Revision 2.1  88/05/09  10:08:31  papowell
PLP: Released Version
X
Revision 1.1  88/04/28  10:58:50  papowell
Initial revision
X
X..
X.SH NAME
lpd \- line printer daemon
X.SH SYNOPSIS
X.B /usr/lib/lpd
X[\-Llogfile] [\-D[n]] [\-X]
X.SH DESCRIPTION
X.I Lpd
is the line printer daemon (spool queue handler) and is normally invoked
at boot time from the
X.IR rc (8)
file.  It makes a single pass through the
X.IR printcap (5)
file to find out about the existing printers and
starts spool queue servers.
It then uses the system calls
X.IR listen (2)
and
X.IR accept (2)
to receive requests to print files in the queue,
transfer files to the spooling area,
display the queue,
remove jobs from the queue,
or perform a spool queue control function.
In each case it creates a server process to handle
the request and the lpd process will listen for more requests.
The
X.B \-L
option specifies an alternate file to be used for logging error messages.
The
X.IR syslog (8)
facility is used to log critical messages as well.
The
X.B \-D
flag enables generation of debugging messages,
and the 
X.B \-X
flag forces use of an Xperimental version of the software if it
is avilable.
X.PP
Access control is provided by two means:
a general set of printer permissions determined by the
X.I /etc/printer_perm
file,
and an optional additional set of restrictions set by the
X.B XU
X(check user) permissions file specified in the printcap entry.
XEach entry in the /etc/printer_perm file specifies a machine,
user,
printer,
and maximum priority allowed;
the ``*'' is a wildcard entry and matches anything.
XFor example,
the following entry allows root on any machine,
to have to access to all queues and any priority,
all users to have access to the lp queue but only a max of
C priority,
and admin on central to have access to the pr queue.
The max and current fields are used to determine the maximum
and current number of pages used by a particular user;
this information is checked by the particular device
to determine if a user or group of users have exceeded their
limits,
and is usually present only in the device specific permissions file.
X.RS
X.nf
X.ta 1.i +1.i +1.i +.5i +.5i +.5i +.5i +.5i +.5i +.5i +.5i
X#host	user	queue	priority	max	current
X*	root	*	A	0	0
X*	*	lp	C	0	0
central	admin	lp	C	0	0
X.fi
X.RE
X.PP
The spool queue
X.I lock
file in each spool directory is used to
control spooling activities,
prevent multiple servers from becoming active simultaneously,
and to store information about the server process.
The
X.IR lpr (1),
X.IR lpq (1),
X.IR lpc (1)
and
X.IR lprm (1)
programs use this file to report on queue status.
To gain control of a spool queue,
a server process locks the control file,
and then unspools the jobs.
XEach job has a control file and a set of data files.
Lines in the control file
file specify files to be printed or non-printing actions to be
performed.
XEach line consists of a flag character and a parameter.
Lower case letters are reserved for the format
indication,
specified by the 
X\-F
option of LPR.
the following is a partial list of the flag characters and their uses.
X.in +3
X.IP J
Job Name.  String to be used for the job name on the burst page.
X.IP C
Classification.
String to be used for the classification line
on the burst page and to determine job priority.
The first letter of the string sets the level;
A is highest, Z is lowest.
The maximum level that can be used is determined by the
printer_perm database and/or the
X.B XU
printcap entry.
X.IP L
Literal.
The line contains identification info from
the password file and appears on the banner page.
X.IP T
Title.  String to be used as the title for
X.IR pr (1).
X.IP H
Host Name.  Name of the machine where
X.I lpr
was invoked.
X.IP P
Person.  Login name of the person who invoked
X.IR lpr .
This is used to verify ownership by
X.IR lprm .
X.IP M
Send mail to the specified user when the current print job completes.
X.IP Z
zoptions. Options passed by
X.IR lpr
X.IR -Zzoptions.
These are passed to output filters.
X.IP f
XFormatted File.  Name of a file to print which is already formatted.
X.IP l
Like ``f'' but passes control characters and does not make page breaks.
X.IP p
Name of a file to print using
X.IR pr (1)
as a filter.
X.IP t
Troff File.  The file contains
X.IR troff (1)
output (cat phototypesetter commands).
X.IP d
DVI File.  The file contains
X.IR Tex (l)
output (DVI format from Stanford).
X.IP g
Graph File.  The file contains data produced by
X.IR plot (3X).
X.IP c
Cifplot File. The file contains data produced by
X.IR cifplot .
X.IP v
The file contains a raster image.
X.IP r
The file contains text data with FORTRAN carriage control characters.
X.IP 1
Troff Font R. Name of the font file to use instead of the default.
X(Obsolete, not used)
X.IP 2
Troff Font I. Name of the font file to use instead of the default.
X(Obsolete, not used)
X.IP 3
Troff Font B. Name of the font file to use instead of the default.
X(Obsolete, not used)
X.IP 4
Troff Font S. Name of the font file to use instead of the default.
X(Obsolete, not used)
X.IP W
Width. Changes the page width (in characters) used by
X.IR pr (1)
and the text filters.
X.IP I
Indent.  The number of characters to indent the output by (in ascii).
X.IP U
Unlink.  Name of file to remove upon completion of printing.
X.IP N
XFile name.  The name of the file which is being printed, or a blank
for the standard input (when 
X.I lpr
is invoked in a pipeline).
X.in -5
X.PP
The spool server will attempt to print a job a limited number of times
before abandoning it.
X.PP
X.I Lpd
uses
X.IR flock (2)
to provide exclusive access to the lock file and to prevent multiple
deamons from becoming active simultaneously.  If the daemon should be killed
or die unexpectedly, the lock file need not be removed.
The lock file is kept in a readable ASCII form
and contains two lines.
The first is the process id of the daemon and the second is the control
file name of the current job being printed.  The second line is updated to
reflect the current status of
X.I lpd
for the programs
X.IR lpq (1)
and
X.IR lprm (1).
X.SH FILES
X.nf
X.ta \w'/etc/printcap           'u
X/etc/printcap	printer description file
X/usr/spool/*	spool directories
X/dev/lp*	line printer devices
X/dev/printer	socket for local requests
X/etc/hosts.equiv	lists machine names allowed printer access
X/etc/printer_perms	permissions
X.fi
X.SH "SEE ALSO"
lpc(8),
pac(1),
lpr(1),
lpq(1),
lprm(1),
printcap(5)
X.br
X.I "PLP - The Public Line Printer Spooler",
by
Patrick Powell,
University of Minnesota.
X.fi
X.SH "HISTORY"
X.PP
The PLP is a reverse engineered version of the Berkeley 4.3BSD Line Printer
Spooler.
It has many advanced features which are described in
X.I "PLP - The Public Line Printer Spooler"
by
Patrick Powell,
University of Minnesota.
END_OF_FILE
if test 6781 -ne `wc -c <'man/lpd.8'`; then
    echo shar: \"'man/lpd.8'\" unpacked with wrong size!
fi
# end of 'man/lpd.8'
fi
if test -f 'man/lpr.1' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'man/lpr.1'\"
else
echo shar: Extracting \"'man/lpr.1'\" \(7221 characters\)
sed "s/^X//" >'man/lpr.1' <<'END_OF_FILE'
X.TH LPR 1 "19 Mar 1988" "U-MN PLP"
X.ig
X$Header: lpr.1,v 2.2 88/05/19 07:43:00 papowell Locked $
X$Log:	lpr.1,v $
Revision 2.2  88/05/19  07:43:00  papowell
XFixed up the -H, -h descriptions
X
Revision 2.1  88/05/09  10:08:40  papowell
PLP: Released Version
X
Revision 1.2  88/05/09  10:01:51  papowell
added -h option
X
Revision 1.1  88/04/28  10:58:53  papowell
Initial revision
X
X..
X.SH NAME
lpr \- off line print
X.SH SYNOPSIS
X.B lpr
X[
X.BI \-P printer
X] [
X.BI \-# num
X] [
X.B \-C
X.I class
X] [
X.B \-J
X.I job
X] [
X.BI \-R remoteAccount
X] [
X.BI \-m \fR[\fImailTo\fR]\fI
X] [
X.B \-T
X.I title
X]
X[\fB\-i\fP[\fInumcols\fP]]
X[
X.BI \-w num
X] [
X.BI \-Z zoptions
X] [
X.BI \-U user
X] [
X.BI \-F filter
X] [
X.B \-bhrs
X] [
X.BI \-D n
X] [
X.B \-X
X] [
filename ...
X]
X.SH DESCRIPTION
X.B Lpr
uses a spooling daemon to print the named files when facilities
become available.  If no names appear, the standard input is assumed.
X.IP "\fB\-P\fIprinter\fR" 5
Output to the specific printer;
the default is to use
the value of the
environment variable PRINTER and
and then the default (site dependent) printer.
X.IP "\fB\-F\fIf\fR" 5
XFilter or format specification.
By default,
input is assumed to a standard text file and the
X.I f
format is used;
the output device is assmed to be a simple line printer.
Therer are other formats available,
listed below.
Not all formats may be available on all printers;
see
X.IR printcap (5)
for details.
XFormats are single lower case letters;
the following are the valid arguments for
X.B \-F
together with the assumed type of data.
XFor compatibility with previous versions of
X.BR lpr ,
the format types can be used as options themselves
X(i.e. by omitting the
X.BR F )
except where noted below,
a warning may be issued in such cases.
X.IP \fBp\fP 5
text to be printed using
X.IR pr (1)
to format the files.
The output is then formatted using the
X.I f
format.
X.IP \fBl\fP 5
text with control characters to be printed,
and page breaks suppressed.
X.IP \fBt\fP 5
output from
X.IR troff (1)
X(originally cat phototypesetter commands,
but now we assume the same as the
X.B n
format).
X.IP \fBn\fP 5
output from (device independent)
X.IR troff .
X.IP \fBd\fP 5
output from
X.IR tex (l)
X(DVI format from Stanford).
X.IP \fBg\fP 5
standard plot data as produced by the
X.IR plot (3X)
routines (see also
X.IR plot (1G)
for the filters used by the printer spooler).
X.IP \fBv\fP 5
a raster image for devices like the Benson Varian.
X.IP \fBc\fP 5
data produced by
X.IR cifplot (l).
X.IP \fBr\fP 5
text in which the first character of each line is interpreted as a
standard FORTRAN carriage control character.
The effect of this format used to be obtained with the
X.B \-f
option.
X.PP
The remaining single letter options have the following meaning.
X.IP \fB\-m\fP[\fImailTo\fP] 5
Send mail upon completion to user
X.I mailTo
X(default is to the submitter).
If the \-m flag is followed by another flag or a single \-,
the default submitter name will be used.
X.IP \fB\-h\fP 5
Request no banner or header for this job.
X.IP \fB\-s\fP 5
Use symbolic links.
Usually files are copied to the spool directory.
This flag will cause a symbolic link to be made to the file,
and the file should not be modified or removed until it has been printed.
Primarily useful for printing very large files,
and its use is restricted due to security loopholes.
X.IP \fB\-r\fP 5
Remove the file after printing it.
This option is also restricted due to security loopholes.
X.IP \fB\-J\fP\ \fIjobname\fP 5
Specify the job name to print on the burst page;
defaults to the name of the first file.
X.IP \fB\-T\fP\ \fItitle\fP 5
Specify the title used by
X.IR pr (1);
defaults to the file name.
X.IP \fB\-w\fP\fIwidth\fP 5
Specify the page width for
X.IR pr .
X.IP \fB\-C\fP\ \fIclass\fP 5
Specify the job classification for use on the burst page and to
set the priority.
Priorities range from A (highest) to Z (lowest);
the default priority is Z.
XFor example,
X.br
X.ti +0.5i
lpr \-C A foo.c
X.br
sets the priority to A and the file foo.c to be printed.
X.IP \fB\-R\fP\ \fIremoteAccount\fP 5
Specify accounting information to be used by a remote system that prints
your output.
X.sp
XFor some printers,
such as the Imagen,
it can be used to specify a real money billing code to be charged for the
printing.  This is only needed if the user has more than one
real money billing code.
X.IP \fB\-#\fP\fInum\fP 5
Specify the number of copies of each file to be printed.
Note that this option is NOT SUPPORTED on all printers,
and its use is strongly discouraged.
X.IP \fB\-i\fP[\fInumcols\fP] 5 
Cause the output to be indented;
X\fInumcols\fP defaults to 8 blanks.
Note that this option is NOT SUPPORTED on all printers,
and thus its use is discouraged.
X.IP \fB\-b\fP 5
The files are assumed to contain binary data. This option allows the
X.I lpr-spooler
to be used for file transfers.
X.IP "\fB\-Z\fP\ \fIextra\ options\fP" 5
This option is used to pass extra options to the input filter for the printer
in question and is mainly used when spooling to non-Unix printers or when
using the spooler to to do file transfers to non-Unix machines.
X.IP "\fB\-D\fR[\fIn\fR]"
XEnables display of debugging information.
The 
X.B \-D
selects level 1;
X.B \-D\fIn\fR
X\fRselects level
X.I n
X(n is a single digit).
X.IP "\fB\-X"
Use an Xperimental version of LPD if the software has been compiled
with the appropriate support;
ignored otherwise.
X.PP
The
X.B \-U
option is used to specify a user name
for the purpose of accounting and banners.
X.PP
The old LPR options
X.B \-1234
are obsolete;
they were used to specify a font to be mounted on font position \fIi\fR.
The 
X.B \-r
X(delete files on job completion)
and
X.B \-s
options are restricted to users who are in a group specified by the
X.B ln
X(allowed to use links) printcap entry for the printer.
X.SH FILES
X.nf
X.ta \w'/usr/spool/*/cf*       'u
X/etc/passwd	personal identification
X/etc/printcap	printer capabilities data base
X/etc/printer_perms	printer permissions
X/usr/lib/lpd*	line printer daemons
X/usr/spool/*	directories used for spooling
X/usr/spool/*/cf*	daemon control files
X/usr/spool/*/df*	data files specified in "cf" files
X/usr/spool/*/tf*	temporary copies of "cf" files
X.fi
X.SH DIAGNOSTICS
The diagnostics from
X.I lpr
are extremely verbose.
If you try to spool too large a file
or too many files,
the job will be rejected.
If this is the case,
use
X.I cat
to append the files and then pipe them to LPR.
X.I Lpr
will object to printing binary files,
as determined by a crude sanity and a.out header check.
If a connection to the
X.I lpd
daemon socket /dev/printer cannot be made,
X.I lpr
will say that the server cannot be started.
X.PP
XEntries in the printcap will determine the exact actions taken by
X.I lpr
in spooling files;
see the
X.IR printcap (5)
man pages for details.
X.IR lpd .
X.SH "SEE ALSO"
lpq(1),
lprm(1),
pr(1),
printcap(5),
lpc(8),
lpd(8),
X.br
X.I "PLP - The Public Line Printer Spooler",
by
Patrick Powell,
University of Minnesota.
X.fi
X.SH "HISTORY"
X.PP
The PLP is a reverse engineered version of the Berkeley 4.3BSD Line Printer
Spooler,
done in 1988 at the University of Minnesota.
It has many advanced features which are described in
X.I "PLP - The Public Line Printer Spooler"
by
Patrick Powell,
Department of Computer Science,
University of Minnesota.
END_OF_FILE
if test 7221 -ne `wc -c <'man/lpr.1'`; then
    echo shar: \"'man/lpr.1'\" unpacked with wrong size!
fi
# end of 'man/lpr.1'
fi
if test -f 'src/mexecv.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'src/mexecv.c'\"
else
echo shar: Extracting \"'src/mexecv.c'\" \(6769 characters\)
sed "s/^X//" >'src/mexecv.c' <<'END_OF_FILE'
X/***************************************************************************
X * U. Minnesota LPD Software * Copyright 1987, 1988, Patrick Powell
X ***************************************************************************
X * MODULE: mexecv.c
X * ExecrV a la 4 BSD for brain damaged System V
X ***************************************************************************
X * Revision History: Created Sat Jan  9 15:23:23 CST 1988
X * $Log:	mexecv.c,v $
X * Revision 3.1  88/06/18  09:35:11  papowell
X * Version 3.0- Distributed Sat Jun 18 1988
X * 
X * Revision 2.1  88/05/09  10:09:36  papowell
X * PLP: Released Version
X * 
X * Revision 1.6  88/04/28  11:02:48  papowell
X * removed unused variables,  shuts up lint
X * 
X * Revision 1.5  88/04/27  20:24:08  papowell
X * Modified the SYSV Braindamaged mode to invoke shells better.
X * The invocation is rather odd, but appears to work.
X * 
X * Revision 1.4  88/03/25  15:00:52  papowell
X * Debugged Version:
X * 1. Added the PLP control file first transfer
X * 2. Checks for MX during file transfers
X * 3. Found and fixed a mysterious bug involving the SYSLOG facilities;
X * 	apparently they open files and then assume that they will stay
X * 	open.
X * 4. Made sure that stdin, stdout, stderr was available at all times.
X * 
X * Revision 1.3  88/03/11  19:29:44  papowell
X * Minor Changes, Updates
X * 
X * Revision 1.2  88/03/05  15:00:56  papowell
X * Minor Corrections,  Lint Problems
X * 
X * Revision 1.1  88/03/01  11:08:56  papowell
X * Initial revision
X * 
X ***************************************************************************/
X#ifndef lint
static char id_str1[] =
X	"$Header: mexecv.c,v 3.1 88/06/18 09:35:11 papowell Exp $ PLP Copyright 1988 Patrick Powell";
X#endif lint
X
X/***************************************************************************
X * ExecrV a la 4 BSD for brain damaged System V
X * Sun Dec  6 20:04:57 CST 1987 Patrick Powell
X * This is a massive hack, based on all sorts of checks and balances.
X *
X * 1. First, we try blinding using exev()
X * 2. Next, we check the perms; if not executable, tough.
X * 3. Next we try to read the file;  if not readable, tough.
X * 4. We read the first character of the file.
X * 5. If it is not #, use Bourne shell;
X * 6. We check for the #!; if not, we use CSH
X * 7. We get the pathname of the file, and args, and use that.
X */
X#include "lp.h"
X
mexecv( command)
X	char *command;
X{
X	int i;		/* ACME Integer, Inc. */
X	struct stat statb;
X	FILE *fp;
X	char buf[BUFSIZ];
X	char cmd[BUFSIZ];
X	char *cp;
X	char *args[100];
X	char **argv = args+2;
X	char *option = 0;
X	char *fname;
X	char *path;
X
X	/*
X	 * close all the file descriptors
X	 */
X	for( i = 3; i < NOFILE; ++i){
X		(void)close(i);
X	}
X	/*
X	 * split command line up
X	 */
X	(void)strcpy(cmd,command);
X	if( getwords(cmd, argv, 98) == 0 ){
X		log(XLOG_INFO,"mexecv: invalid argv passed, command %s",command);
X		return;
X	}
X	if(Debug>4){
X		char **s, b[BUFSIZ];
X		(void)sprintf(b,"mexecv: ");
X		for( s = argv; *s; ++s){
X			(void)sprintf(b+strlen(b),"'%s' ",*s);
X		}
X		log(XLOG_DEBUG,"%s",b);
X	}
X	execv( argv[0],argv );
X
X	if(Debug>4)logerr(XLOG_DEBUG,"mexecv: execv failed" );
X
X	/*
X	 * well, that didn't work, lets try the shell options
X	 */
X	fname = argv[0];
X	if( stat(fname, &statb) < 0 ){
X		logerr( XLOG_INFO,"mexecv: cannot stat %s", fname );
X		return;
X	}
X	if(Debug>4)log(XLOG_DEBUG,
X		"mexecv: %s, perms %o, st_uid %d, st_gid %d, uid %d, gid %d",
X		fname,statb.st_mode &0777, statb.st_uid, statb.st_gid,
X			getegid(), geteuid());
X	if(! (statb.st_mode & 0001)
X		&& !((statb.st_mode & 0010) && statb.st_gid == getegid())
X		&& !((statb.st_mode & 0100) && statb.st_uid == geteuid())){
X		log( XLOG_INFO,"mexecv: %s has no valid execute perms",fname);
X		return;
X	}
X	fp = fopen( fname, "r" );
X	if( fp == NULL ){
X		logerr(XLOG_INFO,"mexecv: cannot open %s for reading and failed execv",
X			fname);
X		return;
X	}
X	if( fgets( buf, sizeof(buf), fp ) == NULL
X		|| (cp = index(buf, '\n')) == NULL ){
X		/* empty file , bad format */
X		log( XLOG_INFO,"mexecv: bad format %s", fname );
X		return;
X	}
X	(void)fclose(fp);
X	*cp = 0;
X	if( buf[0] != '#' ){
X		path = "/bin/sh";
X	} else {
X		/* check for the #! magic number */
X		if( buf[1] != '!' ){
X			/* use csh, be paranoid, and sure */
X			path = "/bin/csh";
X		} else {
X			/* we have an explicit path Name formed */
X			for( path = &buf[2]; *path && isspace(*path); ++path);
X			/* path points to the start of the command */
X			if( *path == 0 ){
X				log( XLOG_INFO,"mexecv: bad format %s", path );
X				return;
X			}
X			/* look for the end of the command */
X			for( cp = path; *cp && !isspace(*cp); ++cp );
X			if( *cp ){
X				/* we have options */
X				*cp = 0;
X				for( ++cp; *cp && isspace(*cp); ++cp);
X				option = cp;
X				++cp;
X				for( ++cp; *cp && !isspace(*cp); ++cp);
X				*cp = 0;
X			}
X		}
X	}
X	if( strcmp( path, "/bin/csh" ) == 0 ){
X		/* we are using csh */
X		if( option == 0 ){
X			option = "-f";
X		} else {
X			(void)strcat(option, "f");
X		}
X	} else if (strcmp( path, "/bin/sh") == 0 ){
X		/*
X		 * nothing
X		 */
X		;
X	} else {
X		fatal( XLOG_INFO,"mexecv: shell (%s) not /bin/csh or /bin/sh", path );
X	}
X	if( option ){
X		--argv;
X		argv[0] = option;
X	}
X	--argv;
X	argv[0] = fname;
X	if(Debug>4){
X		char **s, b[BUFSIZ];
X		(void)sprintf(b,"mexecv: path '%s'", path);
X		for( s = argv; *s; ++s){
X			(void)sprintf(b+strlen(b),"'%s' ",*s);
X		}
X		log(XLOG_DEBUG,"%s",b);
X	}
X	execv( path,argv );
X	logerr_die(XLOG_INFO,"mexecv: execv failed '%s'", path);
X}
X
X
X/*
X * getwords splits a string up into words, and returns a non-null
X * pointer if there are any.
X * Note that splitting is done on a crude basis of matched quotes only
X */
int
getwords(s, argv, maxargc)
X	char *s;	/* string containing isspace separated words */
X	char *argv[];
X	int maxargc;
X{
X	char **w;
X	char *tp = s;
X	int num_words = 0;
X
X	if (s==NULL || *s == 0 )
X		return(0);
X	while (*tp) {
X		while(*tp && isspace(*tp))
X			++tp;
X		if (*tp == 0) continue;
X		num_words++;
X		if( *tp == '\'' ){
X			if( (tp = index( tp+1, '\'')) == 0 ){
X				log(XLOG_INFO,"getwords: unmatched ' in string: %s", s );
X				return(0);
X			}
X			++tp;
X		} else if( *tp == '\"' ){
X			if( (tp = index( tp+1, '\"')) == 0 ){
X				log(XLOG_INFO,"getwords: unmatched ' in string: %s", s );
X				return(0);
X			}
X			++tp;
X		} else  {
X			while ((*tp) && !isspace(*tp))
X			++tp;
X		}
X	}
X	if (num_words==0)
X		return(0);
X	if( num_words > maxargc ){
X		log(XLOG_INFO,"getwords: more than %d arguments" );
X		return(0);
X	}
X	w = argv;
X	while(*s) {
X		while(*s && isspace(*s))
X			++s;
X		if (*s == 0) {
X			*w = NULL;
X			return(1);
X		}
X		if( *s == '\'' ){
X			*w++ = s+1;
X			s = index( s+1, '\'');
X			*s++ = 0;
X		} else if( *s == '\"' ){
X			*w++ = s+1;
X			s = index( s+1, '\"');
X			*s++ = 0;
X		} else  {
X			*w++ = s;
X			while ((*s) && !isspace(*s))
X				++s;
X			if( *s ) *s++ = '\0';
X		}
X	}
X	*w = NULL;
X	return(1);
X}
END_OF_FILE
if test 6769 -ne `wc -c <'src/mexecv.c'`; then
    echo shar: \"'src/mexecv.c'\" unpacked with wrong size!
fi
# end of 'src/mexecv.c'
fi
if test -f 'src/rmjob.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'src/rmjob.c'\"
else
echo shar: Extracting \"'src/rmjob.c'\" \(7416 characters\)
sed "s/^X//" >'src/rmjob.c' <<'END_OF_FILE'
X/***************************************************************************
X * U. Minnesota LPD Software * Copyright 1987, 1988, Patrick Powell
X ***************************************************************************
X * MODULE: rmjob.c
X * Remove jobs from a printer queue
X ***************************************************************************
X * Revision History: Created Sat Jan  9 20:08:26 CST 1988
X * $Log:	rmjob.c,v $
X * Revision 3.1  88/06/18  09:35:34  papowell
X * Version 3.0- Distributed Sat Jun 18 1988
X * 
X * Revision 2.2  88/05/14  10:21:11  papowell
X * Modified -X flag handling
X * 
X * Revision 2.1  88/05/09  10:10:09  papowell
X * PLP: Released Version
X * 
X * Revision 1.4  88/03/25  15:01:32  papowell
X * Debugged Version:
X * 1. Added the PLP control file first transfer
X * 2. Checks for MX during file transfers
X * 3. Found and fixed a mysterious bug involving the SYSLOG facilities;
X * 	apparently they open files and then assume that they will stay
X * 	open.
X * 4. Made sure that stdin, stdout, stderr was available at all times.
X * 
X * Revision 1.3  88/03/11  19:29:16  papowell
X * Minor Changes, Updates
X * 
X * Revision 1.2  88/03/05  15:01:42  papowell
X * Minor Corrections,  Lint Problems
X * 
X * Revision 1.1  88/03/01  11:09:11  papowell
X * Initial revision
X * 
X ***************************************************************************/
X#ifndef lint
static char id_str1[] =
X	"$Header: rmjob.c,v 3.1 88/06/18 09:35:34 papowell Exp $ PLP Copyright 1988 Patrick Powell";
X#endif lint
X
X#include "lp.h"
X
X/***************************************************************************
X * rmjob()
X *  1. get the printcap entries
X *  2. get the queue entries
X *  3. get the active server files and see if they are in queue
X *  4. scan the queue, checking each job for removal
X *
X *  user   local  job   from  remove_all    perms inlist    remove?
X *  ===============================================================
X *  root   yes    *     *     yes           *     *         yes
X *  root   yes    *     *     no            *     yes       yes
X *  root   no     *     mach  yes           *     *         yes
X *  root   no     *     mach  no            *     yes       yes
X *  user   -      user  mach  -             R     yes       yes
X *  user   -      *     *     -             C     yes       yes
X *
X *  5. remove the job;  this may necessitate stopping or killing a deamon
X ***************************************************************************/
static int remove_all;	/* remove all jobs */
static int control_perms;	/* has C perms */
X
rmjob()
X{
X	int i;				/* ACME Integers, Inc. */
X	struct queue *q;	/* job entry */
X	int perms;			/* hold perms values */
X
X	/*
X	 * get the printcap entry
X	 */
X	if(Get_pc_entry(Printer, Status_pc_vars, Status_pc_len) == 0){
X		(void)fprintf(stdout, "Printer %s does not exist\n", Printer );
X		(void)fflush(stdout);
X		return;
X	}
X	if( SD == 0 || *SD == 0 ){
X		if(Debug>2)log(XLOG_DEBUG,"not a Printer");
X		return;
X	}
X	/* chdir to spool directory */
X	if (chdir(SD) < 0) {
X		logerr_die( XLOG_NOTICE,"cannot chdir to %s", SD);
X	}
X	/*
X	 * set the flags needed
X	 */
X	Is_local = strcmp( From, Host ) == 0;
X	Is_root  = strcmp( Person, "root" );
X	remove_all = (Parmcount > 0 && (strcmp( Parms[0].str, "-all" ) == 0));
X	/*
X	 * check to see that the user has RMJOB privs on this machine
X	 */
X	perms = 'R';	/* must be able to at least use the Printer */
X	if( !Is_root && (
X		(Permfile && *Permfile
X			&& !Checkperm( Permfile,From,Person,First_name,&perms,(int *)0,0 ))
X		|| (XU && *XU
X			&& !Checkperm( XU,From,Person,First_name,&perms,(int *)0,0 )))) {
X		(void)fprintf(stdout, "No remove permission on %s", First_name);
X		return;
X	}
X	perms = 'C';	/* check for control perms */
X	control_perms = 0;
X	if( !Is_root && (
X		(Permfile && *Permfile
X			&& Checkperm( Permfile,From,Person,First_name,&perms,(int *)0,0 ))
X		|| (XU && *XU
X			&& Checkperm( XU,From,Person,First_name,&perms,(int *)0,0 )))) {
X		control_perms = 1;
X	}
X	if(Debug>4)log(XLOG_DEBUG,
X		"rmjob: Is_root %d, Is_local %d, remove_all %d, control_perms %d",
X		Is_root, Is_local, remove_all, control_perms );
X	/*
X	 * check for remote machine and networked file system
X	 */
X	if( RM && NW ){
X		Remote_remove();
X		return;
X	}
X	/*
X	 * get the job queue
X	 */
X	Jobcount = Getq();
X	(void)Checkactive();
X	/*
X	 * run down list
X	 */
X	(void)fprintf(stdout,"Printer '%s' (%s):\n", Printer, Host );
X	(void)fflush(stdout);
X	for( i = 0; i < Jobcount; ++i ){
X		q = &Queue[i];
X		if( shouldremove( q ) ){
X			(void)fprintf(stdout,"removing %s, job %d owner %s\n",
X				q->q_name, q->q_num, q->q_user);
X			(void)fflush(stdout);
X			doremove(q);
X		}
X	}
X	/*
X	 * check for remote machine
X	 */
X	if( RM ){
X		Remote_remove();
X	}
X	/*
X	 * give the server a kick
X	 */
X	(void)Startserver();
X}
X
X/***********************************************************************
X * shouldremove( q )
X *  a simple application of the removal decision table
X *
X *  user   local  job   from  remove_all    perms inlist    remove?
X *  ===============================================================
X *  root   yes    *     *     yes           *     *         yes
X *  root   yes    *     *     no            *     yes       yes
X *  root   no     *     mach  yes           *     *         yes
X *  root   no     *     mach  no            *     yes       yes
X *  user   -      user  mach  -             R     yes       yes
X *  user   -      *     *     -             C     yes       yes
X *
X * Returns: 1 if removal is indicated, 0 otherwise
X ***********************************************************************/
int
shouldremove( q )
X	struct queue *q;
X{
X	int i, same_host;
X
X	same_host = (strcmp( From, &q->q_from ) == 0);
X	i = Match_entry(q);
X	if( Is_root && Is_local && remove_all ) return(1);
X	if( Is_root && Is_local && !remove_all && i ) return(1);
X	if( Is_root && !Is_local && same_host && remove_all ) return(1);
X	if( Is_root && !Is_local && same_host && !remove_all && i ) return(1);
X	if( strcmp( Person, q->q_user) == 0 && same_host && i ) return(1);
X	if( i && control_perms ) return(1);
X	return( 0 );
X}
X
X/***************************************************************************
X * doremove(struct queue *q)
X * remove the job
X * 1. Lock the control file.
X * 2. If unsuccessful, find the server PID and kill it off.
X * 3. Use brute force and remove the files.
X ***************************************************************************/
X
doremove( q )
X	struct queue *q;
X{
X	FILE *cfp;
X
X	if( (cfp = Lockcf( q->q_name )) == NULL ){
X		/* hmmm... looks like an active server */
X		if( (cfp = fopen_daemon( q->q_name, "r" )) == NULL ){
X			/* nope, the file has really gone */
X			logerr(XLOG_INFO,"control file %s not readable", q->q_name );
X			return;
X		}
X		/* well, we will just have to kill of the server */
X		if( q->q_daemon == 0){
X			/*
X			 * Hmmm... we have this fellow running the file, and it is
X			 * locked.  That means that it just started running this
X			 * guy. Better check again.
X			 */
X			(void)Checkactive();
X		}
X		if( q->q_daemon ){
X			(void)fprintf( stdout, "killing off %s server %d",
X				q->q_server,q->q_daemon );
X			if( killpg( q->q_daemon, SIGINT) < 0 ){
X				if(Debug>2)log(XLOG_DEBUG,
X						"server %s (%d) was not alive",
X							q->q_server,q->q_daemon );
X			}
X		}
X	}
X	/* use brute force;  we simply remove files */
X	if(Debug>3)log(XLOG_DEBUG,"removing files for job %s",q->q_name);
X	Remove_job( cfp, q );
X	(void)fclose( cfp );
X}
END_OF_FILE
if test 7416 -ne `wc -c <'src/rmjob.c'`; then
    echo shar: \"'src/rmjob.c'\" unpacked with wrong size!
fi
# end of 'src/rmjob.c'
fi
echo shar: End of archive 5 \(of 16\).
cp /dev/null ark5isdone
MISSING=""
for I in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 ; do
    if test ! -f ark${I}isdone ; then
	MISSING="${MISSING} ${I}"
    fi
done
if test "${MISSING}" = "" ; then
    echo You have unpacked all 16 archives.
    rm -f ark[1-9]isdone ark[1-9][0-9]isdone
else
    echo You still need to unpack the following archives:
    echo "        " ${MISSING}
fi
##  End of shell archive.
exit 0

-- 
Please send comp.sources.unix-related mail to rsalz at uunet.uu.net.



More information about the Comp.sources.unix mailing list