v16i017: Public lineprinter spooler package, Part04/16

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


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

#! /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 4 (of 16)."
# Contents:  doc/PLP/01.t filters/pref_main.c man/lpc.1 man/printcap.5
#   src/getopt.c src/lpr_canprint.c src/lpr_temp.c src/servicereq.c
# Wrapped by papowell at attila on Wed Aug 10 10:44:51 1988
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f 'doc/PLP/01.t' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'doc/PLP/01.t'\"
else
echo shar: Extracting \"'doc/PLP/01.t'\" \(5586 characters\)
sed "s/^X//" >'doc/PLP/01.t' <<'END_OF_FILE'
X.ig
X$Header: 01.t,v 1.1 88/05/21 18:39:31 papowell Locked $
X$log$
X..
X.NH 1
Overview
X.PP
The Public Line Printer Spooler (PLP) software is a
reverse engineered version of the Berkeley Line Printer Spooler (LPD).
During the implementation,
there was no resort to any of the Berkeley LPD source,
other than for tables that are used to print big letter banners\**.
X.FS
The author has seen these appear in several public domain games programs,
and has recollections of running card decks which produced
suspiciously similar output.
X.FE
Due to experience with the Berkeley software,
some LPD routines and functionality may be duplicated,
but in general the implementation and structure of the PLP software is
radically different.
X.PP
The Public Line Printer Spooler supports:
X.IP 1). 3
Multiple printers,
one or more per spooling queue.
X.IP 2). 3
Multiple prioritized spooling queues.
X.IP 3). 3
Both local and remote printers.
X.IP 4). 3
Printers attached via serial lines,
which can have line characteristics such as baud rate,
parity,
etc., specified.
X.IP 5). 3
Devices such as an Imagen laser printer which may
require a special communications protocol for printing.
X.IP 6). 3
Operation in a shared file system environment (such as NFS).
X.IP 7). 3
Restriction of use by a printer permissions data base.
In addition to a per-host database,
each individual spool queue may have a supplementary database.
X.PP
The major components of line printer system are the
following files and commands in Table 1.1.
X.TS
center box;
l | l | l.
Name	Type	Purpose
X_
X/??/printcap.<host>	file	printer configuration and capability data base
X/??/printer_perms.<host>	file	printer permissions data base
X/??/log.<host>	file	daemon log file
X/??/lock.<host>	file	daemon lock
X/usr/lib/lpd	daemon	line printer daemon
X/usr/local/bin/lpr	command	enter a job in a printer queue
X/usr/local/bin/lpq	command	examine queues
X/usr/local/bin/lprm	command	delete jobs from a queue
X/usr/local/bin/lpc	command	administer printers and spooling queues
printer,tcp	port	inet service port on which lpd listens
X.TE
X.ce
Table 1.1 Major PLP Components
X.PP
The
X.L /??/printcap.<host>
file
is a master data base describing
characteristics of line printers either directly attached to the host
or accessible across a network.
In the Berkeley LPD software,
the printcap file was
X.L /etc/printcap .
While this convention is easy to use in a single host or loosely
coupled multiple processor environment,
it has proven to be difficult to manage and apply in a networked based
file system such as NFS.
In order to provide an easier management of the PLP software,
the
X.L printcap ,
X.L printer_perms ,
X.L log ,
and
X.L lock
files have the form:
X.L /usr/spool/lpd/<file>.<host> ,
where
X.L <host>
is the network level form of the host name.
Note that this allows a single  spool directory to be made available to
all the systems using an NFS file system.
Note that all files in the spool directory are created using the
X.L daemon
user ID and group ID,
avoiding problems with NFS systems and root userids.
X.PP
The format of the printcap database is based on the
X.IR termcap (5)
format.
X.PP
The
X.L printer_perms
or printer permissions file is used by PLP software to
determine what operations,
queues,
and services can be accesssed by users.
It also determines the spool queues accessible by users from remote hosts,
as well as determining.
The printer permissions file is similar in purpose to the
X.I host.equiv
file that is used by
X.I rshd .
X.PP
The
X.L lpd
program is a
X.I daemon
or server program that carries out actions as requested by other programs.
The
X.L lpr
program creates print jobs in the appropriate spool queue,
and then requests the
X.L lpd
daemon to perform unspooling actions.
The
X.L lpq
program is used to print the status of local and remote spool queues.
The
X.L lprm
program is used to remove jobs from spool queues,
and the
X.L lpc
program is used to control spooling and unspooling activities.
X.PP
Communication between the
X.L lpd
daemon and the utility programs is done using the Internet TCP/IP
communications support provided by most UNIX systems.
XEach host has an
X.L lpd
daemon which listens on a well known port of the host,
and carries out requested activities.
X.PP
The remainder of this document provides details of the structure and
implementation of the above facilities and programs.
Section 2 describes the functionality of the
X.L lpd
daemon and  the 
X.L "lpr" ,
X.L "lpq" ,
X.L "lprm" ,
and
X.L "lpc"
programs.
Section 3 describes the structure of the spool directory associated
with each spool queue,
and the security precautions taken to ensure the integrity of the
the spool directory and print jobs.
Section 4 is a description of the
X.I printcap
data base,
and how the information in the database
is used by the PLP software to perform spooling operations.
Section 5 is a description of the inter-host file transfer protocol used
by PLP.
Section 6 is a description of the unspooling operations carried out by the
X.I lpd
program,
and how they are controlled by the printcap information.
Section 7 details how filter programs are invoked by the spool server
processes and how they are specified in the printcap.
Section 8 describes how PLP can be used in a networked file system
environment.
Section 9 outlines how the
X.I lpc
program is used to control spooling operations.
Section 10 is a discussion of some diagnositic information supplied by
the PLP programs.
Section 11 is an outline of the installation and test procedures for
PLP.
Section 12 is a summary of differences between the Berkeley LPR
software and PLP.
END_OF_FILE
if test 5586 -ne `wc -c <'doc/PLP/01.t'`; then
    echo shar: \"'doc/PLP/01.t'\" unpacked with wrong size!
fi
# end of 'doc/PLP/01.t'
fi
if test -f 'filters/pref_main.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'filters/pref_main.c'\"
else
echo shar: Extracting \"'filters/pref_main.c'\" \(5906 characters\)
sed "s/^X//" >'filters/pref_main.c' <<'END_OF_FILE'
X#ifndef	lint
X/*
X * Updated LPR software;
X * Original Version (Copyright) 1983 Regents of the Univeristy of California
X * This is a derivative work,
X * and the original copyright is still valid.  Covered by the
X * 4BSD Licensing Agreement;  this is NOT public domain software.
X * Mon Nov 23 09:23:23 CST 1987 Patrick Powell, U. Minnesota
X */
X#ifndef __INDENT_INCL
static char id_str1[] =
X	"Revised LPR, Patrick Powell, U. Waterloo, April 10, 1984";
static char id_str2[] =
X	"Re-revised LPR, Patrick Powell, U. Minnesota, 23 Nov 1987";
X#define __INDENT_INCL 1
X#endif __INDENT_INCL
X#endif lint
X/*
X * Prefilter main and setup.
X *	A prefilter is invoked with the following parameters:
X *
X *
X * filter -wwidth -llength -xwidth -ylength [-c]  [-iindent]
X *		-Zoptions -Cclass -Jjob -nlogin -hhost -Fx [files]
X * 
X *	if the [files] are missing, input is from stdin
X *
X *	The following variables are set up
X *
X * name		- name of filter			PRINTCAP ENTRY
X * width	- default 132				pl
X * length	- default 66				pw
X * xwidth	- default 0				px
X * ylength	- default 0				py
X * literal	- default 0 [-c flag]
X * indent	- default 0
X * zopts	- NULL	[lpr]
X * class	- NULL [lpr]
X * job		- NULL [lpr]
X * login	- NULL [lpr]
X * host		- NULL [lpr]
X * format	- set from -F
X * last		- set for last file
X * file		- current file (NULL if stdin)
X *
X *	The list of files is opened, and the file descriptor is set to 0
X *	with a dup2.  The "last" flag is set when the last file is opened.
X *	The name of the current file is available in "file".
X *	Then the "prefilter" function is called.
X *	The program exits with a 0 (successful), 1 (unsuccessful, retry)
X *	and anything else indicates unsuccessful, no retry.
X *	The prefilter() function should return a similar status.
X *	The functions fatal(), logerr(), and logerr_die() can be used to report
X *	status. The variable errorcode can be set by the user before calling
X *	these functions, and will be the exit value of the program. Its default
X *	value will be 2.
X *	The fatal function reports a fatal message, and terminates
X *	logerr() will report a message, append information indicated by errno
X *	(see perror(2) for details), and then returns.
X *	logerr_die() will call logerr(), and then will exit with errorcode
X *	status.
X *	In case of an error, the "cleanup()" function will be called.
X *	This can be used to do any error functions.
X *
X */
X
X#include <stdio.h>
X#include <sys/file.h>
X
int errorcode = 2;
X
char *name;		/* name of filter */
int width = 132;	/* default 132	*/
int length;	/* default 66	*/
int xwidth;	/* default 0	*/
int ylength;	/* default 0	*/
int literal;	/* default 0 [-c flag]*/
int indent;	/* default 0 */
char *zopts;	/* NULL	[lpr]*/
char *class;	/* NULL [lpr]*/
char *job;	/* NULL [lpr]*/
char *login;	/* NULL [lpr]*/
char *host;	/* NULL [lpr]*/
int format;	/* set from -F*/
int last;	/* set for last file*/
char *file;	/* current file (NULL if stdin)*/
X
main( argc, argv )
X	int argc;
X	char **argv;
X    {
X	char * arg;
X	int i;
X
X	name = argv[0];
X	++argv;
X
X	/*
X	 * process the flagged arguments
X	 */
X	while( --argc > 0 ){
X		if( **argv != '-' )
X			break;
X		arg = 1 + *argv++;	/* arg ^s to the option letter */
X		switch( *arg++ ){	/* arg now ^s to the option value */
X		case 'w':
X			if( (i = atoi(arg))< 0 ){
X			fatal("argument for %c out of range",arg[-1]);
X			} else if( i > 0 ){
X				width = i;
X			}
X			break;
X		case 'l':
X			if( (i = atoi(arg))< 0 ){
X			fatal("argument for %c out of range",arg[-1]);
X			} else if( i > 0 ){
X				length = i;
X			}
X			break;
X		case 'x':
X			if( (i = atoi(arg))< 0 ){
X			fatal("argument for %c out of range",arg[-1]);
X			} else if( i > 0 ){
X				xwidth = i;
X			}
X			break;
X		case 'y':
X			if( (i = atoi(arg))< 0 ){
X			fatal("argument for %c out of range",arg[-1]);
X			} else if( i > 0 ){
X				ylength = i;
X			}
X			break;
X		case 'c':
X			literal = 1;
X			break;
X		case 'i':
X			if( (i = atoi(arg))< 0 ){
X			fatal("argument for %c out of range",arg[-1]);
X			} else if( i > 0 ){
X				indent = i;
X			}
X			break;
X		case 'Z':
X			zopts = arg;
X			break;
X		case 'C':
X			class = arg;
X			break;
X		case 'J':
X			job = arg;
X			break;
X		case 'n':
X			login = arg;
X			break;
X		case 'h':
X			host = arg;
X			break;
X		case 'F':
X			format = *arg;
X			break;
X		}
X	}
X	/*
X	 * now assume the rest of the arguments are filenames
X	 */
X	dofiles( argc, argv );
X    }
X
X
X/*
X * Now do the files.  Open each as fd 0 (stdin), and read each one.
X */
dofiles( argc, argv )
X	int argc;	/* # of items in 'argv' */
X	char **argv;
X    {
X	int fd;
X
X	if( argc > 0 ){
X		while( --argc >= 0 ){
X			file = *argv++;
X			if( argc == 0 ){
X				last = 1;
X			}
X			if( (fd = open(file,O_RDONLY,0)) < 0 ) {
X				logerr_die( "cannot open %s ", file );
X			}
X			if( fd != 0 ){
X				if(dup2( fd, 0 ) < 0){
X				errorcode = 1;
X				logerr_die( "dup2 failed" );
X				}
X				(void)close( fd );
X			}
X			prefilter();
X			(void)clearerr( stdin );
X			(void)close(0);
X		    }
X	} else {
X		last = 1;
X		prefilter();
X	}
X	exit(0);
X    }
X
X/*VARARGS1*/
log(msg, a1, a2, a3)
X	char *msg;
X{
X	(void)fprintf(stderr, "%s: ", name);
X	(void)fprintf(stderr, msg, a1, a2, a3);
X	(void)putc('\n', stderr);
X	(void)fflush(stderr);
X}
X
X
X/*VARARGS1*/
fatal(msg, a1, a2, a3)
X	char *msg;
X{
X	log(msg, a1, a2, a3);
X	cleanup();
X	exit(errorcode);
X}
X
X
X/*VARARGS1*/
logerr(msg, a1, a2, a3)
X	char *msg;
X{
X	extern int errno, sys_nerr;
X	extern char *sys_errlist[];
X	register int err = errno;
X
X	(void)fprintf(stderr, "%s: ", name);
X	if (msg){
X		(void)fprintf(stderr, msg, a1, a2, a3);
X		(void)fputs( "- ", stderr);
X	}
X	(void)fputs(err<sys_nerr ?sys_errlist[err] :"Unknown error", stderr);
X	(void)putc('\n', stderr);
X	(void)fflush();
X}
X
X/*VARARGS1*/
logerr_die(msg, a1, a2, a3)
X	char *msg;
X{
X	logerr(msg, a1, a2, a3);
X	cleanup();
X	exit(errorcode);
X}
X
X#ifdef DEBUG
cleanup() {}
X
prefilter()
X    {
X	int c;
X
X	if( file ){
X		log( "file %s", file );
X	} else {
X		log( "file %s", "(stdin)" );
X	}
X	while( (c = getchar()) != EOF ){
X		putchar(c);
X	}
X    }
X#endif DEBUG
END_OF_FILE
if test 5906 -ne `wc -c <'filters/pref_main.c'`; then
    echo shar: \"'filters/pref_main.c'\" unpacked with wrong size!
fi
# end of 'filters/pref_main.c'
fi
if test -f 'man/lpc.1' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'man/lpc.1'\"
else
echo shar: Extracting \"'man/lpc.1'\" \(5371 characters\)
sed "s/^X//" >'man/lpc.1' <<'END_OF_FILE'
X.TH LPC 1 "19 Mar 1988" "U-MN PLP"
X.ig
X$Header: lpc.1,v 2.1 88/05/09 10:08:27 papowell Exp $
X$Log:	lpc.1,v $
Revision 2.1  88/05/09  10:08:27  papowell
PLP: Released Version
X
Revision 1.1  88/04/28  10:58:49  papowell
Initial revision
X
X..
X.SH NAME
lpc \- line printer control program
X.SH SYNOPSIS
X.B lpc
X[
X.BI \-D n
X] [
X.B \-X
X[ command [ argument ... ] ]
X.SH DESCRIPTION
X.I Lpc
is used by the system administrator to control the
operation of the line printer system.  
XFor each line printer configured in /etc/printcap,
X.I lpc
may be used to:
X.IP \(bu 3
disable or enable a printer,
X.IP \(bu 3
disable or enable a printer's spooling queue,
X.IP \(bu 3
rearrange the order of jobs in a spooling queue,
X.IP \(bu 3
find the status of printers, and their associated
spooling queues and printer dameons.
X.IP \(bu 3
start and stop printer servers for a queue with multiple print servers
X.IP \(bu 3
perform remote control of a spool queue
X.PP
Without any arguments,
X.I lpc
will prompt for commands from the standard input.
If arguments are supplied,
X.IR lpc
interprets the first argument as a command and the remaining
arguments as parameters to the command.
The standard input
may be redirected causing
X.I lpc
to read commands from file.
Permission to use spool queue control commands is determined by the
printer permissions file
X.I /etc/printer_perms.
Priviledged commands can only be used by users with
C or control permissions.
Commands may be abreviated;
the following is the list of recognized commands.
X.TP
X? [ command ... ]
X.TP
h[elp] [ command ... ]
X.br
Print a short description of each command specified in the argument list,
or, if no arguments are given, a list of the recognized commands.
X.TP
e[xit]
X.TP
q[uit]
X.br
XEx[it] from lpc.
X.TP
en[able] { all | printer ... }
X.br
XEnable spooling on the local queue for the listed printers. 
This will allow
X.I lpr
to put new jobs in the spool queue.
Priviledged.
X.TP
d[isable] { all | printer ... }
X.br
Disable spooling to the specified spool queues.
This will suppress spooling by
X.IR lpr .
Priviledged.
X.TP
star[t] { all | printer ... }
X.br
XEnable unspooling and start a server for the listed printers.
Priviledged.
X.TP
sto[p] { all | printer ... }
X.br
Disable any further unspooling.
Stop the unspooler after the current job completes.
Priviledged.
X.TP
a[bort] { all | printer ... }
X.br
Disable any further unspooling.
Kill the currently active unspooling server.
Note that the currently active job will not be deleted from the queue.
Priviledged.
X.TP
k[ill] { all | printer ... }
X.br
Do an abort followed by a start.
This is a quick way to kill off a server that has problems.
Priviledged.
X.TP
res[tart] { all | printer ... }
X.br
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.
X.I Lpq
will report that there is no daemon present when this condition occurs. 
X.TP
stat[us] [ terse ] [ all ] [ printer ... ]
Display the status of daemons and queues on the local machine.
If 'terse' is given, then any printers with printing and queueing both
enabled with no entries in the spool queue, will not be displayed.
X.TP
t[opq] printer [ jobnum ... ] [ user ... ]
X.br
Place the jobs in the order listed at the top of the printer queue.
It does this by boosting them to priority A,
and then reordering the priority A jobs.
Priviledged.
X.TP
rem[ote] lpc command
X.br
XExecute the lpc command on the remote host for the printer.
XFor example,
to restart all queues that have remote entries on the current host,
X.I "remote start all"
can be used;
to disable them
X.I "remote disable all"
can be used.
X.TP
lpq { lpq options }
X.br
Run
X.I lpq
from inside the 
X.I lpc
program.
X.TP
lprm { lprm options }
X.br
Run
X.I lprm
from inside the 
X.I lpc
program.
X.TP
lpd
X.br
determines the if the LPD daemon process is running,
and if the UNIX /dev/printer socket is active.
This is handy to determine if the LPD daemon was killed or
committed suicide due to abnormal conditions.
X.TP
clean { all | printer ... }
X.br
Remove all files beginning with ``cf'', ``tf'', or ``df''
from the specified printer queue(s) on the local machine.
X.IP "\fB\-D\fR[\fIn\fR]"
XEnables display of debugging information.
The 
X.B \-D\fIn\fR
X\fRsets debugging information to 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.SH FILES
X.nf
X.ta \w'/etc/printcap           'u
X/etc/printcap	printer description file
X/etc/printer_perms	printer permissions
X/usr/spool/*	spool directories
X/usr/spool/*/lock	lock file for queue control
X.fi
X.SH "SEE ALSO"
lpd(8),
lpr(1),
lpq(1),
lprm(1),
printcap(5),
printers(1),
printer(1)
X.br
X.I "PLP- The Public Line Printer Spooler" ,
Patrick Powell,
U. Minnesota.
X.SH DIAGNOSTICS
X.nf
Most of the diagnostics are self explanatory.
If you are puzzled over the exact cause of failure,
set the debugging level high and run again.
The debugging information will 
attempt to pinpoint the exact cause of failure.
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 5371 -ne `wc -c <'man/lpc.1'`; then
    echo shar: \"'man/lpc.1'\" unpacked with wrong size!
fi
# end of 'man/lpc.1'
fi
if test -f 'man/printcap.5' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'man/printcap.5'\"
else
echo shar: Extracting \"'man/printcap.5'\" \(6334 characters\)
sed "s/^X//" >'man/printcap.5' <<'END_OF_FILE'
X.TH PRINTCAP 5 "19 Mar 1988" "U-MN PLP"
X.ig
X$Header: printcap.5,v 2.2 88/05/19 07:42:43 papowell Locked $
X$Log:	printcap.5,v $
Revision 2.2  88/05/19  07:42:43  papowell
Added several more flags
X
Revision 2.1  88/05/09  10:08:53  papowell
PLP: Released Version
X
Revision 1.2  88/05/09  10:02:04  papowell
added :ab: flag, controls effect of -h option
X
Revision 1.1  88/04/28  10:58:58  papowell
Initial revision
X
X..
X.SH NAME
printcap \- printer capability data base
X.SH SYNOPSIS
X/etc/printcap
X.SH DESCRIPTION
X.I Printcap
is a simplified version of the
X.IR termcap (5)
data base
used to describe line printers.  The spooling system accesses the
X.I printcap
file every time it is used, allowing dynamic
addition and deletion of printers.  Each entry in the data base
is used to describe one printer.  This data base may not be
substituted for, as is possible for 
X.IR termcap ,
because it may allow accounting to be bypassed.
X.PP
The default printer is normally 
X.IR lp ,
though the environment variable PRINTER
may be used to override this.  Each spooling utility supports an option,
X.BI \-P printer,
to allow explicit naming of a destination printer.
X.PP
Refer to the
X.ul
X4.2BSD Line Printer Spooler Manual
for a complete discussion on how setup the database for a given printer.
X.SH CAPABILITIES
The database is a simplified form of the
X.I termcap (5)
database.
The entries can be strings
X(:st=string:),
positive integer values
X(:nu#12:),
or flags
X(:fl: to set,
X:fl@: to clear).
The following list the entries and the main users of them.
Use
X.B A
stands for
all programs,
and is commonly used by several programs.
XFor example,
the
X.B lf
X(lock file) entry is used by most programs to determine the state of the
spool queue.
X.B R
stands for
X.IR lpr ,
and is used by lpr for spooling purposes;
X.B D
stands for
X.IR lpd ,
and is used by lpd for controlling unspooling;
X.B P
stands for accounting information and is used by
X.I pac
or other programs.
Note that when the a filter is invoked by lpd or lpr,
the printcap entry will be available as the
X.B PRINTCAP
environment variable.
X.nf
X
X.ta \w'\0\0\0\0'u +\w'\0\0\0\0'u +\w'Type 'u +\w'Default 'u +4n +4n +4n 8i
X\fBFL	Use	Type	Default	Description\fR
XXf	D	str	NULL	output filter for format X used by lpd
XXe	R	str	NULL	prefilter for format X  used by lpr
ab	D	bool	false	always print banner, ignore lpr -h option
af	D	str	NULL	name of accounting file
bp	D	str	NULL	banner printing program (see ep)
br	D	num	none	if lp is a tty, set the baud rate (see ty)
cf	D	str	NULL	cifplot data filter
co	P	num	20	cost in dollars per thousand pages
df	D	str	NULL	tex data filter (DVI format)
ep	D	str	NULL	end of job banner printer
fc	D	num	0	if lp is a tty, clear flag bits (see ty)
fd	D	bool	false	no forwarded jobs accepted
ff	D	str	``\ef''	string to send for a form feed
fj	D	bool	false	send control file first to remote site
fo	D	bool	false	print a form feed when device is opened
fs	D	num	0	like `fc' but set bits (see ty)
fx	R	str	``flp''	valid output filter formats
gf	D	str	NULL	graph data filter (plot (3X) format)
if	D	str	NULL	name of text filter which does accounting
ld	D	str	NULL	leader string printed on printer open
lf	A	str	``log''	error log file (servers, filters and prefilters)
lh	D	bool	false	long hostname control file format
ln	R	str	NULL	groups allowed to use LPR -s (link), -r (remove)
lo	A	str	``lock''	name of lock file
lp	D	str	NULL	device name to open for output
mx	R	num	1000	maximum job size (1KB blocks, 0 = unlimited)
nf	D	str	NULL	DITROFF data filter
nw	A	bool	false	networked or distributed file system	
of	D	str	NULL	name of OF filter program
pl	D	num	66	page length (in lines)
pr	RD	str	``/bin/pr''	pr program for p format
pw	D	num	132	page width (in characters)
ps	A	str	NULL	printer status file name
px	D	num	0	page width in pixels (horizontal)
py	D	num	0	page length in pixels (vertical)
qh	D	str	NULL	unspooler program, instead of normal unspooler
rf	D	str	NULL	filter for printing FORTRAN style text files
rm	A	str	NULL	machine name for remote printer
rp	A	str	NULL	remote printer name argument
rw	D	bool	false	open the printer for reading and writing
sb	D	bool	false	short banner (one line only)
sc	R	bool	false	suppress multiple copies
sd	A	str	NULL	spool directory
sf	D	bool	false	suppress form feeds separating multiple jobs
sh	D	bool	false	suppress headers and/or banner page
st	A	str	``status''	queue server status file name
tf	D	str	NULL	troff data filter (C/A/T phototypesetter)
tr	D	str	NULL	trailer string to print when queue empties
ty	D	str	NULL	stty form to set printer line
vf	D	str	NULL	(Versatek) raster image filter
xc	D	num	0	if lp is a tty, clear local mode bits (see ty)
xs	D	num	0	like `xc' but set bits (see ty)
xt	R	str	NULL	formats to check for printable files
xu	A	str	NULL	additional printer_perms file for this queue
X.fi
X.PP
By convention,
all output filter names have for form
X.B Xf,
where
X.B X
is the lower case letter corresponding to the lpr formatting option.
The
X.B if
and
X.B of
filters are the standard output filters.
The filter capabilities have been extended by providing a
X.I prefilter
capability.
The names of prefilters have the form
X.B Xe,
and are specified in the same manner as the other filters.
If a prefilter is specified,
X.I lpr
will run the input files through the prefilter,
and spool the output of the prefilter for
disposition.
X.SH "TY (STTY) OPTIONS"
X.PP
The following
X.IR stty (1)
options are recognized by the
X.B ty
X(stty) printcap entry,
and can be used to set serial line characteristics for the printer.
X.nf
X.ta 16n +16n +16n +16n +16n +16n +16n +16n +16n
bs0	bs1	[-]cbreak	cooked	cr0	
cr1	cr2	cr3	[-]decctlq	[-]echo	
X[-]even	ff0	ff1	[-]lcase	[-]litout	
nl0	nl1	nl2	nl3	[-]nl	
X[-]noflsh	new	[-]nohang	old	[-]odd	
X[-]raw	start	stop	tab0	tab1	
tab2	[-]tabs	[-]tandem	tek	ti700	
X[-]tilde	tn300	tty33	tty37	vt05	
X.fi
X.SH "SEE ALSO"
termcap(5),
lpc(8),
lpd(8),
pac(8),
lpr(1),
lpq(1),
lprm(1)
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 6334 -ne `wc -c <'man/printcap.5'`; then
    echo shar: \"'man/printcap.5'\" unpacked with wrong size!
fi
# end of 'man/printcap.5'
fi
if test -f 'src/getopt.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'src/getopt.c'\"
else
echo shar: Extracting \"'src/getopt.c'\" \(6106 characters\)
sed "s/^X//" >'src/getopt.c' <<'END_OF_FILE'
X/***************************************************************************
X * U. Minnesota LPD Software * Copyright 1987, 1988, Patrick Powell
X ***************************************************************************
X * MODULE: Getopt.c
X * Getopt(3) implementation; modified so that the first time it is
X * called it sets "Name" to argv[0];
X ***************************************************************************
X * Revision History: Created Fri Jan  1 15:36:11 CST 1988
X * $Log:	getopt.c,v $
X * Revision 3.1  88/06/18  09:34:13  papowell
X * Version 3.0- Distributed Sat Jun 18 1988
X * 
X * Revision 2.1  88/05/09  10:08:08  papowell
X * PLP: Released Version
X * 
X * Revision 1.4  88/04/15  10:45:19  papowell
X * When checking for alternate flag chars, got a && mixed up with || test
X * 
X * Revision 1.3  88/04/07  12:27:20  papowell
X * Added ability to detect '+' options
X * 
X * Revision 1.2  88/04/06  12:13:51  papowell
X * Minor updates, changes in error message formats.
X * Elimination of the AF_UNIX connections, use AF_INET only.
X * Better error messages.
X * 
X * Revision 1.1  88/03/01  11:08:25  papowell
X * Initial revision
X * 
X ***************************************************************************/
X#ifndef lint
static char id_str1[] =
X	"$Header: getopt.c,v 3.1 88/06/18 09:34:13 papowell Exp $ PLP Copyright 1988 Patrick Powell";
X#endif lint
X/***************************************************************************
X * int Getopt ( argc, argv, optstring)
X *     int argc;
X *    	char **argv, *opstring;
X * int Optind, Opterr;
X * char *Optarg;
X * extern char *Name; 
X * Returns: EOF if no more options left;
X *    '?' if option not in optstring;
X *    option character if in optstr.
X *      if option char is followed by : in opstring, an argument is required,
X *        and Optarg will point to the option argument
X *      if option char is followed by ? in opstring, an argument is optional
X *        and Optarg will point to the argument if it immediately follows
X *        the option character
X *	If there are a special set of characters (such as "+" ) that should also
X *	be allowed to indicate flags, these are specified in the Opt_flag,
X *  which indicates that the character is allowed to act as an option flag
X * 
X * 
X * Getopt places the argv index of the next argument to be processed in
X * Optind. Because Optind is external, it is automatically set to zero
X * before the first call to Getopt.  When all the options have been
X * processed (i.e., up to the first non-option argument), Getopt returns
X * EOF.  The special option -- may be used to delimit the end of the
X * options; EOF will be returned, and -- will be skipped.
X * 
X * Getopt prints an error message on stderr and returns the offending
X * character when it encounters an option letter that is not included in
X * optstring.  This error message may be disabled by setting Opterr to a
X * non-zero value.
X * 
X * Side Effect:  when Getopt is called and Optind is 0, Name is set to
X * argv[0].  This allows pulling the program Name from the file.
X * Errors: if an argument is specified and none is there, then Optarg is
X * set to NULL
X * 
X ***************************************************************************/
X
X#include <stdio.h>
X
int	Optind = 0;			/* next argv to process */
int	Opterr = 0;			/* Non-zero disables errors msgs */
char	*Optarg = NULL;			/* Pointer to option argument */
static	char *next_opt = NULL;	/* pointer to next option char */
extern  char *Name;				/* the program Name */
extern  char *index();			/* find character in string */
char *Opt_flag;			/* first character is a flag */
X
int
Getopt(argc, argv, optstring)
X	int argc;					/* number of arguments */
X	char **argv;				/* array or arguments */
X	char *optstring;			/* option string */
X{
X	int option;				/* current option found */
X	char *match;			/* matched option in optstring */
X
X	if( Optind == 0 ){
X		/* set up the Name variable for error messages */
X		Name = argv[0];
X		Optind = 1;
X	}
X	if ( next_opt == NULL || *next_opt == '\0' ) {
X		/* No more arguments left in current or initial string */
X		if ( Optind >= argc ){
X			return( EOF );
X		}
X		next_opt = argv[Optind];
X		if( next_opt[0] != '-'
X			&& (Opt_flag == 0 || index( Opt_flag, next_opt[0] ) == 0) ){
X			/* we hit the last argument */
X			return( EOF );
X		}
X		/*
X		 * we have a '-' or a flag as first character
X		 */
X		if( next_opt[0] == '-' ){
X			++next_opt;
X		}
X		/* Single '-', end of opts */
X		if ( *next_opt == '\0' ){
X			return( EOF );
X		}
X		Optind++;
X	}
X	option = *next_opt++;
X	/*
X	 * Case of '--',  Force end of options
X	 */
X	if ( option == '-' ){
X		return( EOF );
X	}
X	/*
X	 * See if option is in optstring
X	 */
X	if ( (match = index(optstring, option)) == NULL ) {
X		if ( Opterr == 0 ){
X			(void)fprintf(stderr, "%s: Illegal option '%c'\n", Name, option);
X		}
X		return( '?' );
X	}
X	/*
X	 * Argument always follows this option
X	 */
X	if ( match[1] == ':' ) {
X		/*
X		 * Set Optarg to proper value
X		 */
X		if ( *next_opt != '\0' ){
X			Optarg = next_opt;
X		} else if ( Optind < argc ) {
X			Optarg = argv[Optind++];
X		} else {
X			if ( Opterr == 0 ){
X				(void)fprintf(stderr,
X					"%s: missing argument for '%c'\n",Name,option);
X				Optarg = NULL;
X			}
X		}
X		if( Optarg != NULL && Optarg[0] == '-' ){
X			if ( Opterr == 0 ){
X				(void)fprintf(stderr,
X					"%s: missing argument for '%c'\n",Name,option);
X				Optarg = NULL;
X			}
X		}
X		next_opt = NULL;
X	}
X	/*
X	 * Argument sometimes follows this option
X	 */
X	if ( match[1] == '?' ) {
X		/*
X		 * Set Optarg to proper value
X		 */
X		if ( *next_opt != '\0' ){
X			Optarg = next_opt;
X		} else {
X			Optarg = NULL;
X		}
X		next_opt = NULL;
X	}
X	return( option );
X}
X
X/***************************************************************************
X * Push_opt()
X * Some flags may have an optional argument.  The Push_opt is used to
X * push the argument that would normally be supplied back.  The assumption
X * is that the argument will start with a - sign, i.e.- be a flag,
X * and be the current value of Optind
X ***************************************************************************/
Push_opt()
X{
X	next_opt = 0;
X	Optind = Optind - 1;
X}
END_OF_FILE
if test 6106 -ne `wc -c <'src/getopt.c'`; then
    echo shar: \"'src/getopt.c'\" unpacked with wrong size!
fi
# end of 'src/getopt.c'
fi
if test -f 'src/lpr_canprint.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'src/lpr_canprint.c'\"
else
echo shar: Extracting \"'src/lpr_canprint.c'\" \(6092 characters\)
sed "s/^X//" >'src/lpr_canprint.c' <<'END_OF_FILE'
X/***************************************************************************
X * U. Minnesota LPD Software * Copyright 1987, 1988, Patrick Powell
X ***************************************************************************
X * MODULE: lpr_canprint.c
X * Checks to see if a file is printable
X * This will be a system dependent function.  If you have setreuid(),
X * you can implement this in a fairly effective manner, as the file
X * open and stat() is done as the user, not as root.
X * The "is_exec" and "is_arch" functions are very system dependent.
X * If you have file(1) available,  check to see how it determines the file
X * types.  This may be more bizzare than you expect.
X ***************************************************************************
X * Revision History: Created Sat Jan 30 15:17:59 CST 1988
X * $Log:	lpr_canprint.c,v $
X * Revision 3.2  88/06/24  17:55:54  papowell
X * MODS for VAX 4.3BSD UNIX
X * 
X * Revision 3.1  88/06/18  09:34:51  papowell
X * Version 3.0- Distributed Sat Jun 18 1988
X * 
X * Revision 2.2  88/05/19  10:34:15  papowell
X * Fixed open() calls to have a 0 parameter, ie: open(f, perms, 0), where needed
X * 
X * Revision 2.1  88/05/09  10:09:06  papowell
X * PLP: Released Version
X * 
X * Revision 1.9  88/05/06  07:08:54  papowell
X * Modified getwd() call so that a setreuid() is done first.  This way there
X * are no problems with root perms on different systems.
X * 
X * Revision 1.8  88/04/28  17:31:59  papowell
X * fixed the setreuid() calls so that they will work on several systems
X * very odd behaviour.  Also modified the access() calls.
X * 
X * Revision 1.7  88/04/28  11:03:30  papowell
X * Modified the "printability" check to only do known text formats.
X * The XT flag is now used to force a check, rather than not forced a check
X * 
X * Revision 1.5  88/04/07  09:10:09  papowell
X * Apollo Workstation Modifications
X * 
X * Revision 1.4  88/04/06  12:13:14  papowell
X * Minor updates, changes in error message formats.
X * Elimination of the AF_UNIX connections, use AF_INET only.
X * Better error messages.
X * 
X * Revision 1.3  88/03/25  15:00:23  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.2  88/03/11  19:27:52  papowell
X * Minor Changes, Updates
X * 
X * Revision 1.1  88/03/01  11:08:43  papowell
X * Initial revision
X * 
X ***************************************************************************/
X#ifndef lint
static char id_str1[] =
X	"$Header: lpr_canprint.c,v 3.2 88/06/24 17:55:54 papowell Exp $ PLP Copyright 1988 Patrick Powell";
X#endif lint
X
X#include "lpr.h"
extern long lseek();
X
X/***************************************************************************
X * Is_printable(  char *f )
X * Test to see if this is a printable file.
X * Return: 0 if unprintable; 1 otherwise
X ***************************************************************************/
static char errmsg[] = "File '%s' not printed: %s";
X
int
Is_printable( file, statb )
X	char *file;
X	struct stat *statb;	/* file status */
X{
X	char buf[BUFSIZ];
X	int fd = -1;		/* file descriptor */
X	int n, i, c;		/* Acme Integers, Inc. */
X	int succ = 0;
X	int euid = geteuid();	/* euid of process */
X
X	/*
X	 * If you have setreuid, you are very lucky; do all this as the user
X	 */
X	if( access(file, F_OK | R_OK) < 0){
X		Warnmsg(errmsg, file, "cannot access it");
X	} else if(Remove && access(file, F_OK | R_OK | W_OK ) < 0){
X		Warnmsg(errmsg, file, "cannot remove it");
X 	} else {
X		/*
X		 * do the rest of tests as USER
X		 */
X		if( euid == 0 ){
X			Set_uid( getuid() );
X		}
X		if ((fd = open(file, O_RDONLY, 0)) < 0) {
X			Warnmsg(errmsg, file, "cannot open it");
X		} else if (fstat(fd, statb) < 0) {
X			Warnmsg(errmsg, file, "cannot stat it");
X		} else if ((statb->st_mode & S_IFMT) == S_IFDIR) {
X			Warnmsg(errmsg, file, "it is a directory");
X		} else if (statb->st_size == 0) {
X			Warnmsg(errmsg, file, "it is an empty file");
X		} else if( (n = read(fd, buf, sizeof(buf))) <= 0 ){
X			Warnmsg(errmsg, file, "cannot read it");
X		} else if( Binary || Format == 'l' ){
X			succ = 1;
X		} else if( !(index( "fpr", Format) || (XT && index( XT, Format)) )){
X			/*
X			 * We don't have to do the following checks, applicable to
X			 * text files.
X			 */
X				succ = 1;
X		} else if( is_exec(fd, buf, n) ){
X			Warnmsg(errmsg, file, "executable program");
X		} else if( is_arch(fd, buf, n)){
X			Warnmsg(errmsg, file, "archive file");
X		} else {
X			succ = 1;
X			/*
X			 * check for clean and lovely files, up to the first block
X			 */
X			for( i = 0; i < n; ++i ){
X				c = buf[i];
X				if(!isascii(c) || !( c == '\b' || isprint(c) || isspace(c))){
X					Warnmsg(errmsg, file, "it is a garbage file");
X					succ = 0;
X						break;
X				}
X			}
X		}
X		if( succ == 0 ){
X			(void)close(fd);
X			fd = -1;
X		} else if( lseek( fd, 0L, 0 ) < 0 ){
X			logerr( XLOG_INFO, "Is_printable: lseek failed %s", file );
X			(void)close(fd);
X			fd = -1;
X		}
X		if( euid == 0 ){
X			Clear_uid();
X		}
X	}
X	return(fd);
X}
X/*
X * The is_exec and is_arch are system dependent functions
X * which check if a file is an executable or archive file,
X * based on the information in the header.
X */
X
X#ifndef	NO_A_OUT_H
X#include <a.out.h>
X#endif	NO_A_OUT_H
X#include <ar.h>
X
static int
is_exec( fd, buf, n )
X	int fd;
X	char *buf;
X	int n;
X{
X	int i;
X#ifdef IS_DATAGEN
X#	include <sgs.h>
X	struct header header;
X
X	i = 0;
X	if( lseek(fd, (long)0, 0 ) < 0 ){
X		logerr(XLOG_INFO,"is_exec: cannot lseek");
X	}
X	if( read(fd, (char *)&header, sizeof(header) ) == sizeof(header)  ){
X		i =  ISMAGIC(header.magic_number);
X	}
X#endif IS_DATAGEN
X#if defined(IS_VAX) || defined(IS_SUN)
X
X	i = 0;
X	if( n >= sizeof( struct exec ) ){
X		i = !(N_BADMAG( (*(struct exec *)buf) ));
X	}
X#endif
X#if defined( IS_UMAX ) || defined( NO_A_OUT_H )
X	i = 0;
X#endif
X	return( i );
X}
X
static int
is_arch( fd, buf, n )
X	int fd;
X	char *buf;
X{
X	return( !strncmp( buf, ARMAG, strlen( ARMAG )) );
X}
END_OF_FILE
if test 6092 -ne `wc -c <'src/lpr_canprint.c'`; then
    echo shar: \"'src/lpr_canprint.c'\" unpacked with wrong size!
fi
# end of 'src/lpr_canprint.c'
fi
if test -f 'src/lpr_temp.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'src/lpr_temp.c'\"
else
echo shar: Extracting \"'src/lpr_temp.c'\" \(5731 characters\)
sed "s/^X//" >'src/lpr_temp.c' <<'END_OF_FILE'
X/***************************************************************************
X * U. Minnesota LPD Software * Copyright 1987, 1988, Patrick Powell
X ***************************************************************************
X * MODULE: lpr_temp.c
X * Routines to manage the Temp_file array
X ***************************************************************************
X * Revision History: Created Sat Jan 30 12:31:45 CST 1988
X * $Log:	lpr_temp.c,v $
X * Revision 3.1  88/06/18  09:35:03  papowell
X * Version 3.0- Distributed Sat Jun 18 1988
X * 
X * Revision 2.2  88/05/14  10:18:36  papowell
X * Use long format for job file names;
X * Added 'fd', no forward flag;
X * Control file has to have hostname and origination agree.
X * 
X * Revision 2.1  88/05/09  10:09:28  papowell
X * PLP: Released Version
X * 
X * Revision 1.4  88/05/06  07:07:58  papowell
X * Fixed up error messages.
X * 
X * Revision 1.3  88/03/25  15:00:45  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.2  88/03/11  19:29:54  papowell
X * Minor Changes, Updates
X * 
X * Revision 1.1  88/03/01  11:08:52  papowell
X * Initial revision
X * 
X ***************************************************************************/
X#ifndef lint
static char id_str1[] =
X	"$Header: lpr_temp.c,v 3.1 88/06/18 09:35:03 papowell Exp $ PLP Copyright 1988 Patrick Powell";
X#endif lint
X
X#include "lpr.h"
X
X/***************************************************************************
X * Get_tmp_data()
X *   Generate the name of a data file
X * Get_cf()
X *   return the name of the control file.
X * Add_temp( char *s )
X *   Add the name of a file to the temporary file list
X * Remove_temp()
X *   Unlink all the files in the Temp_file[] list
X ***************************************************************************/
X
X/***************************************************************************
X * Get_tmp_data()
X * Generate the name of a data file
X * The name has the form: df<seq><job><host>
X ***************************************************************************/
static int seq;
X
char *
Get_tmp_data()
X{
X	char buf[BUFSIZ];	/* Big Buffers, Inc. */
X	int c;				/* ACME Integers, Inc. */
X	char *sp;			/* ACME Pointers, Inc. */
X	char *st = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
X
X	/*
X	 * convert sequence number to A-Z, a-z
X	 */
X	if( seq >= strlen(st) ){
X		Diemsg( "too many input files, split job up" );
X	}
X	c = st[seq];
X	++seq;
X	/*
X	 * generate name
X	 */
X	(void)sprintf(buf, "df%c%03d%s", c, Job_number, Host );
X	if(Debug>3)log(XLOG_DEBUG,"Get_tmp_data: %s",buf);
X
X	/*
X	 * Add to list of temporary files to be removed in case of error
X	 */
X	sp = Add_temp( buf );
X	return( sp );
X}
X
X
X/***************************************************************************
X * Get_cf()
X * return the name of the control file.  This has the form
X * tf<Priority><Sequence><Host>
X ***************************************************************************/
char *
Get_cf()
X{
X	char buf[BUFSIZ];	/* Big Buffers, Inc. */
X	char *sp;			/* ACME Pointers and Buggy Whips */
X
X	(void)sprintf(buf, "tf%c%03d%s", Priority, Job_number, Host );
X	/*
X	 * check to see that the job file name fits in the limits
X	 */
X	if( strlen( buf ) >= CFNAMELEN ){
X		fatal( XLOG_INFO, "Get_cf: control file name too long '%s'",
X			buf);
X	}
X	if(Debug>3)log(XLOG_DEBUG,"Get_cf: control file %s",buf);
X	sp = Add_temp( buf );
X	return( sp );
X}
X
X/***************************************************************************
X * Add_temp( char *s )
X * Add the name of a file to the temporary file list
X * Note: these will be deleted on abnormal exit
X ***************************************************************************/
static char *Temp_space;
static int Temp_size;
X
char *
Add_temp( s )
X	char *s;
X{
X	int i;
X	char *sp;		/* ACME Pointers and Integers */
X
X	if( Temp_max == 0 ){
X		Temp_max = 10;
X		Temp_file = (char **)malloc( (unsigned)sizeof(char *) * Temp_max);
X		if( Temp_file == 0 ){
X			fatal( XLOG_INFO, "Add_temp: malloc Temp_file failed" );
X		}
X	}
X	if( Temp_max <= Temp_count ){
X		Temp_max += 10;
X		Temp_file = (char **)realloc((char *)Temp_file,
X			(unsigned)(sizeof(char *)*Temp_max));
X		if( Temp_file == 0 ){
X			fatal( XLOG_INFO, "Add_temp: realloc Temp_file failed" );
X		}
X	}
X	i = strlen( s ) + 1;
X	if( i > Temp_size ){
X		Temp_size = BUFSIZ;
X		Temp_space = malloc( BUFSIZ );
X		if( Temp_space == 0 ){
X			fatal( XLOG_INFO, "Add_temp: malloc Temp_space failed" );
X		}
X	}
X	sp = Temp_space;
X	(void)strcpy(Temp_space, s );
X	Temp_file[Temp_count] = sp;
X	++Temp_count;
X	Temp_space += i;
X	Temp_size -= i;
X	if(Debug>5){
X		for(i=0;i<Temp_count;++i)log(XLOG_DEBUG,"temp %d %s",i,Temp_file[i]);
X	}
X	return( sp );
X}
X
X
X/***************************************************************************
X * Remove_temp()
X * Unlink all the files in the Temp_file[] list
X ***************************************************************************/
X
Remove_temp()
X{
X	char buf[BUFSIZ];	/* hold the full pathname */
X	int i;				/* ACME Integers, Inc. */
X	char *sd_end;		/* end of the SD name in buf */
X
X	if( Temp_count <= 0 || SD == 0 || *SD == 0
X		|| (strlen(SD)+CFNAMELEN)> sizeof(buf) ){
X		return;
X	}
X	(void)strcpy(buf, SD );
X	(void)strcat(buf, "/" );
X	sd_end = &buf[strlen(buf)];
X	for(i = 0; i < Temp_count; ++i ){
X		(void)strcpy( sd_end, Temp_file[i] );
X		if(Debug>3)log(XLOG_DEBUG,"Remove_temp: removing temp file %s", buf );
X		if( unlink( buf ) < 0 ){
X			logerr(XLOG_INFO,"Remove_temp: cannot remove temp file %s", buf );
X		}
X	}
X}
END_OF_FILE
if test 5731 -ne `wc -c <'src/lpr_temp.c'`; then
    echo shar: \"'src/lpr_temp.c'\" unpacked with wrong size!
fi
# end of 'src/lpr_temp.c'
fi
if test -f 'src/servicereq.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'src/servicereq.c'\"
else
echo shar: Extracting \"'src/servicereq.c'\" \(5963 characters\)
sed "s/^X//" >'src/servicereq.c' <<'END_OF_FILE'
X/***************************************************************************
X * U. Minnesota LPD Software * Copyright 1987, 1988, Patrick Powell
X ***************************************************************************
X * MODULE: servicereq.c
X * service requests to lpd
X ***************************************************************************
X * Revision History: Created Sat Jan  2 08:54:52 CST 1988
X * $Log:	servicereq.c,v $
X * Revision 3.1  88/06/18  09:35:39  papowell
X * Version 3.0- Distributed Sat Jun 18 1988
X * 
X * Revision 2.1  88/05/09  10:10:17  papowell
X * PLP: Released Version
X * 
X * Revision 1.3  88/04/06  12:12:48  papowell
X * Minor updates, changes in error message formats.
X * Elimination of the AF_UNIX connections, use AF_INET only.
X * Better error messages.
X * 
X * Revision 1.2  88/03/25  15:01:39  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.1  88/03/01  11:09:16  papowell
X * Initial revision
X * 
X ***************************************************************************
X * Description:
X * The LPD daemon waits for a request from an associated process using a socket.
X * The main lpd daemon forks a server process,  which connects to the
X * requesting process.  The two processes communicate over the socket. 
X * A message packet containing a request is the first information transferred.
X * Some requests will need to have error messages and diagnostics generated
X * by LPD sent to the user;  the "Echo_on_stdout" flag causes errors to be
X * echoed there as well.
X * The following operations are supported:
X *	    \1Printer\n
X * 	    	check the queue for jobs and print any found.
X *          -- acknowlege request and close socket
X *          -- start up the Printer
X *	    \2Printer\n
X *	    	receive a job from another machine and queue it.
X *          -- a complex file transfer protocol is used to transfer files.
X *	    \3Printer [users ...] [jobs ...]\n
X *	    	return the current state of the queue (short form).
X *          -- errors and diagnostics returned as well
X *	    \4Printer [users ...] [jobs ...]\n
X *	    	return the current state of the queue (long form).
X *          -- errors and diagnostics returned as well
X *	    \5Printer Person [users ...] [jobs ...]\n
X *	    	remove jobs from the queue.
X *          -- errors and diagnostics returned as well
X *	    \6Printer Person operation
X *	    	enable/disable queueing, etc.
X *          -- errors and diagnostics returned as well
X ***************************************************************************/
X#ifndef lint
static char id_str1[] =
X	"$Header: servicereq.c,v 3.1 88/06/18 09:35:39 papowell Exp $ PLP Copyright 1988 Patrick Powell";
X#endif lint
X
X#include "lp.h"
X
static char	command[BUFSIZ];	/* command line buffer */
static char	*cmd_names[] = {
X	"ERROR",			/* 0 */
X	"Startprinter",		/* 1 */
X	"receive files",	/* 2 */
X	"display [short]",	/* 3 */
X	"display [long]",	/* 4 */
X	"remove job",		/* 5 */
X	"control operation"			/* 6 */
X};
X
X/****************************************************************
X * servicereq()
X *   1. Reads the first line from the socket
X *   2. Determine service request
X *   3. Call suitable dispatch function
X ****************************************************************/
servicereq()
X{
X	int n;			/* ACME Integer, Inc. */
X
X	/*
X	 * use almost bombproof way to read command line from socket
X	 */
X	n = bpread( 1, command, sizeof(command));
X	if(n < 2 ){
X		fatal(XLOG_INFO,"servicereq: bad command line");
X	}
X	Request = command[0];
X	if (Request < 1 || Request > 6 ){
X		fatal(XLOG_INFO,"servicereq: bad request (%d) %s",Request, &command[1]);
X	}
X	if (Debug>1)log( XLOG_DEBUG,"%s requests %d (%s) %s",From,Request,
X		cmd_names[Request],&command[1]);
X	splitline( &command[1] );
X	if( Request != REQ_CONTROL ){
X		/*
X		 * extract Printer Name from command
X		 */
X		Printer = Parms[0].str;
X		/*
X		 * check to see if you can do the job
X		 */
X		if(chkhost() == 0){
X			fatal(XLOG_INFO,"Host %s cannot access %s", From, Printer);
X		}
X	}
X	switch (Request) {
X	/*
X	 * start Printer
X	 */
X	case REQ_START:
X		/* signal the other end that you are doing the request */
X		putchar( 0 );		/* fd 1 is the socket */
X		(void)fflush(stdout);	/* send it */
X		(void)close(1);			/* disconnect */
X		if( dup2(0,1) < 0 ){
X			logerr_die(XLOG_INFO,"dup2 failed");
X		}
X		Startprinter();		/* start Printer */
X		break;
X	/*
X	 * get remote jobs
X	 */
X	case REQ_RECV:	/* get files from remote site */
X		recvfiles();
X		Startprinter();		/* start Printer */
X		break;
X	/*
X	 * display current queue
X	 */
X	case REQ_DSHORT:	/* display the queue (short form) */
X	case REQ_DLONG:		/* display the queue (long form) */
X		/*	echo errors on stdout as well as stderr */
X		Echo_on_stdout = 1;
X		Short_format = (REQ_DSHORT==Request);
X		Shift_parms(1);
X		(void)Displayq();
X		break;
X	/*
X	 * remove job from queue
X	 */
X	case REQ_REMOVE:	/* remove a job from the queue */
X		/*	echo errors on stdout as well as stderr */
X		Echo_on_stdout = 1;
X		Person = Parms[1].str;
X		Shift_parms(2);
X		rmjob();
X		break;
X	/*
X	 * perform control function
X	 */
X	case REQ_CONTROL:	/* remove a job from the queue */
X		Echo_on_stdout = 1;
X		Person = Parms[0].str;
X		Shift_parms(1);
X		(void)Control_ops();
X		break;
X	}
X}
X
X/**********************************************************************
X * chkhost()
X * check permissions to see if Host has access to the Printer
X * Return: 1 if permissions to use Printer, 0 otherwise
X **********************************************************************/
static int
chkhost()
X{
X	if( strcmp(From, Host) == 0	/* this Host */
X		||( Permfile && *Permfile
X			&& Checkperm(Permfile,From,(char*)0,Printer,(int*)0,(int*)0,0)) ){
X		return(1);
X	}
X	return(0);
X}
END_OF_FILE
if test 5963 -ne `wc -c <'src/servicereq.c'`; then
    echo shar: \"'src/servicereq.c'\" unpacked with wrong size!
fi
# end of 'src/servicereq.c'
fi
echo shar: End of archive 4 \(of 16\).
cp /dev/null ark4isdone
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