v16i024: Public lineprinter spooler package, Part11/16

Rich Salz rsalz at bbn.com
Thu Sep 15 22:14:53 AEST 1988


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

#! /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 11 (of 16)."
# Contents:  doc/PLP/11.t src/localprinter.c src/lpr_parms.c
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f 'doc/PLP/11.t' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'doc/PLP/11.t'\"
else
echo shar: Extracting \"'doc/PLP/11.t'\" \(15498 characters\)
sed "s/^X//" >'doc/PLP/11.t' <<'END_OF_FILE'
X.ig
X$Header: 11.t,v 1.1 88/05/21 18:39:52 papowell Locked $
X$log$
X..
X.bp
X.NH 1
Installation and Testing
X.PP
The following is a summary of the installation
and test procedures for the PLP software.
X.NH 2
Source Files
X.PP
As distributed,
all source and related files for the software have been
collected under a common directory
X$(PLP),
The $(PLP) directory has the following structure.
X.DS
X.DT
X.ta 12m +4n +4n
X.L
X.SM
README	-- brief summary
Makefile	-- calls {bin, filters, utilities}/Makefile
bin/	-- directory for binaries and executables
bin/Makefile	-- Makefile for executables
doc/	-- documentation source, this document
filters/	-- output filters
lint/	-- directory for lint output
man/	-- man pages
src/	-- source for lpd, lpr, lpc, etc.
test/	-- test programs and files
utilities/	-- source for pr, cpr and other handy print formatters.
printcap/	-- a method to organize printcap entries
X.DE
X.NH 2
Printcap And Printer Permissions Files
X.PP
The PLP software uses a different organization of printcap and permissions
files than the Berkeley LPD.
All of the PLP related control and informations files are gathered in
X.L /usr/spool/lpd .
XFor example:
X.DS
X.nf
X.SM
X.L
X.ta 15n +4n +4n +4n 8i
X.vs -2
X.R
X.LG
X/usr/spool/lpd/printcap.<host>	# printcap for <host>
X/usr/spool/lpd/printer_perms.<host>	# printer permissions for <host>
X/usr/spool/lpd/lpd.lock.<host>	# lpd daemon lock for <host>
X/usr/spool/lpd/log.<host>	# lpd daemon log for <host>
X.vs +2
X.LG
X.R
X.DE
In a networked base file system,
this allows a single spool directory to be shared among all the
systems using PLP.
In addition,
only system which are performing unspooling operations will need to
have an LPD daemon running.
XFinally,
care has been taken to ensure that all accesses to the shared files are
done by
user id
X.L daemon .
X.PP
In order to update an existing system,
all that needs to be done is to create a spool directory and
provide the above files.
The file
X.L $(PLP)/test/printer_perms.all
is a prototype printer permissions file that does not provide
many restrictions.
X.KF
X.in +1i
X.nf
X.DT
X.L
X.SM
X.vs -2
X.ta 4n +4n +4n +4n +4n +4n +4n +4n +4n +4n +4n 8i
X#!/bin/csh
X# Creating the /usr/spool/lpd directory
set h=<<<<host>>>>;	# specify your host name
mkdir /usr/spool/lpd
ln -s /etc/printcap /usr/spool/lpd/printcap.${h}
cp $(PLP)/test/printer_perms.all /usr/spool/lpd/printer_perms.${h}
X.vs +2
X.sp .5v
X.R
X.LG
X.in -1i
X.ce
XFigure 11.1  Creating Directories
X.KE
X.NH 2
Compilation and Installation
X.PP
The
X.L bin
directory is used to hold binaries.
During the initial installation procedure,
you should copy the
X.L Makefile
from the
X.L src directory,
and set any system  dependent flags in the Makefile.
The flags
X.L IS_<system>
are used to specify the system type,
and cause conditional compilation of
entries in the
X.L src/lp.h
file.
After checking the flags and their implications,
X.L "make all"
can be used
to compile and link the programs.
X.PP
As distributed,
the
X.L XPERIMENT
compilation flag is set in the Makefile,
and causes a test verion of the PLP softwar to be generated.
It is strongly suggested you try the test or experimental version first,
i.e.- compile with the XPERIMENT option enabled,
and then try a fully functional version.
X.NH 2
Test Version
X.PP
A test version of the spooling software can be generated
by compiling with the XPERIMENT flag set.
This causes
X.L /tmp/printcap.<host>,
X.L /tmp/printer_perms.<host>,
and a non-priviledged INET port
to be used,
rather than
X.L /usr/spool/lpd/printcap.<host>,
and the priviledged TCP/IP printer server port.
X.PP
The PLP distribution
X.B test
directory contains prototype or debugging versions of printcap,
printer_perms,
and other files;
X.B test/Makefile
will generate and install the necessary directories,
etc.,
and
will install the necessary filters.
The test devices have their spool directories in /tmp,
and should be trivial to install.
Run the tests listed below
to ensure that the various programs are working.
Note that all the functionality of the PLP software can be checked out
as an ordinary user,
and you do NOT need to run as ROOT.
X.PP
In summary,
to make the test verions,
do the following.
X.IP 1).
Create a bin directory,
copy the Makefile from src,
edit the Makefile and set the various system dependencies.
X.IP 2).
Run
X.L "make all" .
At this point you will have all of your binaries in the bin
directory,
where you should leave them.
Set up your shell $path or $PATH to use
X$(PLP)/bin directory ahead of /usr/ucb,
otherwise you will use the existing LPD programs.
X.IP 3).
Go to the
X.L test
directory,
read the
X.L test/README
file,
edit the
X.L test/Makefile
according to directions,
and do
X.L "make bin" .
in the
X.L test
directory.
This generates some executables and places them in the /tmp
directory,
as well as installing a test version of the printer permission file.
X.IP 4).
Now you should take a nap,
play rogue,
or whatever you do to relax.
The next part is not fun.
X.NH 3
Test 1\- LPC, LPR, LPQ
X.PP
To run the first tests,
change to the
X.L test
directory and do
X.L "make test1" .
This installs the printcap file of Figure 11.2 in /tmp/printcap:
X.KF
X.in +1i
X.nf
X.DT
X.L
X.SM
X.vs -2
X.ta 4n +4n +4n +4n +4n +4n +4n +4n +4n +4n +4n 8i
X#
X# TEST VERSION OF PRINTCAP FILE:
X# Test 1: simple lpr functions
X#
test:\e
X	:fx=flpdnt:ex:\e
X	:pw#75:pl#66:rw:\e
X	:br#9600:fs#040:fc#011:\e
X	:ty=new 19200 even -tabs tandem:\e
X	:lp=output:\e
X	:if=/tmp/filter -delay30:\e
X	:of=/tmp/lpf -D5:\e
X	:sd=/tmp/test:
X.vs +2
X.sp .5v
X.R
X.LG
X.in -1i
X.ce
XFigure 11.2  Test 1 Printcap File
X.KE
X.PP
You should look at the code for the
X.L filter
and the
X.L lpf
programs which were created by the
X.L "make bin" .
The
X.L filter
program is a handy dandy debugging filter.
The
X.L lpf
filter simply copies stdin to stdout,
and suspends itself when it detects the stop string.
The
X.L lpf
filter source is the skeleton for any new filters that are needed.
X.PP
You can test the functionality of the
lpq,
and lpr
programs by using the illustrated commands.
Sample output has been provided.
X.nf
X.vs -2
X.DT
X.SM
X.L
X.ta 12n +4n +4n +4n +4n +4n +4n +4n
X%>lpq -D5	#should display queue (empty)
lpq: pid=4233, LOG_DEBUG, First_printer: simple at Fri May 20 17:02:08 1988
lpq: simple- pid=4233, LOG_DEBUG, Get_Printer: First_printer 'simple' at Fri May 20 17:02:08 1988
lpq: simple- pid=4233, LOG_DEBUG, Get_printer: using Printer simple at Fri May 20 17:02:08 1988
lpq: simple- pid=4233, LOG_DEBUG, Readlockfile: lockfile 'lock' at Fri May 20 17:02:08 1988
lpq: simple- pid=4233, LOG_DEBUG, Readlockfile: lock, perms 0100644 at Fri May 20 17:02:08 1988
lpq: simple- pid=4233, LOG_DEBUG, Readlockfile: 'lock' pid 0 len 0 at Fri May 20 17:02:08 1988
lpq: simple- pid=4233, LOG_DEBUG, Checklockfile: lock server 0 at Fri May 20 17:02:08 1988
lpq: simple- pid=4233, LOG_DEBUG, printstatus: ST status at Fri May 20 17:02:08 1988
Printer 'simple' (attila.cs.umn.edu):
X  work done at Wed May 18 09:38:59 1988
X
X%>lpr xx	#place job in queue
lpr: Warning- File 'xx' not printed: cannot access it
lpr: Fatal error- nothing to print
X
X%>echo hi | lpr	#place job in queue
lpr: simple- Startserver: host 'attila.cs.umn.edu' server for 'simple'
X	not started - Connection refused at Fri May 20 17:08:51 1988
X
X%>lpq	#should display queue one entry
Printer 'simple' (attila.cs.umn.edu):
Warning: no server present
X  Rank Owner       Pr Job Host        Files                Size
X   1st papowell    Z  13  attila      (stdin)              3
X
X%>lpc	#play with lpc
X>status
Queue          Jobs    Queueing     Printing
simple            1    enabled      enabled (no server)
X
X>disable simple
simple: queueing disabled
X>status
Queue          Jobs    Queueing     Printing
simple            1    disabled     enabled (no server)
X>quit
X.R
X.LP
X.NH 3
Test 2\- LPD Functionality
X.PP
Use the commands:
X.ti +.5i
X.L "echo >/tmp/error"
X.ti +.5i
X.L "lpd  -D5 -L /tmp/error; tail -f /tmp/error"
X.br
to create the error log file and to start up ldp.
It is best to do this at one terminal,
and then do the remaining tests at another terminal.
Lucky windowing system users will,
of course,
simply open another window.
You will be amused to watch the lpd spring into action,
trying to create servers,
etc.
The
X.L simple
server will log into the
X.L /tmp/simple/log
file.
X.PP
You can remove /tmp/test/log,
and see the interaction of the lpd daemon and the printer server
little clearer.
To kill the lpd daemon,
do the following:
X.DS
X.DT
X.L
X.SM
lpc lpd		##- prints the lpd daemon id
kill <pid>	# kill off the daemon
rm /tmp/test/log	# remove the log file
echo >/tmp/error
lpd -D5 -L /tmp/error
tail -f /tmp/error
X.R
X.DE
X.PP
If you are curious,
try starting multiple
X.L "lpd"
programs;
when
X.L lpd
is started,
it checks for a running daemon,
print a message,
and then exits.
X.PP
You can examine the conditions of the servers and other
activites by using
X.I lpq .
Note that the lpq status report includes a chatty informational piece about
the job progress.
X.PP
The OF filter has been carefully created to print out
various pieces of information.
You can see what this is if you look at /tmp/test/output,
where the output is going.
You will notice that the IF filter is a shell script,
and will do a sleep for a while.
You can now test out the various lpq,
lpr,
and lpc functions.
X.NH 3
Test 3 \- Remote Servers
X.PP
These tests check out the functionality of inter host spooling functions.
They have been written so that they will use the local host intitially,
but can be extended to the remote host.
X.PP
In the
X.L test
direcotory, do
X.L "make test2"
to install the second form of the printcap file.
You will not have to kill the lpd to do this.
Now try
X.ti +.5i
X.L "lpq -Premote"
X.br
and examine the output.
The lpq program will print out the local queue,
and then send a message to the remote host (which is the local host)
using the INET protocol.
This will check out the functionality of the network communication.
You can play with lpr,
lpc,
etc. and check this out.
Try the
X.I remote
functions of the
X.I lpc
program.
X.PP
If you have two hosts available,
install the PLP software on both of them.
XEdit the printcap files so that one of them has the local test,
and the other the remote test entry.
Don't forget to install and modify the printer_perms file so that the
remote host can access the test spool queue.
Try the communications out.
X.NH 3
Test 4 \- Multiple Servers
X.PP
This will demonstrate how to have multiple servers for a single spool
queue.
Install the printcap file by doing
make test3.
Use lpq to check the status of the spool queue.
Now use lpr to send a slog (10 or more) jobs to the multi queue.
You can use
X.ti +.5i
X.L "lpq +10 -a"
X.br
to monitor what happens.
X.NH 3
Test 5 \- Serial Line Control
X.PP
If you have a printer,
attach it to a suitable serial line,
and modify the test printcap entry so that it is set up
for the printer.
I have found that the following procedure works pretty good.
X.PP
Set the
X.B sh
X(suppress headers or banners)
in the printcap entry,
and remove the
X.B of
entry.
Set up a new entry for if,
X.B "if=/tmp/serial -d30"
and edit the filter program to print out the stty settings.
You can now run lpr to try and send things out to the printer.
You will either have lots of problems or no problems in communicating
with the printer.
X.PP
Watch out for parity;
you may have to fool around with the printer parity settings.
I strongly suggest a NO parity setting.
Tandem flow control is another tricky area.
You may have to open the printer RW using
X.B rw
to get tandem flow control.
This has been a problem with several installations.
X.NH 2
Installing a Working Version
X.PP
Before you install a the PLP software,
you should make a copy of the existing print spooler software.
There is a set of programs in the
X.L backup
directory of the PLP distribution that have proven to be very useful.
X.IP 1).
XEdit the
X.L bin/Makefile ,
and disable the XPERIMENT flag.
Do a
X.L "make clean; make all"
to regenerate the working version.
X.IP 2).
Create a printer permissions file.
You can base this on the version in the
X.L test
directory.
The version
in Figure 12.3 is useful for initial installations,
and can be found in
X.L test/printer_perms.all .
X.KF
X.nf
X.SM
X.L
X.vs -2
X# Printer permissions data base
X# host user printerqueue maxpriority maxpages currentpages
X# * is a wildcard
X#host   user      printer     perms  pr maxpages pages
X*       root      *           *      *  0        0  #root on any system
X*       *         *           R      G  0        0 #anybody can do remote
X.vs +2
X.LG
X.R
X.sp .5v
X.ce
XFigure 11.3  Sample Printer Permissions File
X.KE
X.IP 3).
Do a
X.L "make install"
and check that permissions have been set correctly.
X.IP 4).
Using the same tests as outlined above,
make sure that lpr,
lpc,
and lpq
are functional.
X.IP 5).
Start lpd
and check that files are unspooled and transferred correctly.
When sending files to remote sites,
both must be running PLP versions.
X.NH 2
Organization of Printcap Information
X.PP
If you are working in an environment with a large number of
different sites and different printers,
you may find the programs in the
X.L printcap
directory handy to manage printcap files.
The organization and management is based on the following structure.
X.PP
XEach printer has a physical location name and a set of aliases.
XFor our sample printer,
X.L printer_loc ,
There is a
X.L printer_loc.local
file which contains a printcap entry suitable for the host which has the device
attached,
a
X.L printer_loc.remote
file which contains a printcap entry suitable for a host
which can communicate directly to the remote host,
and a 
X.L printer_loc.forward
file which contains a printcap entry suitable for a host
which forwards jobs to either a local or remote host.
XFor example,
here are typical entries for the 3 files.
These files are stored in the directory
X.L printcap/devices .
XFigure 12.4 is a sample of several of them.
X.KF
X.TS
center box;
lw(2.5) |  lw(2.5i) .
X.L
X.SM
dg1_lind23.local	dg1_lind23.remote
X_
T{
X.nf
dg1_lind23.local|dg1:\e
X    :sd=/usr/spool/dg1_lind23:\e
X    :lp=/dev/tty09:sy=9600 -even -odd:
T}	T{
X.nf
dg1_lind23.local|dg1:\e
X    :sd=/usr/spool/dg1_lind23:\e
X    :rm=attila:rp=dg1_lind23:
T}
X.TE
X.TS
center box;
lw(2.5i) .
X.L
X.SM
dg1_lind23.forward
X_
T{
X.nf
dg1_lind23.local|dg1:\e
X    :sd=/usr/spool/dg1_lind23:\e
X    :rm=attila:rp=dg1_lind23:
T}
X.TE
X.ce
XFigure 11.4  Sample Printcap Files
X.KE
X.PP
XEach host will have a file containing the names of the entries in
the printcap file.
The
X.L genpc
program will generate a printcap file from the named printer file
by concatenating the printcap information and placing it in a
X.L host.printcap
file.
This file can then be copied to the desired destination.
X.NH 2
Checking Out Exisitng Printcaps and Filters
X.PP
If you have an exisiting printcap file,
you can check it out by using the XPERIMENTAL form
of PLP before you commit to the actual form.
X.IP 1). 3
XFirst,
copy the original
X.L /etc/printcap
file to
X.L /tmp/printcap.<host> .
X.IP 2). 3
Modify the 
X.L /tmp/printcap.<host>
file so that the
X.L /usr/spool
directories in it are modified to be
X.L /tmp
directories.
X.IP 3). 3
Compile the test version of the PLP software;
there is an entry in the makefile,
X.L "make test"
which will do this in an efficient manner.
X.IP 4). 3
Set your 
X.L $path
to use  the test version,
and run
X.L "checkpc -f"
to create the spool direcotories needed by the
X.L /tmp/printcap.<host>
version.
X.IP 4). 3
You can now run a parallel version of the PLP software,
and check out the behaviour of devices and filters.
END_OF_FILE
if test 15498 -ne `wc -c <'doc/PLP/11.t'`; then
    echo shar: \"'doc/PLP/11.t'\" unpacked with wrong size!
fi
# end of 'doc/PLP/11.t'
fi
if test -f 'src/localprinter.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'src/localprinter.c'\"
else
echo shar: Extracting \"'src/localprinter.c'\" \(16055 characters\)
sed "s/^X//" >'src/localprinter.c' <<'END_OF_FILE'
X/***************************************************************************
X * U. Minnesota LPD Software * Copyright 1987, 1988, Patrick Powell
X ***************************************************************************
X * MODULE: localprinter.c
X * local Printer queue job handler
X ***************************************************************************
X * Revision History: Created Wed Jan 13 15:34:42 CST 1988
X * $Log:	localprinter.c,v $
X * Revision 3.1  88/06/18  09:34:24  papowell
X * Version 3.0- Distributed Sat Jun 18 1988
X * 
X * Revision 2.4  88/05/21  10:27:48  papowell
X * Minor editing
X * 
X * Revision 2.3  88/05/19  10:33:53  papowell
X * Fixed open() calls to have a 0 parameter, ie: open(f, perms, 0), where needed
X * 
X * Revision 2.2  88/05/14  10:17:51  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:08:26  papowell
X * PLP: Released Version
X * 
X * Revision 1.5  88/05/09  10:03:18  papowell
X * Revised effects of -h option
X * 
X * Revision 1.4  88/05/05  20:08:11  papowell
X * Added a NOHEADER option that allows user to suppress banner
X * 
X * Revision 1.3  88/03/25  14:59:44  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/05  15:01:02  papowell
X * Minor Corrections,  Lint Problems
X * 
X * Revision 1.1  88/03/01  11:08:31  papowell
X * Initial revision
X * 
X ***************************************************************************/
X#ifndef lint
static char id_str1[] =
X	"$Header: localprinter.c,v 3.1 88/06/18 09:34:24 papowell Exp $ PLP Copyright 1988 Patrick Powell";
X#endif lint
X
X#include "lp.h"
X
char *Setup_filter();			/* setup filter */
static int prjobs;				/* numbers of jobs done */
X
X/**********************************************************************
X * Printinit()
X * 1. set up the state to indicated 0 completed jobs
X * 2. get the printer ready
X **********************************************************************/
Printinit()
X{
X	int n;
X
X	if(Debug>3)log(XLOG_DEBUG,"Printinit: called with prjobs %d", prjobs );
X	n = Print_ready();
X	return( n );
X}
X
X/**********************************************************************
X * Printerror()
X * called when there is an error in the job handling
X * 1. set up the state to indicated 0 completed jobs
X * 2. close the printer
X **********************************************************************/
void
Printerror()
X{
X	if(Debug>3)log(XLOG_DEBUG,"Printerror: called with prjobs %d", prjobs );
X
X	prjobs = 0;
X	Print_close();
X}
X/**********************************************************************
X * Printfinal()
X * called when there is an error in the job handling
X * 1. if there are completed jobs, print the trailer
X * 2. close the printer
X **********************************************************************/
void
Printfinal()
X{
X	if(Debug>3)log(XLOG_DEBUG,"Printfinal: called with prjobs %d", prjobs );
X	/*
X	 * print out trailer on close with a job out
X	 */
X	if( prjobs ){
X		/*
X		 * FQ set means FF needed on open
X		 */
X		if( FQ && FF && *FF ){
X			if(Debug>3)log( XLOG_DEBUG, "Printfinal: FF on final");
X			(void)Print_string( FF );
X		}
X		if( TR && *TR ){
X			/*
X			 * TR is sent out
X			 */
X			if(Debug>2)log( XLOG_DEBUG, "Printfinal: TR '%s'", TR);
X			(void)Print_string( TR );
X		}
X	}
X	prjobs = 0;
X	Print_close();
X}
X
X/**********************************************************************
X * Printjob
X *   1.  First scan extracts information which controls printing
X *   2.  Set any default values not passed
X *   3.  Second scan does the printing.
X * Returns:  JBUSY, JFAIL, JSUCC, JABORT
X * Side effects:  sets information vector  CFparm[].
X **********************************************************************/
Printjob(cfp, q)
X	FILE *cfp;			/* control file */
X	struct queue *q;	/* job entry */
X{
X	int i;				/* ACME Integer, Inc. */
X	char parm[BUFSIZ];	/* holds a line read in */
X	char *arg;			/* control line argument */
X	char opt;			/* control line option */
X	int  jstatus;	    /* job status */
X	int  perms = 'R';	/* file perms */
X	long jobsize;		/* job size */
X
X	if( fseek( cfp, 0L, 0 ) < 0 ){
X		logerr_die(XLOG_INFO, "Printjob: start- fseek failed" );
X	}
X	/*
X	 * set job status
X	 */
X	jstatus = JABORT;	/* default */
X	/*
X	 * initialize the CFparm array, which holds value read from file
X	 */
X	for( i = 0; i < 26; ++i ){
X		CFparm[i][0] = 0;
X	} 
X
X	/*
X	 * read the control file and extract user information
X	 */
X	jobsize = 0;
X	while(fgets( parm, sizeof(parm), cfp )){
X		if( (arg = index(parm, '\n')) == 0 ){
X			log(XLOG_INFO,"Printjob: bad control file (%s), no endline",
X				q->q_name);
X			goto error;
X		}
X		*arg = 0;
X		opt = parm[0];
X		arg = parm+1;
X		if( !isascii(opt) || ! isalnum( opt )){
X			log( XLOG_INFO, "Printjob: bad control file (%s), line('%d'%s)",
X				q->q_name,opt, arg);
X			goto error;
X		}
X		/*
X		 * copy it into the appropriate place if needed
X		 */
X		if( isupper( opt ) ){
X			switch( opt ){
X			case 'U':
X			case 'N': break;
X			default:
X				if( CFparm[opt - 'A'][0] ){
X					log(XLOG_INFO,
X						"Printjob: duplicate %c parm '%s', previous:'%s'",
X						opt, arg, CFparm[opt-'A']);
X					goto error;
X				}
X				if( strlen( arg ) >= MAXPARMLEN ){
X					log(XLOG_INFO,
X						"Printjob: control file %s line too long:'%s'",
X						q->q_name,arg);
X					goto error;
X				}
X				(void)strcpy( CFparm[opt - 'A'], arg );
X				break;
X			}
X		} else if( islower( opt )){
X			if( Job_match( q->q_name, arg) == 0 ){
X				logerr(XLOG_INFO,"Printjob: bad control file '%s' entry '%s'",
X					q->q_name,parm);
X				goto error;
X			}
X			if( stat( arg, &LO_statb ) < 0 ){
X				logerr( XLOG_INFO,"Printjob: cannot stat file %s",arg);
X				goto error;
X			}
X			if( (i = Add_name( arg )) < 0 ){
X				logerr( XLOG_INFO,"Printjob: too many files %s",q->q_name);
X				goto error;
X			}
X			jobsize = jobsize + (LO_statb.st_size + 1023)/1024;
X			if( MX && jobsize > MX ){
X				logerr( XLOG_INFO,"Printjob: job too big %s",q->q_name);
X				goto error;
X			}
X			switch( opt ){
X				case 'f':	/* uses the IF filter */
X				case 'l':
X					break;
X				default:
X					if( Filter_name[opt-'a'] == 0){
X						log( XLOG_INFO,"Printjob: no %c filter",opt);
X						goto error;
X					}
X					break;
X			}
X		}
X	}
X	/*
X	 * Set up any parameters that were not provided to default values
X	 */
X	if( PWIDTH[0] = 0){
X		(void)sprintf( PWIDTH, "%d", PW );
X	}
X	/*
X	 * check permissions
X	 */
X	if( strcmp( &q->q_from, FROMHOST ) ){
X		log(XLOG_INFO,
X			"Printjob: control file origin '%s' and H entry '%s' do not match",
X			&q->q_from, FROMHOST );
X			goto error;
X	}
X	if((Permfile && *Permfile &&
X			!Checkperm(Permfile,FROMHOST,LOGNAME,First_name,&perms,(int *)0,0))
X       ||(XU && *XU &&
X			!Checkperm(XU,FROMHOST,LOGNAME,First_name,&perms,(int *)0,0 ) )){
X		log(XLOG_INFO,
X			"Sorry %s@%s, you don't have permission to use '%s'",
X			LOGNAME, FROMHOST, First_name );
X			goto error;
X	} else if((Permfile && *Permfile &&
X			!Checkperm(Permfile,FROMHOST,LOGNAME,First_name,&perms,(int *)0,1))
X       ||(XU && *XU &&
X			!Checkperm(XU,FROMHOST,LOGNAME,First_name,&perms,(int *)0,1 ) )){
X		log( XLOG_INFO, "Sorry %s@%s, no more pages allowed on '%s'",
X			LOGNAME, FROMHOST, First_name );
X			goto error;
X	}
X	/*
X	 * See if there are any files to print
X	 */
X	if( Parmcount == 0 ){
X		/* no files */
X		if(Debug>4)log(XLOG_DEBUG,"Printjob: no files");
X		jstatus = JSUCC;
X		goto error;
X	}
X	/*
X	 * Pass 2: Do the printing now
X	 */
X	if( fseek(cfp, 0L, 0) < 0 ){
X		/* this is impossible */
X		logerr( XLOG_NOTICE, "Printjob: fseek %s failed",q->q_name);
X		goto error;
X	}
X	if( QH ){
X		/*
X		 * queuejob returns one of the Job Status settings
X		 */
X		jstatus = queuejob(cfp, q);
X		goto error;
X	}
X	/*
X	 * Put out FF on open and between jobs
X	 */
X	if( prjobs == 0 ){
X		/*
X		 * FO set means FF needed on open
X		 */
X		if( LD && *LD ){
X			if(Debug>3)log( XLOG_DEBUG, "Printjob: putting out LD on open");
X			jstatus = Print_string( LD );
X			if( jstatus != JSUCC ){
X				log( XLOG_INFO, "Printjob: LD on open printing failed" );
X				goto error;
X			}
X		}
X		if( FO && FF && *FF ){
X			if(Debug>3)log( XLOG_DEBUG, "Printjob: putting out FF on open");
X			jstatus = Print_string( FF );
X			if( jstatus != JSUCC ){
X				log( XLOG_INFO, "Printjob: FF on open printing failed" );
X				goto error;
X			}
X		}
X		prjobs = 1;
X	} else if( SF == 0 && FF && *FF ){
X		if(Debug>3)log(XLOG_DEBUG,"Printjob: putting out FF between jobs");
X		jstatus = Print_string( FF );
X		if( jstatus != JSUCC ){
X			log( XLOG_INFO, "Printjob: FF printing failed" );
X			goto error;
X		}
X	}
X	/*
X	 * print banner
X	 * if it has not been disabled by the SH flag
X	 * or the lpr -h flag was used and the AB (always banner) is clear
X	 */
X	if( !(SH || (NOHEADER[0] && !AB)) ){
X		jstatus = Print_banner();
X		if( jstatus != JSUCC ){
X			log( XLOG_INFO, "Printjob: banner printing failed" );
X			goto error;
X		}
X		prjobs = 1;
X	}
X	/*
X	 * Banner Printing Program
X	 */
X	if( BP && *BP ){
X		jstatus = Banner_print(BP);
X		if( jstatus != JSUCC ){
X			log( XLOG_INFO, "Printjob: BP program %s failed", BP);
X			goto error;
X		}
X		prjobs = 1;
X	}
X	/*
X	 * print individual jobs
X	 */
X	while(fgets( parm, sizeof(parm), cfp )){
X		if( (arg = index(parm, '\n')) == 0 ){
X			log( XLOG_INFO,"Printjob: bad control file format (%s), no endline",
X				q->q_name);
X			goto error;
X		}
X		*arg = 0;
X		opt = parm[0];
X		arg = parm+1;
X		if( opt == 0 || ! isalnum( opt )){
X			log( XLOG_INFO, "bad control file (%s), line(%s)",
X				q->q_name,parm);
X			goto error;
X		}
X		if( islower( opt ) ){
X			/*
X			 * print the file
X			 */
X			prjobs = 1;
X			jstatus = printfile( opt, arg );
X			if( jstatus != JSUCC ){
X				goto error;
X			}
X		}
X	}
X	/*
X	 * End Printing Program
X	 */
X	if( EP && *EP ){
X		jstatus = Banner_print(EP);
X		if( jstatus != JSUCC ){
X			log( XLOG_INFO, "Printjob: EP program %s failed", EP);
X			goto error;
X		}
X		prjobs = 1;
X	}
X
X	/*
X	 * error and status reporting
X	 */
error:
X	if( MAILNAME[0] ){
X		sendmail(q, jstatus);
X	}
X	if(Debug>3)log(XLOG_DEBUG,"Printjob: '%s' status %d",q->q_name,jstatus);
X	return (jstatus);
X}
X
X/***********************************************************************
X * printfile( int format; char *datafile )
X *   1. determine the format and corresponding filter command
X *   2. if 'p' format, set up pr process to format output
X *   3. output to Printer
X * Returns: JFAIL if retry, JSUCC if success, JABORT if ugly
X ***********************************************************************/
static int
printfile(format, file)
X	int format;
X	char *file;
X{
X	int dfd;			/* data file fd */
X	int status;			/* return status */
X	char *filter;		/* program Name */
X	int nofilter = 0;	/* no filter, just copy */
X	char buf[BUFSIZ];	/* hold the Printer command */
X	int p[2];			/* pipe file descriptors */
X	int prchild;		/* Printer process */
X
X	if(Debug>3)log( XLOG_DEBUG, "printfile: format %c, file %s", format, file);
X	/*
X	 * Open input file
X	 */
X	if ((dfd = open_daemon(file, O_RDONLY, 0)) < 0) {
X		logerr( XLOG_NOTICE,"printfile: open failed '%s'", file);
X		return(JABORT);
X	}
X	/*
X	 * find filter chain to be generated
X	 */
X	switch (format) {
X	/*
X	 * use the filter Name tagged by 'Xf', where X is format
X	 */
X	default:
X		filter = Setup_filter( format, Filter_name[format-'a']);
X		break;
X	/*
X	 * 'f' and 'l' formats use the IF filter, and OF if not present
X	 */
X	case 'f':	/* default */
X	case 'l':	/* ignore control */
X	case 'p':	/* print file using 'pr' */
X		if( IF == 0 || *IF == 0){
X			/*
X			 * you have to use the OF filter; we don't set up a filter
X			 */
X			nofilter = 1;
X		} else {
X			filter = Setup_filter( 'f', IF);
X		}
X		if( format != 'p' ){
X			break;
X		}
X		/*
X		 * create a process to invoke 'pr'
X		 * first, set up the pr command
X		 */
X		(void)sprintf(buf, "%s -w%d -l%d %s %s",
X			PR, PWIDTH, PL, PRTITLE[0]?"-h":"", PRTITLE);
X		if(Debug>3)log( XLOG_DEBUG, "printfile: pr command '%s'", buf);
X		/*
X		 * create PR process
X		 */
X		if( pipe(p) < 0 ){
X			logerr_die( XLOG_NOTICE, "printfile: cannot make pipe" );
X		}
X		/*
X		 * make a pipe, fork PR process
X		 * Run this process as DAEMON
X		 */
X		if ((prchild = fork()) == 0) {	/* child */
X			if( dup2(dfd, 0) < 0		/* file is stdin */
X			 || dup2(p[1], 1) < 0 ){	/* pipe stdout */
X				logerr_die( XLOG_NOTICE, "printfile: dup2 failed, PR process" );
X			}
X			/* set the uid to be safe */
X			if( geteuid() == 0 && setreuid( Daemon_uid, Daemon_uid ) < 0 ){
X				logerr_die( XLOG_INFO, "printfile: setreuid failed" );
X			}
X			mexecv(buf);
X			logerr_die( XLOG_NOTICE,"printfile: cannot execv %s", buf);
X		} else if (prchild < 0) {
X			logerr_die( XLOG_NOTICE,"printfile: fork for pr failed");
X		}
X		(void) close(p[1]);		/* close output side */
X		(void) close(dfd);
X		dfd = p[0];	/* use pipe for input */
X		break;
X	}
X	/*
X	 * start filter
X	 */
X	if( nofilter ){
X		status = Print_copy( dfd );
X	} else if (filter == 0 || *filter==0) {
X		log( XLOG_INFO,"printfile: no %c filter, file %s", format,file);
X		status = JABORT;
X	} else {
X		/*
X		 * start filter up
X		 */
X		if(Debug>0)log( XLOG_DEBUG,
X			"printfile: format %c, file %s, filter %s", format,file,filter);
X		status = Print_filter( dfd, filter );
X	}
X	(void)close( dfd );
X	return( status );
X}
X
X/********************************************************************
X * Banner_print( char *prog)
X * Print the banner using the user specified program
X * 1. setup the filter
X * 2. start program
X * 3. wait for completion.
X ********************************************************************/
Banner_print( prog )
X	char *prog;
X{
X	char *filter;
X	int status;
X
X	if(Debug>3)log( XLOG_DEBUG, "Banner_print %s", prog);
X	filter = Setup_filter( 'f', prog);
X	if (filter == 0 || *filter==0) {
X		log( XLOG_INFO,"Banner_printer: bad program %s", prog );
X		status = JABORT;
X	} else {
X		/*
X		 * start filter up
X		 */
X		if(Debug>3)log( XLOG_DEBUG, "Banner_print: filter %s", filter);
X		status = Print_filter( 0, filter );
X	}
X	return( status );
X}
X/********************************************************************
X * queuejob()
X * Use the user specified Queue Handler.
X * exec'd as `qh -PPrinter -B[nsl] control_file'.
X *  exit codes are used to indicate the different success:
X *   0 - successful; 1 retry; anything else- abandon
X * Returns: JSUCC, etc.
X * NOTE: the queue handler is invoked with the control file as
X *  stdin and the Printer as stdout.
X ********************************************************************/
X
queuejob(cfp, q)
X	FILE *cfp;				/* control file */
X	struct queue *q;		/* queue entry */
X{
X	union wait status;
X	int id, pid, ret;
X	char buf[BUFSIZ];
X
X	/*
X	 * set up arguments
X	 */
X	(void)sprintf(buf, "%s %s", QH, Printer, q->q_name);
X	if(Debug>0)log( XLOG_DEBUG,"queuejob: %s", buf);
X	/*
X	 * Open the Printer
X	 */
X	Print_open();
X	if( (pid = fork()) == 0 ){	/* child */
X		if( dup2(fileno(cfp), 0) < 0 ){	/* stdin is cf */
X			logerr_die( XLOG_NOTICE, "queuejob: dup2 failed" );
X		}
X		if( dup2(Print_fd, 1) < 0 ){	/* stdin is cf */
X			logerr_die( XLOG_NOTICE, "queuejob: dup2 failed" );
X		}
X		if( geteuid() == 0 && setreuid( Daemon_uid, Daemon_uid ) < 0 ){
X			logerr_die( XLOG_INFO, "queuejob: setreuid failed" );
X		}
X		mexecv(buf);
X		logerr_die( XLOG_INFO, "queuejob: exec failed" );
X	} else if( pid < 0 ){
X		logerr_die( XLOG_INFO, "queuejob: fork failed" );
X	}
X	/*
X	 * wait for process
X	 */
X	if(Debug>0)log( XLOG_DEBUG, "waiting for queuejob %d", pid );
X	while ((id = wait(&status) ) > 0 && pid!=id){
X		if(Debug>3)log(XLOG_DEBUG,"queuejob: caught %d, %s", id,
X			Decode_status(&status) );
X	}
X	if(Debug>0)log( XLOG_DEBUG, "queuejob: pid %d status %s", id,
X		Decode_status(&status ) );
X	if( id < 0 || status.w_stopval != 0 || (unsigned)status.w_retcode > 1 ){
X		logerr( XLOG_INFO, "queuejob process %d failed, status (%s)",
X			id, Decode_status(&status));
X		ret = JABORT;
X	} else if( status.w_retcode == 1 ){
X		ret = JFAIL;
X	} else {
X		ret = JSUCC;
X	}
X	return (ret);
X}
END_OF_FILE
if test 16055 -ne `wc -c <'src/localprinter.c'`; then
    echo shar: \"'src/localprinter.c'\" unpacked with wrong size!
fi
# end of 'src/localprinter.c'
fi
if test -f 'src/lpr_parms.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'src/lpr_parms.c'\"
else
echo shar: Extracting \"'src/lpr_parms.c'\" \(15634 characters\)
sed "s/^X//" >'src/lpr_parms.c' <<'END_OF_FILE'
X/***************************************************************************
X * U. Minnesota LPD Software * Copyright 1987, 1988, Patrick Powell
X ***************************************************************************
X * MODULE: lpr_parms.c
X * get the parameters for lpr program
X ***************************************************************************
X * Revision History: Created Mon Jan 25 17:29:45 CST 1988
X * $Log:	lpr_parms.c,v $
X * Revision 3.1  88/06/18  09:35:00  papowell
X * Version 3.0- Distributed Sat Jun 18 1988
X * 
X * Revision 2.4  88/05/25  15:42:37  papowell
X * No header flag modification
X * 
X * Revision 2.3  88/05/19  09:00:18  papowell
X * Fixed lint unused variables
X * 
X * Revision 2.2  88/05/14  10:18:40  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:23  papowell
X * PLP: Released Version
X * 
X * Revision 1.8  88/05/09  10:03:47  papowell
X * Revised effects of -h option
X * 
X * Revision 1.7  88/05/05  20:08:45  papowell
X * Added a NOHEADER option that allows user to suppress banner
X * 
X * Revision 1.6  88/04/07  12:31:53  papowell
X * Modified to use Getopt
X * 
X * Revision 1.5  88/04/06  12:13:46  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.4  88/03/25  15:00: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.3  88/03/11  19:28:41  papowell
X * Minor Changes, Updates
X * 
X * Revision 1.2  88/03/05  15:01:51  papowell
X * Minor Corrections,  Lint Problems
X * 
X * Revision 1.1  88/03/01  11:08:50  papowell
X * Initial revision
X * 
X ***************************************************************************/
X#ifndef lint
static char id_str1[] =
X	"$Header: lpr_parms.c,v 3.1 88/06/18 09:35:00 papowell Exp $ PLP Copyright 1988 Patrick Powell";
X#endif lint
X
X#include "lpr.h"
X
X/***************************************************************************
X * Setup_parms( int argc; char **argv )
X * 1. get the parameters;
X * 2. set up the get the printcap entry
X * 3. check to see if any parameters violate the printcap restrictions
X * 4. get the sequence number
X ***************************************************************************/
X
Setup_parms( argc, argv )
X	int argc;
X	char **argv;
X{
X	/*
X	 * get the parameters
X	 */
X	Get_parms( argc, argv );
X	/*
X	 * print the parameters passed
X	 */
X	if(Debug>4)Show_parms();
X	/*
X	 * get the printcap entry
X	 */
X	Get_Printer(1);
X	/*
X	 * check authorizations
X	 */
X	Can_use();
X	/*
X	 * check consistency of parameters
X	 */
X	Check_parms();
X	/*
X	 * get the sequence number
X	 */
X	Get_sequence();
X	if(Debug>4)Show_parms();
X}
X 
X/***************************************************************************
X * Get_parms( int argc; char **argv )
X * 1. Scan the argument list and get the flags
X ***************************************************************************/
X
static char *optstr = "#:C:D:F:J:P:R:T:U:XZ:bcdfghi:lm?nprstvw:";
Get_parms( argc, argv )
X	int argc;
X	char **argv;
X{
X	int option;
X	int i;
X
X	while( (option = Getopt(argc,argv,optstr)) != EOF ){
X		switch( option ){
X		case '#':
X			Check_int_dup( option, &Copies, Optarg );
X			break;
X		case 'C':
X			Check_str_dup( option, CLASSNAME, Optarg );
X			break;
X		case 'D':
X			Check_int_dup( option, &Debug, Optarg );
X			break;
X		case 'F':
X			if( strlen( Optarg ) != 1 ){
X				Diemsg( "bad -F format string '%s'\n",Optarg);
X			}
X			if( Format ){
X				Diemsg( "duplicate format specification -F%s\n", Optarg);
X			} else {
X				Format = *Optarg;
X			}
X			break;
X		case 'J':
X			Check_str_dup( option, JOBNAME, Optarg );
X			break;
X		case 'P':
X			if( Printer ){
X				Check_str_dup( option, Printer, Optarg );
X			}
X			if( *Optarg == 0 ){
X				Diemsg( "missing printer name in -P option\n" );
X			}
X			Printer = Optarg;
X			break;
X		case 'R':
X			Check_str_dup( option, ACCNTNAME, Optarg );
X			break;
X		case 'T':
X			Check_str_dup( option, PRTITLE, Optarg );
X			break;
X		case 'U':
X			Root_only( option );
X			Check_str_dup( option, BNRNAME, Optarg );
X			(void)strcpy( LOGNAME, Optarg );
X			break;
X		case 'X':
X			Check_dup( option, &Exper );
X#			ifdef DEBUG
X				Setup_test();
X				Tailor_names();
X#			else
X				Diemsg( "-X not allowed" );
X#			endif DEBUG
X			break;
X		case 'Z':
X			Check_str_dup( option, CLASSNAME, Optarg );
X			break;
X		case 'b':
X			Check_dup( option, &Binary );
X			break;
X		case 'h':
X			Check_dup( option, &Noheader );
X			/*
X			 * set the NOHEADER flag for lpd
X			 */
X			NOHEADER[0] = 'X';
X			break;
X		case 'i':
X			Check_str_dup( option, INDENT, Optarg );
X			break;
X		case 'm':
X			/*
X			 * -m[Mailname]
X			 */
X			if( Optarg == 0 ){
X				Check_str_dup( option, MAILNAME, Person );
X				(void)sprintf(MAILNAME,"%s@%s",Person,Host);
X			} else {
X				Check_str_dup( option, MAILNAME, Optarg );
X			}
X			break;
X		case 'r':
X			Check_dup( option, &Remove );
X			break;
X		case 's':
X			Check_dup( option, &Use_links );
X			break;
X		case 'c':
X		case 'd':
X		case 'f':
X		case 'g':
X		case 'l':
X		case 'n':
X		case 'p':
X		case 't':
X		case 'v':
X			if( Format ){
X				Diemsg( "duplicate format specification -%c\n", option);
X				exit( 1 );
X			} else {
X				Format = option;
X			}
X			break;
X		case '?':
X			break;
X		case 'w':
X			Check_str_dup( option, PWIDTH, Optarg );
X			i = atoi( PWIDTH );
X			if( i <= 0 ){
X				Diemsg( "-w <width>, width value '%s' bad", PWIDTH );
X				exit( 1 );
X			}
X			(void)sprintf( PWIDTH, "%d", i );
X			break;
X		default:
X			fatal(XLOG_INFO, "Get_parms: badparm %c", option );
X		}
X	}
X
X	/*
X	 * set up the Parms[] array
X	 */
X	for( ; Optind < argc; ++Optind ){
X		if( Parmcount < MAXPARMS ){
X			Parms[Parmcount].str = argv[Optind];
X			++Parmcount;
X		} else {
X			Diemsg( "too many files to print; break job up" );
X		}
X	}
X	/*
X	 * set default format
X	 */
X	if( Format == 0 ){
X		Format = 'f';
X	}
X	if( FROMHOST[0] == 0 ){
X		(void)strcpy(FROMHOST, Host);
X	}
X}
X
X/***************************************************************************
X * Check_int_dup( int option, int *value, char *arg )
X * 1.  check to see if value has been set
X * 2.  if not, then get integer value from arg
X ***************************************************************************/
X 
Check_int_dup( option, value, arg )
X	int option;
X	int *value;
X	char *arg;
X{
X	if( *value ){
X		Diemsg( "duplicate option %c", option );
X	}
X	if( sscanf( arg, "%d", value ) != 1 || *value <= 0){
X		Diemsg( "option %c parameter (%s) is not positive integer",
X			option, arg);
X	}
X}
X/***************************************************************************
X * Check_str_dup( int option, char *value, char *arg )
X * 1.  check to see if value has been set
X * 2.  if not, then set it
X ***************************************************************************/
Check_str_dup( option, value, arg )
X	int option;
X	char *value;
X	char *arg;
X{
X	if( *value ){
X		Diemsg( "duplicate option %c", option );
X	}
X	if( strlen( arg ) > MAXPARMLEN ){
X		Diemsg( "option %c arguement too long (%s)", option, arg );
X	}
X	(void)strcpy(value, arg );
X}
X/***************************************************************************
X * Check_dup( int option, int *value )
X * 1.  check to see if value has been set
X * 2.  if not, then set it
X ***************************************************************************/
Check_dup( option, value )
X	int option;
X	int *value;
X{
X	if( *value ){
X		Diemsg( "duplicate option %c", option );
X	}
X	*value = 1;
X}
X/***************************************************************************
X * Root_only( int option );
X * 1.  check to see if root
X ***************************************************************************/
Root_only( option )
X	int option;
X{
X	if( Is_root == 0 ){
X		Diemsg( "option %c can be used only by root", option );
X	}
X}
X/***************************************************************************
X * Can_use()
X * Check for permissions and priority
X * 1. RG - restrict access by group: must be in group
X * 2. printcap: check for restrictions
X * 3. XU: check for restrictions
X ***************************************************************************/
Can_use()
X{
X	int prior;		/* find the max priority */
X	int op;	/* 'R' for lpr */
X	char buf[BUFSIZ];
X	char *pf;		/* XU perm file */
X
X	/*
X	 * get the full path name
X	 */
X	pf = XU;
X	if( pf && *pf && pf[0] != '/' ){
X		(void)sprintf( buf, "%s/%s", SD, pf );
X		pf = buf;
X	}
X	/*
X	 * check for priority
X	 */
X	Priority = CLASSNAME[0];
X	if( Priority == 0 ){
X		Priority = 'Z';
X	}
X	if( !isascii(Priority) || !isupper(Priority) ){
X		Priority = 'Z';
X		Warnmsg( "Priority set to %c", Priority );
X	}
X	/*
X	 * check to see if we have access restricted by group perms
X	 */
X	if( !Is_root && RG && *RG && !Checkgrp( Person,RG ) ){
X		Diemsg( "Sorry %s@%s, you don't have permission to use the %s",
X			Person, Host, Printer );
X	}
X	/*
X	 * check to see if we have restricted access
X	 */
X	prior = Priority;
X	op = 'R';	/* able to use lpr */
X	if((Permfile && *Permfile
X		&& !Checkperm(Permfile,Host,Person,First_name,&op,(int *)0,0))
X		||(pf && *pf
X			&& !Checkperm(pf,Host,Person,First_name,&op,(int *)0,0 ) )){
X		Diemsg( "Sorry %s@%s, you don't have permission to use '%s'",
X			Person, Host, Printer );
X	}
X	if((Permfile && *Permfile
X			&& !Checkperm(Permfile,Host,Person,First_name,&op,&prior,1 ))
X		||(pf && *pf
X			&& !Checkperm(pf,Host,Person,First_name,&op,&prior,1 ) )){
X		Diemsg( "Sorry %s@%s, no more pages allowed on '%s'",
X			Person, Host, Printer );
X	}
X	/*
X	 * now check to see if you have not exceeded your page limits
X	 */
X	if( prior > Priority ){
X		Warnmsg( "maximum Priority allowed is %c", prior );
X		Priority = prior;
X	}
X	if(Debug>2)log(XLOG_DEBUG,"Can_use: %s can use %s, priority %c",
X		Person, Printer, Priority );
X}
X
X/***************************************************************************
X * Checkgrp( name, list )
X * -- check to see if person is a member of one of the groups
X * Returns: 1 if  person is a member, 0 if not
X ***************************************************************************/
X
Checkgrp( name, list )
X	char *name, *list;
X{
X	char buf[BUFSIZ];
X	char *cp, *bp;
X	struct group *gr;
X	char **grplist;
X
X	if(Debug>4)log(XLOG_DEBUG,"Checkgrp: checking for %s in %s", name, list );
X	cp = list;
X	while( cp && *cp ){
X		for( bp = buf; *cp && (*bp = *cp) && (*bp != ','); ++bp, ++cp );
X		*bp = 0;
X		if( *cp ){
X			++cp;
X		}
X		if(Debug>5)log(XLOG_DEBUG,"Checkgrp: checking group %s", buf );
X		if( gr = getgrnam(buf) ){
X			for( grplist = gr->gr_mem; *grplist; ++grplist ){
X				if( strcmp( name, *grplist ) == 0 ){
X					if(Debug>4)log(XLOG_DEBUG,"Checkgrp: %s in %s",
X						name, gr->gr_name );
X					return(1);
X				}
X			}
X		}
X	}
X	if(Debug>4)log(XLOG_DEBUG,"Checkgrp: %s not in any group" );
X	return( 0 );
X}
X/***************************************************************************
X * Check_parms()
X *	Check for parameter consistency
X *  1. Check to see if the format is allowed
X *  2. Check on the multiple copies
X ***************************************************************************/
Check_parms()
X{
X	char *msg;
X	/* check format and options */
X	if( FX && *FX && index( FX, Format ) == 0 ){
X		msg=NULL;
X		switch(Format){
X		case 'f': msg = "Normal or plain files";	break;
X		case 't': msg = "Troff files, use -Fn for Ditroff";	break;
X		case 'n': msg = "Ditroff files, use -Ft for (old) troff files";break;
X		case 'v': msg = "Varian raster images";		break;
X		case 'd': msg = "TeX intermediate files (DVI)";	break;
X		case 'g': msg = "Plot intermediate files";	break;
X		case 'c': msg = "Cifplot intermediate files";	break;
X		default:  msg = "format 'X' files"; msg[8]=Format;
X		}
X		Diemsg("Printer %s does not know how to interpret %s\n", Printer, msg);
X	}
X	if( SC && Copies > 1){
X		Warnmsg("multiple copies are not allowed");
X		Copies = 0;
X	}
X	if(MC > 0 && Copies > MC){
X		Warnmsg("only %d copies are allowed", MC);
X		Copies = MC;
X	}
X	if( Remove && !Is_root
X		&& (LN == 0 || *LN == 0 || !Checkgrp( Person, LN ))){
X		Warnmsg( "-r (remove) not allowed" );
X		Remove = 0;
X	}
X#ifdef NOSYMLINK
X	if( Use_links ){
X		Warnmsg("-s (symbolic links) disabled");
X		Use_links = 0;
X	}
X#else
X	if( Use_links ){
X		/*
X		 * check to see if we are a member of the right group
X		 */
X		if( !Is_root && (LN == 0 || *LN == 0 || !Checkgrp( Person, LN ) )){
X			Warnmsg("-s (symbolic links) not allowed by user %s", Person);
X			Use_links = 0;
X		} else if( RM && NW ){
X			Warnmsg("-s (symbolic links) not available for this queue" );
X			Use_links = 0;
X		}
X	}
X#endif NOSYMLINK
X	if( Remove && !Use_links ){
X		Warnmsg( "-r (remove) not allowed without -s" );
X		Remove = 0;
X	}
X}
X
X/***************************************************************************
X * Get_sequence()
X * Get the job sequence number
X * 1. Check to see if queuing is enabled
X * 2. Get the job number from the .job file
X ***************************************************************************/
X
Get_sequence()
X{
X	char buf[MAXPATHLEN];		/* holds the pathname */
X	FILE *fp;				/* for sequence number */
X	int i;					/* waiting time */
X
X	/*
X	 * check to see if printing is enabled
X	 */
X	if( LO == 0 || *LO == 0 || SD == 0 || *SD == 0 ){
X		fatal( XLOG_CRIT, "Get_sequence: bad printcap entry" );
X	}
X	if( LO[0] == '/' ){
X		(void)strcpy( buf, LO );
X	} else {
X		(void)sprintf( buf, "%s/%s", SD, LO );
X	}
X	/*
X	 * get the sequence file name
X	 */
X	(void)sprintf( buf, "%s/.seq.%s", SD, Host );
X	if(Debug>3)log(XLOG_DEBUG,"sequence file name '%s'", buf );
X	/*
X	 * lock the sequence file and get a new number
X	 */
X	for( i = 0;
X		(fp = Getlockfile( buf, &Job_number,(char *)0,0,&LO_statb )) == NULL
X			&& i < 3;
X		++i ){
X		sleep( (unsigned)(i+ (getpid()&1) ) );
X	}
X	if( fp == NULL ){
X		Diemsg("cannot lock sequence file %s, try later (%s)", buf,
X			Errormsg( errno ) );
X	}
X	if( !Is_root && (LO_statb.st_mode & DISABLE_QUEUE) ){
X		Diemsg( "printer %s- queueing disabled", Printer );
X	}
X	/*
X	 * set the sequence number to the new value mod 1000;
X	 */
X	Job_number = (Job_number+1) % 1000;
X	Setlockfile( buf, fp, Job_number, Time_str() );
X	(void)fclose(fp);
X	if(Debug>4)log(XLOG_DEBUG, "Get_sequence: number %d", Job_number);
X}
X
X/***************************************************************************
X * Show_parms()
X * Display the values of the parameters that were read.
X * 1. Print the CFparm array
X * 2. Print the other parameters
X ***************************************************************************/
X
Show_parms()
X{
X	int i;
X	char *s;
X
X	/*
X	 * CFparm first:
X	 */
X	(void)fprintf(stderr,"CFparm:\n");
X	for( i = 'A'; i <= 'Z'; ++i ){
X		s = CFparm[i-'A'];
X		if( s[0] ){
X			(void)fprintf(stderr," %c  '%s'\n", i, s );
X		}
X	}
X	(void)fprintf(stderr, " Format: %c\n",  Format );
X	(void)fprintf(stderr, " Copies: %d\n",  Copies );
X	(void)fprintf(stderr, " Binary: %d\n",  Binary );
X	(void)fprintf(stderr, " Use_links: %d\n",  Use_links );
X	(void)fprintf(stderr, " Exper: %d\n",  Exper );
X	(void)fprintf(stderr, " Priority: %d\n",  Priority );
X	(void)fprintf(stderr, " Job_number: %d\n",  Job_number );
X	if( Read_stdin ){
X		(void)fprintf(stderr, " Read_stdin: %s\n",  Read_stdin );
X	}
X	if( Filter_out ){
X		(void)fprintf(stderr, " Filter_out: %s\n",  Filter_out );
X	}
X	(void)fprintf(stderr, " Temp_count: %d\n",  Temp_count );
X	(void)fprintf(stderr, " Temp_max: %d\n",  Temp_max );
X	for( i = 0; i < Temp_count; ++i ){
X		s  = Temp_file[i];
X		(void)fprintf(stderr," %d  '%s'\n", i, s );
X	}
X}
END_OF_FILE
if test 15634 -ne `wc -c <'src/lpr_parms.c'`; then
    echo shar: \"'src/lpr_parms.c'\" unpacked with wrong size!
fi
# end of 'src/lpr_parms.c'
fi
echo shar: End of archive 11 \(of 16\).
cp /dev/null ark11isdone
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