v16i020: Public lineprinter spooler package, Part07/16

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


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

#! /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 7 (of 16)."
# Contents:  doc/PLP/06.t doc/PLP/07.t src/checkpc.c
#   src/remoteprinter.c src/startprinter.c
# Wrapped by papowell at attila on Wed Aug 10 10:44:57 1988
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f 'doc/PLP/06.t' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'doc/PLP/06.t'\"
else
echo shar: Extracting \"'doc/PLP/06.t'\" \(10628 characters\)
sed "s/^X//" >'doc/PLP/06.t' <<'END_OF_FILE'
X.ig
X$Header: 06.t,v 1.1 88/05/21 18:39:41 papowell Locked $
X$log$
X..
X.NH 1
Local Spool Queues and Servers
X.PP
The 
X.I lpd
process
handles the unspooling process for local and remote spool queues in
much the same manner.
X.I Lpd
forks a server process to unspool entries from a queue.
The server (or unspooler) process checks the spool queue lock file to see if
unspooling is enabled,
sorts jobs according to priority,
and then takes printing actions as specified by the
printcap entry for the spool queue.
In order to provide fine control over the printing process,
the unspooler forks a set of filter processes
based on information in the printcap entry to handle specialized printer
requirements.
These filter processes are used to:
X.IP 1). 3
Provide control over device dependencies,
above that allowed by the simple serial line control functions.
X.IP 2). 3
Print banners or job separator information.
X.IP 3). 3
Provide specific processing for a particular job format.
X.IP 4). 3
Provide accounting information.
X.PP
Different classes of output devices require different amounts or kinds of
filter support.
The following sections outline the different options
and the filter support provided for them.
X.NH 2
Job Format and Filter Selection
X.PP
Associated with each data file of a job is a unspooling format.
When unspooling a job,
the server uses this format to select a filter to be used to process
the data file.
By convention,
the format used for printing a job is specified by
a lower case letter (a\-z),
and the corresponding filter for the format is specified by
the printcap field
x\c
X.B f,
where x represents the format.
This is not uniformly true,
as the
X.B af
X(accounting file name),
X.B lf
X(log file name),
and
X.B ff
X(form feed string)
entries are used for other purposes.
In Figure 6.1,
X.B af
specifies the accounting file,
X.B lf
is the log file,
and
X.B of ,
X.B if ,
and
X.B tf
are filter programs.
X.KF
X.DT
X.nf
X.SM
X.L
X.in +1i
X# Versatec Printer, Lind 33
X#   Uses the new filters
versatec_lind33\||\|versatec:\e
X	:fx=flpdt:mx#2000:\e
X	:lp=/dev/va0:sd=/usr/spool/versatec_lind33:\e
X	:af=vaacct:\e
X	:lf=logfile:\e
X	:of=/usr/lib/vpf:\e
X	:if=/usr/lib/vpf:\e
X	:df=/usr/lib/vpf:\e
X	:tf=/usr/lib/rvcat:
X.in -1i
X.LG
X.R
X.ce
XFigure 6.1.  Local Printer Printcap Entry
X.KE
X.NH 2
No Filter Support Specified
X.PP
If no output filters are specified,
the server opens the output device,
sets the serial line characteristics if it is a serial line,
and prints directly to the output device.
X.NH 2
Banners and Separators
X.PP
By default,
jobs are separated by a banner page or separator page that is generated by the
server process.
The default banner is a single page,
with the user name and job information printed in large letters.
The
X.B sb
X(short banner)
option specifies a single line banner of the following form:
X.nf
X.ti +5
X.L "[user]:[host] Job: [jobname] Date: [date]"
X.ti +5
X.L "papowell:attila.cs.umn.edu Job: (stdin) Date: Fri May 20 11:29:05 1988"
X.fi
X.PP
The
X.B sh
X(suppress header)
flag suppress banner printing.
The
X.I lpr
no header option 
X(\-h)
allows the user to request no header or banner for the job;
the
X.B ab
X(always print banner) printcap flag
causes the server to ignore the no banner request.
X.PP
Consecutive printer jobs are normally separated by a form feed;
the default (c
X.B \ef )
can be changed by specifying a value for the
X.B ff
X(form feed string) field.
The
X.B sf
X(suppress form feeds)
can be used to suppress any printing of form feeds between jobs.
When the printer is started,
it may be necessary to initialize the printer by sending some additional
information.
The
X.B fo
X(form feed on open) flag specifies that the
X.B ff
string is printed before the first job,
and the
X.B fq
X(form feed on quitting)
flag specifies that a form feed is printed after the last job.
In addition,
X.B ld
X(leader on open) specifies a string to be printed before the
X(optional) intial form feed
and the
X.B tr
X(trailer) specifies a string to be printed after the
the (optional) final form feed.
The
X.B ld
and
X.B tr
strings are useful for specifying an escape sequence that sets up
form length, etc.
X.PP
In addition to the built in banner printer,
the
X.B bp
X(banner printer)
and
X.B ep
X(end printer)
fields can be used to specify banner and trailer printing programs.
These programs are invoked to print banners or other information after the
built in banner or separator has been printed.
Custom banner printing may be done by suppressing built in banners with
X.B sh
and
X.B sf
and using the
X.B bp
and
X.B ep
entries.
X.NH 2
Simple OF and IF Filter Support
X.PP
The
X.B OF
X(output filter)
specified by the
X.B of
field is used by the server to
print banners and provide a simple filter action for devices that
need a minmum amount of control.
The OF filter
is not intended to perform accounting since it is started only once
and no provision is made for passing
owners' login name,
identifying the begining and ending of jobs,
etc.
X.PP
The OF filter is started when the server discovers that it has a
job to print.
The server will open the output device,
do any line control operations,
and then start the OF filter.
Banner and job separator strings will be sent to the
OF filter,
which filters them and sends them to the output device.
In order to use other filters,
the server will request the OF
filter to suspend itself by sending it the two character sequence
X\e031\e001 or ESC ^A.
The OF filter should then suspend itself by using a
X.L "kill(0,SIGSTOP)" .
The server will wait for this event,
and then start up other filters.
After they have completed,
the server will signal the OF filter to continue by using
X.L "kill(OF_pid,SIGCONT)" .
X.PP
The IF filter
specified by the
X.B if
field is used to format jobs with the
X.B f
format,
which is for ordinary textual output.
The
X.I lpr
program will use 
X.B f
format by default if no format is specified,
and also for printing literal output
X(lpr \-l option)
or
X.I pr
output (lpr \-p option).
The IF filter is expected to do formatting and update an accounting file.
If there is no IF filter and an
X.B f
format job is printed,
it is filtered through the
X.B OF
filter.
If there is no OF filter,
then the printer will copy the file directly to the output device.
X.NH 2
Non-standarstandard Formats and Filters
X.PP
The
X.B lpr
program allows the user to specify a job format;
the
X.B f
format is the default format for text files.
The
X.B fx
printcap field specifies the formats allowed on the printer;
the default permitted formats are
X.L "f, l,"
and
X.L "p" .
The
X.B lpr
program checks to see if the requested format is allowed when
it spools a job.
XEach format must have a corresponding filter,
which is used to process data files of the specified format.
Note that these filters may be invoked once per data file,
or the entire set of data files may be combined into a single file
and passed through a single invocation of the filter.
Usually the effects of doing this are indistinguishable,
but some filters will cause an alignment of printer media
to be done for each invocation.
This is an implementation dependent phenomina.
X.PP
The commonly available set of formats is specified in the
X.I lpr
man page.
The
X.I "f"
X(default),
X.I "l"
X(literal),
and
X.I p
X(use the ``pr'' program to format output)
formats are printed using the
X.B if
output filter.
The
X.I lpr
X\-f option is used to specify printing with a filter that
handles FORTRAN formats;
this flag is translated by
X.I lpr
into printing with the
X.B r
format.
The
X.I "a, i, l,"
and
X.I "o"
formats are unavailable,
as their filter names
X(\c
X.L af,
X.L if,
X.L lf
and
X.L of )
are used for other purposes.
X.NH 2
Prefilters
X.PP
The 
X.I lpr
program can pre-filter files before spooling them.
The
X.B Xe
field is used to specify that format
X.B X
files are to processed by the specified prefilter.
The prefilter specification consists of the pathname and arguments of the
prefilter program,
followed by the format that is to be used for spooling the output.
X.KF
X.DT
X.L
X.SM
X.nf
X.in +1i
X# Versatec Printer, Lind 33
X#   Uses a prefilter for f format
versatec_lind33\||\|versatec:\e
X	:fx=flpdt:mx#2000:\e
X	:lp=/dev/va0:sd=/usr/spool/versatec_lind33:\e
X	:af=/usr/adm/vaacct:\e
X	:of=/usr/lib/vpf:\e
X	:if=/usr/lib/vpf:\e
X	:df=/usr/lib/vpf:\e
X	:tf=/usr/lib/rvcat:\e
X	:fe=/usr/local/lib/vprintup -X w4,f:
X.R
X.LG
X.in -1i
X.ce
XFigure 6.2 Prefilter Printcap Entry
X.KE
XFor example,
the printcap entry in Figure 6.2 specifies that
X.B f
format files are prefiltered through
X.I vprintup
and the output is in the
X.I f
format.
X.NH 2
Special Queue Handlers
X.PP
If the user does not like the way that the PLP server handles files,
the printcap can be used to specify a queue handler program
to handle processing of the job and data files.
This is useful when you are sending files to a remote machine
using a special protocol or a remote procedure call.
The printcap queue handler field
X.B qh
specifies a program which will be responsible
for handling the job.
X.KF
X.DT
X.L
X.SM
X.nf
X.in +1i
X.ta 4n +4n +4n +4n +4n +4n +4n +4n +4n +4n +4n 8i
X# Special queue entry, used for bizzare purposes
X# The queue_handler program will take care of everything
special:\e
X	:lp=/dev/null:\e
X	:qh=/usr/local/lib/queue_handler:
X.R
X.LG
X.in -1i
X.ce
XFigure 6.3 Queue Handler Printcap Entry
X.KE
X.PP
The queue handler is invoked once per queue entry,
and exits with a 0 (successful),
X1 (unsuccessful, retry),
or other (give up and delete entry) status.
XError messages printed on
X.I stderr
X(file descriptor 2) will be placed in the spool queue log file.
X.NH 2
Multiple Servers For a Spool Queue
X.PP
If a spool queue has multiple servers,
they are specified using the
X.B sv
X(servers) parameter,
which contains a comma separated list of server entries in the printcap file.
The printcap entry for a server contains a
X.B ss
X(serves) parameter which contains the name of the spool queue that it
serves.
X.PP
Printcap entries for the server are determined in the following manner.
When the spool queue server starts up,
it reads the spool queue printcap entry,
and determines that there are multiple servers for the queue.
It then forks a printer server process for each name in the
X.B sv
list.
X.PP
The individual printer server process reads the printcap entry for the
individual printer,
overwriting or adding any existing values read from printcap for the
spool queue.
Since server entries use the
the spool directory of the spool queue,
their individual log and other files should have
distinct names.
Common information can be put in the spool queue printcap entry,
and entries that differ for each printer,
such as the output device,
need to appear the individual printer printcap entry.
END_OF_FILE
if test 10628 -ne `wc -c <'doc/PLP/06.t'`; then
    echo shar: \"'doc/PLP/06.t'\" unpacked with wrong size!
fi
# end of 'doc/PLP/06.t'
fi
if test -f 'doc/PLP/07.t' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'doc/PLP/07.t'\"
else
echo shar: Extracting \"'doc/PLP/07.t'\" \(9734 characters\)
sed "s/^X//" >'doc/PLP/07.t' <<'END_OF_FILE'
X.ig
X$Header: 07.t,v 1.1 88/05/21 18:39:43 papowell Locked $
X$log$
X..
X.bp
X.NH 1
XFilter Support
X.PP
The filter programs are started by a queue server
in order to support specialized unspooling operations.
While the server process runs SUID 
X.L root ,
and the filter process will also run SUID
X.L daemon .
The ownerships of files,
etc.,
which have to be manipulated by filter programs should
have the appropriate permissions for the
X.L daemon
userid.
X.PP
There are a set of template filters supplied with the PLP software
that can be easily modified to meet most common requirements.
A common method of incorporating new filters is to use a shell
script as a filter,
and have the shell script invoke a specialized program with the
appropriate parameters.
This techique has a slight penalty in performance,
but is very quick to implement.
X.PP
X.NH 2
XFilter Program Invocation and Actions
X.PP
Output filters are invoked by the queue server daemon,
and take their input from stdin
X(file descriptor 0),
have stdout (file descriptor 1) connected to the output device,
and stderr (file descriptor 2) connected either to
X.B lf
X(log file) or to a data sink (/dev/null).
Normal completion of the filter results when
it reads EOF on stdin,
and should exit with user status 0 if there were no errors.
It should ignore any SIGPIPE signals.
A user status 1 indicates that the job did not complete
normally and should be reprinted,
and any other status will cause the job to be discarded.
The filter should also check for successful writes to stdout.
X.PP
A filter process runs setuid 
X.I daemon
and is in the same process group as its creating server process.
This allows
X.IR killpg \|(2)
to kill both the queue server process and any filters it has created.
XFor example,
X.I lprm
terminates a running queue handler by
sending a SIGINT signal to the queue servers process group using
X.I killpg.
This signal can be trapped by filters which need
to perform cleanup operations such as
deleting temporary files.
X.NH 2
XFilter Parameters and Invocation
X.PP
XFilters are invoked with a set of parameters determined by the
entries in the printcap,
their intended purpose,
and other actions.
XFigure 7.1 is an example of a filter specification.
X.KF
X.in +1i
X.nf
X.DT
X.L
X.SM
X# Versatec Printer, Lind 33
X# Patrick Powell, 3 Nov 87
X#   Uses the new filters
versatec\||\|versatec_lind33:\e
X	:fx=flpdt:mx#2000:\e
X	:lp=/dev/va0:sd=/usr/spool/versatec_lind33:\e
X	:af=/usr/adm/vaacct:\e
X	:of=/usr/lib/vpf -v3 -m '-K prefix \e013\e015':
X.LG
X.in -1i
X.R
X.ce
XFigure 7.1. Filter Specification Example
X.KE
X.PP
A filter is invoked with the parameters in Figure 7.2,
which may be present or missing,
and in any order.
The accounting file (if present) will always be the last parameter,
and is the only one without a
X.B \-
prefix.
X.KF
X.nf
X.DT
X.L
X.SM
X.in +1i
filtername arguments \e
X	-Pprinter -wwidth -llength -xwidth -ylength [-c] [-iindent] \e
X	[-Zoptions] [-Cclass] [-Jjob] [-Raccntname] -nlogin -hHost \e
X	-Fformat [affile]
X.R
X.in -1i
X.LG
X.ce
XFigure 7.2  Filter Arguments
X.KE
X.PP
The
X.I filtername
and
X.I arguments
values are provided in the printcap filter information.
Arguments can be quoted and will be passed as a single argument to the
filter program,
similar to the method used by the Bourne shell.
Note that the escape sequences in Figure 7.1 will be translated into
a single character value,
and the resulting string will be an arguement for the filter.
X.PP
The
X.B \-P
X(printer) option is used to pass the printcap entry printer name.
The
X.B \-w
and
X.B \-l
options specify the horizontal and vertical page
size in characters and lines (obtained from the
X.B pw
and
X.B pl
printcap entries).
Note that the
X.L "lpr -wNNN"
value will be passed if it has been specified by a user as the
X.B \-w
option value.
The
X.B \-x
and
X.B \-y
options specify the horizontal and vertical page
size in pixels (from the
X.B px
and
X.B py
printcap entries).
The
X.B \-F
X(format)
option specifies the format that this filter is being used for.
X.PP
The above parameters are provided for all filters,
including the OF filter and
BP and EP banner printing filters.
The OF filter must detect the character sequence ESC\ ^A
X(\e031, \e001),
flush its output,
and suspend itself using \fIkill\fP\|(\fIgetpid\fP(),\ SIGSTOP).
The server will then start up other filters,
and use them to print jobs.
After the job has been printed,
the server will signal the OF filter to continue using
SIGCONT.
X.PP
All filters are invoked with the above parameters,
and the additional ones may be provided depending on functionality.
The
X.B \-c
X(literal) flag is optional,
and is specified for literal or
X.B \-l
output being printed using the
X.B IF
filter.
The
X.B \-i
X(indent)
value is optional,
and is the value specified by the
X.B \-i
option of
X.I lpr .
The
X.B \-Z
X(extra parameters) are parameters passed to the filter by the
X.I lpr
X.B \-Z
option.
The
X.B \-C
X(class or priority)
and
X.B \-J
X(job name)
are optional and generated by
X.IR lpr .
The
X.B \-n
and
X.B \-h
parameters specify the login name and host name respectively of the
originator of the job.
X.PP
The last (optional) entry is the name of the
accounting file,
taken from the
X.B af
printcap entry.
This may be a default value,
or specified by the user.
If the accounting file does not exist or is unable to be opened in
append mode,
then accounting action is suppressed.
X.NH 2
Banner Printing Filters
X.PP
The
X.B bp
X(banner printer BP)
and
X.B ep
X(end printer EP)
entries specify a banner and end printing program that is invoked
at the start and end of a job.
The BP and EP filters are invoked with the same parameters as the
IF filter,
and with the
X.B -Ff
format option.
Special flags and parameters for these filters may be specified 
in the printcap entry.
X.PP
The banner printing programs will have
their standard input
X(file descriptor 0) set to
X.L /dev/null ,
standard output
X(file descriptor 1) to the output device,
and standard error
X(file descriptor 2)
to the error logging file.
They must exit with 0 user status for successful completion;
any other value indicates unsuccessful completion and the
and an error reported.
X.NH 2
Accounting Information
X.PP
Accounting information is appended to the accounting file by the
appropriate output filter.
Rather than have a complex binary accounting database,
this version assumes that accounting information will be simple and easy
to maintain and understand.
The
X.I pac
program has been supplied to make accounting information easily managable,
but most accounting procedures can be carried out with a simple
shell script,
and a hearty use of
X.I sort ,
X.I sed ,
and
X.I awk .
In order to keep track of accounting information,
it must be maintained in a consistent manner.
XEntries in the raw accounting file should have the form
illustrated in
XFigure 7.3.
X.KF
X.L
X.SM
X.in +1i
X.nf
host              user printer       format pages date
attila.cs.umn.edu root imagen_lind22 n      5     Fri May 20 21:29:22 CDT 1988
X.R
X.LG
X.in -1i
X.ce
XFigure 7.3 Accounting File Entry
X.KE
X.PP
The host,
user,
printer,
and format
information
can be obtained from the parameters passed to the filter.
The page entry is the number of billable pages.
When the
X.I pac
program produces a summary,
the summary file has the format as in
XFigure 7.4.
X.KF
X.L
X.SM
X.in +1i
X.nf
host              user printer       format pages  jobs
attila.cs.umn.edu root imagen_lind22 n      5      1
attila.cs.umn.edu root imagen_lind22 l      220    7
X.R
X.LG
X.in -1i
X.ce
XFigure 7.4 Summary File Entry
X.KE
X.PP
XExperience has indicated that most sites use a differing approaches
to accounting,
with little requirement commonality.
Thus,
these accounting procedures and information may be
added or modified as required.
Note that the accounting is done by the filter programs,
and not by the PLP software.
X.NH 2
Prefilters
X.PP
The 
X.I lpr 
program can use
X.I prefilters
to process the text before spooling.
The prefilters are invoked with the the following arguments,
which are the same as specified for the output filter.
X.DS
X.DT
X.SM
X.L
filtername arguments \e
X	-Pprinter -wwidth -llength -xwidth -ylength [-c] [-iindent] \e
X	[-Zoptions] [-Cclass] [-Jjob] [-Raccntname] -nlogin -hHost \e
X	-Fformat file [files]
X.R
X.DE
X.PP
The options are specified in exactly the same manner
as for the filter for the specified format.
The file names are either those specified to
X.I lpr
by the user,
or a copy of the input from stdin.
The prefilter must copy these files to stdout,
performing whatever filter functions are neccessary.
X.PP
If successful,
the prefilter should exit with a 0 user status;
anything else will indicate failure and the user job will be discarded.
XErrors written to
X.L stderr
will be directed to the
X.I lpr
X.L stderr
output.
X.NH 2
Adapting Existing Filters and Writing Filters
X.PP
If you have an existing set of filters for the Berkeley LPD
daemon,
you can use the
X.L compat
program supplied with this package to adapt them to use with PLP.
This program invokes an OF, IF,
or other filter with the old Berkeley style of parameters.
XFor example,
the following entry printcap
X.B if
entry will invoke the
X.L imfilter
program to be used as the IF filter.
X.ti +.5i
X.L "if=/usr/local/lib/compat /usr/local/lib/imfilter"
X.PP
If a new filter is needed,
you can start with the 
programs supplied with this distribution,
found in the
X.I filters
directory.
A sample filter would consist of an application independent
X.L main
routine which parses the command line input flags
and calls a user supplied
X.L filter()
function,
and support functions.
These are available in the
X.L filter/main.c
file.
The 
X.I suspend()
support routine
suspends the filter when the appropriate string is detected in the input.
XError message and termination routines are provided.
END_OF_FILE
if test 9734 -ne `wc -c <'doc/PLP/07.t'`; then
    echo shar: \"'doc/PLP/07.t'\" unpacked with wrong size!
fi
# end of 'doc/PLP/07.t'
fi
if test -f 'src/checkpc.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'src/checkpc.c'\"
else
echo shar: Extracting \"'src/checkpc.c'\" \(9770 characters\)
sed "s/^X//" >'src/checkpc.c' <<'END_OF_FILE'
X/***************************************************************************
X * U. Minnesota LPD Software * Copyright 1987, 1988, Patrick Powell
X ***************************************************************************
X * MODULE: checkpc.c
X * Check out a print cap,  and create entries
X ***************************************************************************
X * Revision History: Created Tue Mar  1 07:56:38 CST 1988
X * $Log:	checkpc.c,v $
X * Revision 3.1  88/06/18  09:33:56  papowell
X * Version 3.0- Distributed Sat Jun 18 1988
X * 
X * Revision 2.2  88/05/14  10:20:42  papowell
X * Modified -X flag handling
X * 
X * Revision 2.1  88/05/09  10:07:42  papowell
X * PLP: Released Version
X * 
X * Revision 1.6  88/04/15  13:06:27  papowell
X * Std_environ() call added, to ensure that fd 0 (stdin), 1 (stdout), 2(stderr)
X * have valid file descriptors;  if not open, then /dev/null is used.
X * 
X * Revision 1.5  88/04/07  12:30:22  papowell
X * 
X * Revision 1.4  88/03/25  14:59:05  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/12  10:03:28  papowell
X * *** empty log message ***
X * 
X * Revision 1.2  88/03/11  19:28:12  papowell
X * Minor Changes, Updates
X * 
X * Revision 1.1  88/03/01  11:08:16  papowell
X * Initial revision
X * 
X ***************************************************************************/
X#ifndef lint
static char id_str1[] =
X	"$Header: checkpc.c,v 3.1 88/06/18 09:33:56 papowell Exp $ PLP Copyright 1988 Patrick Powell";
X#endif lint
X/*
X * checkpc: check out the entries in the printcap,
X * checking to see that the default files and directories are present
X * or absent as are indicated by the printcap entry.
X *
X * checkpc [-l] [-s] [-a] [-o] [-f] [-Pprinter] [printcapfile]
X * The default is to create all the various files;
X * the following flags are used to disable automatic creation:
X * -l - no log file
X * -s - no status file
X * -o - no output device
X * -a - no accounting file
X * -f - fix, attempt to create with the desired perms
X * -P printer this printer only
X * printcapfile: name of the printcap file to be used; default is /etc/printcap
X */
X
X#include "lp.h"
X
int	noout;			/* no output file */
int	nolog;			/* no log file */
int noout;			/* no output file */
int nostat;			/* no status file */
int noacct;			/* no accounting file */
int fix;			/* fix if bad or missing */
struct passwd *pwent, *getpwnam();	/* password entry */
int DU, DG;
int canchown;		/* can do chown */
X
main( argc, argv )
X	int argc;
X	char **argv;
X{
X	char **prlist;
X	int option;
X
X	/*
X	 * Set fd 0, 1, 2 to /dev/null if not open
X	 */
X	Std_environ();
X	/*
X	 * set umask to avoid problems with user umask
X	 */
X	(void)umask(0);
X
X#	ifdef XPERIMENT
X		Setup_test();
X#	endif XPERIMENT
X	/*
X     * set up the pathnames for information files
X	 */
X	fprintf( stdout, "before printcap  '%s'\n", Printcap );
X	Tailor_names();
X	fprintf( stdout, "after printcap  '%s'\n", Printcap );
X
X    while ((option = Getopt( argc, argv, "D:afolsXP:" )) != EOF ){
X        switch (option) {
X        case 'D':       /* turn on Debugging */
X			if( Optarg ){
X				Debug = atoi( Optarg );
X			}
X            break;
X		default:
X			usage();
X			break;
X		case 'a':	/* no acct file */
X			++noacct;
X			break;
X		case 'f':	/* no acct file */
X			++fix;
X			break;
X		case 'o':	/* no output file */
X			++noout;
X			break;
X		case 'l':	/* no log file */
X			++nolog;
X			break;
X		case 's':	/* no status file */
X			++nostat;
X			break;
X		case 'X':	/* Test version */
X#	ifdef DEBUG
X			Setup_test();
X			Tailor_names();
X#	else
X			usage();
X#	endif DEBUG
X			break;
X		case 'P':	/* printer */
X			if( Optarg ){
X				Printer = Optarg;
X			} else {
X				usage();
X			}
X			break;
X		}
X	}
X	if( Optind < argc ){
X		(void)strcpy(Printcap, argv[Optind]);
X		++Optind;
X	}
X	if( Optind < argc ){
X		usage();
X	}
X
X	canchown = (geteuid() == 0 );
X
X	if( canchown == 0 ){
X		(void)fprintf(stdout, "%s: not running root\n", Name );
X		(void)fflush(stdout);
X	}
X
X	if((pwent = getpwnam(DAEMON) ) == NULL){
X		logerr_die( XLOG_DEBUG, "getpwnam failed for daemon" );
X	}
X	DU = pwent->pw_uid;
X	DG = pwent->pw_gid;
X	(void)fprintf(stdout, "Printcap file: %s\n", Printcap );
X		(void)fflush(stdout);
X	if( Printcap[0] != '/' ){
X		(void)fprintf(stdout, "Printcap file must be absolute path name\n");
X		(void)fflush(stdout);
X		exit(1);
X	}
X
X	if( Printer ){
X		doprinter();
X	} else {
X		(void)fprintf(stdout, "Doing all printers\n" );
X		(void)fflush(stdout);
X		for(prlist = All_printers(); Printer = *prlist; ++prlist ){
X			doprinter();
X		}
X	}
X}
X
X/*
X *	doprinter:
X *	1. get the printcap entry
X *	2. check the spool direcotry for ownership, etc.
X *  3. check the log, accounting, and lock file for existence.
X */
doprinter()
X{
X	if( Get_pc_entry(Printer, All_pc_vars, All_pc_len ) == 0){
X		(void)fprintf(stdout,"no printer %s", Printer );
X		(void)fflush(stdout);
X		return;
X	}
X	(void)fprintf(stdout, "checking printer %s: ", Printer );
X		(void)fflush(stdout);
X	/*
X	 * check to see if the spool directory exists
X	 */
X	(void)fprintf(stdout, "SD %s, ",SD);
X		(void)fflush(stdout);
X	(void)all_check( 0,S_IFDIR, SD, 0755, "daemon", "daemon" );
X	if( chdir( SD ) < 0 ){
X		logerr( XLOG_DEBUG, "cannot chdir to SD" );
X		return;
X	}
X	if( noout == 0 && LP  && *LP ){
X		(void)fprintf(stdout, "LP %s, ",LP);
X		(void)fflush(stdout);
X		(void)all_check( noout,S_IFREG, LP, 0644, "daemon", "daemon" );
X	}
X	if( nolog == 0 && LF && *LF ){
X		(void)fprintf(stdout, "LF %s, ",LF);
X		(void)fflush(stdout);
X		(void)all_check( nolog,S_IFREG, LF, 0664, "daemon", "daemon" );
X	}
X	if( LO && *LO ){
X		(void)fprintf(stdout, "LO %s, ",LO);
X		(void)fflush(stdout);
X		(void)all_check( 0,S_IFREG, LO, 0644, "daemon", "daemon" );
X	}
X	if( noacct || AF == 0 ||  *AF == 0 ){
X		(void)fprintf(stdout, "no AF, ");
X			(void)fflush(stdout);
X	} else {
X		(void)fprintf(stdout, "AF %s, ",AF);
X			(void)fflush(stdout);
X		(void)all_check( noacct,S_IFREG, AF, 0664, "daemon", "daemon" );
X	}
X	if( nostat == 0 && ST && *ST ){
X		(void)fprintf(stdout, "ST %s, ",ST);
X		(void)fflush(stdout);
X		(void)all_check( nostat,S_IFREG, ST, 0664, "daemon", "daemon" );
X	}
X	if( PS && *PS ){
X		(void)fprintf(stdout, "PS %s, ",PS);
X		(void)fflush(stdout);
X		(void)all_check( nostat,S_IFREG, PS, 0664, "daemon", "daemon" );
X	}
X	(void)fprintf(stdout, "\n" );
X		(void)fflush(stdout);
X}
X
X/*
X * check and fix if necessary
X */
all_check(remove,type,path,perms, owner, group)
X	int type;	/* S_IFDIR or S_IFREG */
X	char *path;	/* pathname of thing */
X	int perms;	/* perms for the file/directory */
X	char *owner, *group;
X{
X	struct stat statbuf;
X	char cmd[BUFSIZ];
X	int status;
X	int ok;
X
X	ok = 1;
X	if( stat( path, &statbuf ) < 0 ){
X		logerr( XLOG_DEBUG, "%s cannot be stated", path);
X		if( remove ){
X			return 1;
X		}
X		if( fix ){
X			fixup( type, path, perms, owner, group );
X		}
X		return(0);
X	}
X	if( remove ){
X		(void)fprintf(stdout, "removing %s", path );
X		(void)fflush(stdout);
X		(void)sprintf( cmd, "rm -f %s", path );
X		status = system(cmd);
X		if(status){
X			(void)fprintf(stdout, "fix: %s failed, try by hand\n", cmd);
X		(void)fflush(stdout);
X			exit(1);
X		}
X	}
X	if( (statbuf.st_mode & type) == 0 ){
X		(void)fprintf(stdout,"not a %s ",(type==S_IFDIR)?"directory":"file" );
X		(void)fflush(stdout);
X		return(0);
X	}
X	if( statbuf.st_uid != DU ){
X		ok = 0;
X		(void)fprintf(stdout, "not owner '%s' ",owner );
X		(void)fflush(stdout);
X		if( fix  && canchown ){
X			fixup( type, path, perms, owner, group );
X			return 0;
X		}
X	}
X	if( statbuf.st_gid != DG ){
X		ok = 0;
X		(void)fprintf(stdout, "not group '%s' ",group );
X		(void)fflush(stdout);
X		if( fix  && canchown ){
X			fixup( type, path, perms, owner, group );
X			return 0;
X		}
X	}
X	if( (statbuf.st_mode & 0777) != perms ){
X		ok = 0;
X		(void)fprintf(stdout, "perms are %o ", (statbuf.st_mode & 0777) );
X		(void)fflush(stdout);
X		if( fix ){
X			fixup( type, path, perms, owner, group );
X			return 0;
X		}
X	}
X	putchar( '\n' );
X	(void)fflush(stdout);
X	return ( ok );
X}
X
X/*
X * fixup( type, path, perms, owner, group )
X * -- try to create the file/directory with the appropriate
X * permissions
X */
fixup( type, path, perms, owner, group )
X	int type, perms;
X	char *path, *owner, *group;
X{
X	int status;
X	char cmd[BUFSIZ];
X	struct stat statbuf;
X
X	(void)fprintf(stdout, "trying to fix %s %s\n",(type==S_IFDIR)?"directory":"file",path);
X		(void)fflush(stdout);
X	if( type==S_IFDIR ){
X		(void)sprintf( cmd, "mkdir %s", path );
X	} else {
X		(void)sprintf( cmd, "touch %s", path );
X	}
X	(void)fprintf(stdout, "fix: %s\n", cmd );
X		(void)fflush(stdout);
X	status = system( cmd );
X	if( stat( path, &statbuf ) < 0 ){
X		(void)fprintf(stdout, "cannot stat %s, you have to try by hand\n", path );
X		(void)fflush(stdout);
X	}
X	/*
X	 * fix up ownership and perms, you are root
X	 */
X	if( canchown ){
X		(void)sprintf(cmd, "chown %s %s", owner, path );
X		(void)fprintf(stdout, "fix: %s\n", cmd );
X			(void)fflush(stdout);
X		status = system( cmd );
X		if(status){
X			(void)fprintf(stdout, "fix: %s failed, try by hand\n", cmd);
X		}
X		(void)sprintf(cmd, "chgrp %s %s", group, path );
X		(void)fprintf(stdout, "fix: %s\n", cmd );
X			(void)fflush(stdout);
X		status = system( cmd );
X		if(status){
X			(void)fprintf(stdout, "fix: %s failed, try by hand\n", cmd);
X		}
X	}
X	(void)sprintf(cmd, "chmod %o %s", perms, path );
X	(void)fprintf(stdout, "fix: %s\n", cmd );
X		(void)fflush(stdout);
X	status = system( cmd );
X	if(status){
X		(void)fprintf(stdout, "fix: %s failed, try by hand\n", cmd);
X	}
X}
X
usage()
X{
X	(void)fprintf(stdout,
X	"use: %s [-aflso][-Pprinter] [printcapfile]", Name);
X		(void)fflush(stdout);
X	exit(1);
X}
X
cleanup()
X{ ; }
END_OF_FILE
if test 9770 -ne `wc -c <'src/checkpc.c'`; then
    echo shar: \"'src/checkpc.c'\" unpacked with wrong size!
fi
# end of 'src/checkpc.c'
fi
if test -f 'src/remoteprinter.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'src/remoteprinter.c'\"
else
echo shar: Extracting \"'src/remoteprinter.c'\" \(9823 characters\)
sed "s/^X//" >'src/remoteprinter.c' <<'END_OF_FILE'
X/***************************************************************************
X * U. Minnesota LPD Software * Copyright 1987, 1988, Patrick Powell
X ***************************************************************************
X * MODULE: remoteprinter.c
X * send a job to a remote Printer
X ***************************************************************************
X * Revision History: Creation Fri Jan 15 19:28:22 CST 1988
X * $Log:	remoteprinter.c,v $
X * Revision 3.1  88/06/18  09:35:31  papowell
X * Version 3.0- Distributed Sat Jun 18 1988
X * 
X * Revision 2.3  88/05/14  10:18:22  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.2  88/05/11  09:52:49  papowell
X * Remote printer file transfer error fixed.
X * 
X * Revision 2.1  88/05/09  10:10:04  papowell
X * PLP: Released Version
X * 
X * Revision 1.4  88/04/06  12:12:35  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:01:27  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/12  10:03:32  papowell
X * *** empty log message ***
X * 
X * Revision 1.1  88/03/01  11:09:10  papowell
X * Initial revision
X * 
X ***************************************************************************/
X#ifndef lint
static char id_str1[] =
X	"$Header: remoteprinter.c,v 3.1 88/06/18 09:35:31 papowell Exp $ PLP Copyright 1988 Patrick Powell";
X#endif lint
X
X#include "lp.h"
X
X/***************************************************************************
X * int Setup_xfer()
X * sends the "\02Printer" message to the remote Host
X * Returns: successful JSUCC, otherwise JFAIL
X ***************************************************************************/
int
Setup_xfer()
X{
X	char buf[BUFSIZ];
X
X	if( RP == 0 || *RP == 0 ){
X		fatal(XLOG_INFO, "no RP specified for RM (%s)", RM );
X	}
X	(void)sprintf( buf, "%c%s\n",  REQ_RECV, RP );
X	if(Debug>3)log(XLOG_DEBUG,
X		"Setup_xfer: request %d, (REQ_RECV) Host '%s' pr '%s'",
X		REQ_RECV,RM,RP);
X	if( JSUCC == Link_line( -1, buf )){
X		if(Debug>3)log(XLOG_DEBUG,"Setup_xfer: request sent");
X		if( JSUCC == Link_confirm()){
X			if(Debug>3)log(XLOG_DEBUG,"Setup_xfer: request to %s confirmed",RM);
X			return(JSUCC);
X		}
X		if(Debug>3)log(XLOG_DEBUG,"Setup_xfer: request to %s not confirmed",RM);
X	} else {
X		if(Debug>3)log(XLOG_DEBUG,"Setup_xfer: request not sent");
X	}
X	setstatus("request for file transfer to %s failed %s", RM, Time_str() );
X	fatal( XLOG_INFO, "Setup_xfer: cannot start transfer to %s", RM );
X	/*NOTREACHED*/
X}
X
X/***************************************************************************
X * Sendjob( FILE *cfp; struct queue *q)
X *   1.  First scan extracts information which controls printing
X *			and finds the names of the files to send.
X *	 2.	 The data files are then sent.
X *	 3.	 Control file is then sent.
X *   4.  Job files are removed
X *   5.  Control file is removed
X * Returns:  JBUSY, JFAIL, JSUCC, JABORT
X * NOTE: this code was based on a description of the LPD file transfer
X *    protocol.
X *
X * File transfer protocol:
X * Sender: sends line of form 'flag' length filename
X * Receiver: acknowledges with 0 (single byte)
X * Sender: sends file (length bytes of information), then a teminating 0
X * Receiver: acknowledges with 0 (single byte)
X *
X * Tne end is signalled by closing the stream, which results in a read error.
X * 
X *************************************************************************/
Sendjob(cfp, q)
X	FILE *cfp;			/* control file */
X	struct queue *q;	/* job entry */
X{
X	FILE *fp;					/* File to send */
X	char parm[MAXPATHLEN];			/* holds a line read in */
X	char *arg;					/* control line argument */
X	char opt;					/* control line option */
X	int  jstatus;			    /* job status */
X	int  i;						/* ACME Integers, Inc. */
X
X	/*
X	 * set job status
X	 */
X	jstatus = JFAIL;	/* default */
X
X	/*
X	 * read the control file and extract user information
X	 */
X	Parmcount = 0;
X	while(fgets( parm, sizeof(parm), cfp )){
X		if( (arg = index(parm, '\n')) == 0 ){
X			log( XLOG_INFO, "Sendjob: bad control file format (%s), no endline",
X				q->q_name);
X			jstatus = JABORT;
X			goto error;
X		}
X		*arg = 0;
X		opt = parm[0];
X		arg = parm+1;
X		if( !isascii(opt) || !isalnum( opt ) || strlen( arg ) > MAXPARMLEN ){
X			log( XLOG_INFO, "Sendjob: bad control file (%s), line(%s)",
X				q->q_name,parm);
X			jstatus = JABORT;
X			goto error;
X		}
X		if( !islower( opt ) && opt != 'U' ){
X			continue;
X		}
X		if( Job_match( q->q_name, arg ) == 0 ){
X			log( XLOG_INFO, "Sendjob: bad file name format (%s)", arg );
X			jstatus = JABORT;
X			goto error;
X		}
X		if( islower( opt )){
X			if( Add_name(arg) < 0 ){
X				log( XLOG_INFO, "Sendjob: too many files (%s)", arg );
X				jstatus = JABORT;
X				goto error;
X			}
X		} else {
X			if( (i = Find_name(arg) ) < 0 ){
X				log(XLOG_INFO,"Sendjob: job(%s)U specified for '%s' not in job",
X					q->q_name,parm);
X				jstatus = JABORT;
X				goto error;
X			}
X		}
X	}
X	/*
X	 * We send the control file first if we are using the PLP protocol
X	 */
X	if( FJ ){
X		jstatus = sendfile( cfp, q->q_name, CNAME);
X		if( jstatus != JSUCC ){
X			setstatus("transfer %s to %s failed %s",q->q_name,RM,Time_str());
X			log(XLOG_INFO,"Sendjob: sendname %s to %s failed",q->q_name,RM);
X			goto error;
X		}
X	}
X	/*
X	 * send the jobs in the file
X	 */
X	for( i = 0; i < Parmcount; ++i ){
X		arg = Parms[i].filename;
X		if( (fp = fopen_daemon( arg, "r" )) == NULL ){
X			jstatus = JABORT;
X			logerr( XLOG_INFO,"Sendjob: cannot open data file %s",arg);
X			goto error;
X		}
X		/*
X		 * send the file
X		 */
X		if(Debug>3)log(XLOG_DEBUG,"Sendjob: sending file %s", arg );
X		jstatus = sendfile( fp, arg, DFILE );
X		(void)fclose(fp);
X		if( jstatus != JSUCC ){
X			setstatus("transfer %s to %s failed %s",arg,RM,Time_str());
X			log(XLOG_INFO,"Sendjob: transfer %s to host %s failed",arg,RM);
X			goto error;
X		}
X	}
X	/*
X	 * send the control file
X	 */
X	if(Debug>3)log(XLOG_DEBUG,"sending file %s", q->q_name );
X	if( FJ ){
X		jstatus = sendname( cfp, q->q_name, CEND );
X	} else {
X		jstatus = sendfile( cfp, q->q_name, CFILE );
X	}
X	if( jstatus != JSUCC ){
X		setstatus("transfer %s to %s failed %s",q->q_name,RM,Time_str());
X		log(XLOG_INFO,"Sendjob: transfer %s to host %s failed",q->q_name,RM);
X		goto error;
X	}
X	/*
X	 * finished!
X	 */
X	jstatus = JSUCC;
error:
X	if( jstatus != JSUCC ){
X		Link_close();
X	}
X	return (jstatus);
X}
X
X/***************************************************************************
X * sendfile( FILE* fp; char *name; int flag )
X *   sendfile protocol:
X * 1. line containing the flag, number of bytes, and file name is sent.
X *     This has the format:
X *        "%c%d %s", flag, filesize, name
X *    DFILE (data file) flag is 03,  a CFILE (control file) flag is 02
X * 2. the remote end responds by sending back a single 0 character;
X *    anything else is an error condition and terminates transfer
X * 3. the file is then copied to the remote end and terminated with 0
X * 4. if an error is detected, we send a non-zero character
X *    and close the link.
X ***************************************************************************/
X
sendfile( fp, name, flag )
X	FILE *fp;
X	char *name;
X	int flag;
X{
X	int succ;			/* ACME Integer, Inc. */
X	struct stat statb;	/* status buffer */
X
X	/*
X	 * stat the file
X	 */
X	if( fstat( fileno(fp), &statb) < 0 ){
X		logerr( XLOG_INFO, "sendname: could not stat %s", name );
X		return( JFAIL );
X	}
X	/*
X	 * rewind the file
X	 */
X	if( fseek(fp, 0L, 0) < 0 ){
X		logerr_die( XLOG_INFO, "sendfile: fseek failed '%s'", name );
X	}
X	succ = sendname( fp, name, flag );
X	if( succ == JSUCC ){
X		succ = Link_copy( fp, (long)statb.st_size, name );
X	}
X	if( succ == JSUCC ){
X		succ = Link_ack( 0 );
X	}
X	if( succ == JSUCC ){
X		succ = Link_confirm();
X	}
X	if( succ != JSUCC ){
X		succ = JFAIL;
X		Link_close();
X	}
X	return( succ );
X}
X
X/***************************************************************************
X * Send_error()
X * Called when you have retried a couple of times; bad job, needs attention
X ***************************************************************************/
void
Send_error()
X{
X	log(XLOG_CRIT, "job cannot be sent from %s to %s", Host, RM );
X	exit( 0 );
X}
X
X/***************************************************************************
X * sendname( FILE *fp; char *name; int flag )
X *   sendname protocol:
X * 1. line containing the flag and file name is sent
X *     This has the format:
X *        "%c%d %s", flag, filesize, name
X *    DFILE (data file) flag is 03,  a CFILE (control file) flag is 02
X * 2. the remote end responds by sending back a single 0 character;
X *    anything else is an error condition and terminates transfer
X ***************************************************************************/
sendname( fp, name, flag )
X	FILE *fp;
X	char *name;
X	int flag;
X{
X	struct stat statb;	/* status buffer */
X	int succ;			/* ACME Integer, Inc. */
X	char buf[BUFSIZ];
X
X	/*
X	 * stat the file
X	 */
X	if( fstat( fileno(fp), &statb) < 0 ){
X		logerr( XLOG_INFO, "sendfile: could not stat %s", name );
X		return( JFAIL );
X	}
X	(void)sprintf( buf, "%c%d %s\n", flag, statb.st_size, name);
X	succ = Link_send( buf );
X	if( succ == JSUCC ){
X		succ = Link_confirm();
X	}
X	return( succ );
X}
X
X/***************************************************************************
X * Allsent( )
X *    all files have been sent; send a closing 0 and shut down link
X ***************************************************************************/
void
Allsent()
X{
X	(void)Link_ack( 0 );
X	Link_close();
X}
END_OF_FILE
if test 9823 -ne `wc -c <'src/remoteprinter.c'`; then
    echo shar: \"'src/remoteprinter.c'\" unpacked with wrong size!
fi
# end of 'src/remoteprinter.c'
fi
if test -f 'src/startprinter.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'src/startprinter.c'\"
else
echo shar: Extracting \"'src/startprinter.c'\" \(10002 characters\)
sed "s/^X//" >'src/startprinter.c' <<'END_OF_FILE'
X/***************************************************************************
X * U. Minnesota LPD Software * Copyright 1987, 1988, Patrick Powell
X ***************************************************************************
X * MODULE: Startprinter.c
X * Printer queue job handler
X * 
X * StartPrinter is responsible for handling the Printer queue.
X * 1.  Get the printcap entry.
X * 2.  Check the spool directory to see if printing is enabled
X * 3.  Check to see if there are any jobs
X * 4.  If a remote Printer, call remotePrinter()
X *     If a local Printer, call localPrinter()
X ***************************************************************************
X * Revision History: Created Sat Feb 13 09:11:38 CST 1988
X * $Log:	startprinter.c,v $
X * Revision 3.1  88/06/18  09:35:49  papowell
X * Version 3.0- Distributed Sat Jun 18 1988
X * 
X * Revision 2.4  88/05/21  10:28:30  papowell
X * Minor editing
X * 
X * Revision 2.3  88/05/14  10:18:27  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.2  88/05/11  09:50:52  papowell
X * Remote printer file transfer error fixed.
X * 
X * Revision 2.1  88/05/09  10:10:30  papowell
X * PLP: Released Version
X * 
X * Revision 1.6  88/04/27  18:02:36  papowell
X * The SIGCHLD signal has an odd behaviour on some systems.  Modified so that
X * it will not get set UNLESS processes are started;  also,  it is reset
X * to SIG_DFL, not SIG_IGN.
X * 
X * Revision 1.5  88/04/07  21:24:27  papowell
X * changed calls of init to (*init)().  Sigh.
X * 
X * Revision 1.4  88/04/06  12:13:05  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:01:47  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:20  papowell
X * Minor Changes, Updates
X * 
X * Revision 1.1  88/03/01  11:09:24  papowell
X * Initial revision
X * 
X ***************************************************************************/
X#ifndef lint
static char id_str1[] =
X	"$Header: startprinter.c,v 3.1 88/06/18 09:35:49 papowell Exp $ PLP Copyright 1988 Patrick Powell";
X#endif lint
X
X#include "lp.h"
extern int Printjob(), Sendjob();
extern int Printinit(), Setup_xfer();
extern void Printfinal(), Printerror(), Allsent(), Send_error();
X
Startprinter()
X{
X	int pid;				/* process id */
X	char *ps, *st;			/* ACME Pointers */
X
X	/*
X	 * ignore SIGCHILD,  explicitly wait for them
X	 */
X	(void)signal(SIGCHLD, SIG_DFL);
X	/*
X	 * get the printcap entry
X	 */
X	if( Get_pc_entry(Printer, All_pc_vars, All_pc_len ) == 0){
X		log( XLOG_INFO, "trying to start non-existent Printer" );
X		exit(0);
X	}
X	if( SS && *SS ){
X		/*
X		 * we have a spool server that is to be started
X		 */
X		ps = PS;
X		st = ST;
X		if( Set_pc_entry(SS, All_pc_vars, All_pc_len ) == 0){
X			log( XLOG_INFO, "queue %s does not entry", SS );
X			exit(0);
X		}
X		PS = ps;
X		ST = st;
X		LO = Printer;
X		SV = 0;
X	}
X	if( SD == 0 || *SD == 0 ){
X		/*
X		 * no spooling directory, not a Printer
X		 */
X		if(Debug>0)log(XLOG_DEBUG, "Startprinter: not a Printer");
X		exit(0);
X	}
X	if( RM && NW ){
X		(void)Remote_start();
X		exit(0);
X	}
X	/* chdir to spool directory */
X	if (chdir(SD) < 0) {
X		logerr_die( XLOG_NOTICE,"Startprinter: cannot chdir to %s", SD);
X	}
X	/*
X	 * check to see if there is a deamon running
X	 */
X	Lfd = Getlockfile( LO, &pid, (char *)0, 0, &LO_statb );
X	if( Lfd == NULL ){
X		if(Debug>2)log(XLOG_DEBUG, "Startprinter: server present, pid %u",pid);
X		exit(0);
X	}
X	if( fseek( Lfd, 0L, 0 ) < 0 ){
X		logerr_die( XLOG_INFO, "Startprinter: T1 fseek failed");
X	}
X	/*
X	 * check for unspooling enabled
X	 */
X	if( LO_statb.st_mode & DISABLE_PRINT) {
X		if(Debug>0)log( XLOG_DEBUG,"Startprinter: unspooling disabled");
X		exit(0);
X	}
X	/*
X	 * handle multiple servers
X	 */
X	if( SV && *SV ){
X		Closelockfile(LO, Lfd );
X		Lfd = 0;
X		Start_server();
X		/*
X		 * Check on the status of the queue lock file
X		 */
X		Lfd = Getlockfile( LO, &pid, (char *)0, 0, &LO_statb );
X		if( Lfd == NULL ){
X			if(Debug>2)log(XLOG_DEBUG, "Startprinter: server present, pid %u",pid);
X			exit(0);
X		}
X	}
X	/*
X	 * set up log file
X	 */
X	if( fseek( Lfd, 0L, 0 ) < 0 ){
X		logerr_die( XLOG_INFO, "Startprinter: T2 fseek failed");
X	}
X	if(Debug>0)log(XLOG_DEBUG, "Startprinter: should log into %s",
X		LF?LF:"/dev/null");
X	Setuplog( LF, 0 );
X	if( fseek( Lfd, 0L, 0 ) < 0 ){
X		logerr_die( XLOG_INFO, "Startprinter: T3 fseek failed");
X	}
X	/*
X	 * OK, you are the server, go to it.
X	 * set process group to the queue handler process
X	 */
X	(void) setpgrp(0, getpid());
X
X	Setlockfile( LO, Lfd, getpid(), "(checking queue)");
X	setstatus( "checking queue at %s", Time_str());
X
X	/*
X	 * search the spool directory for work and sort by queue order.
X	 */
X	if(Debug>0)log(XLOG_DEBUG, "Startprinter: unqueueing jobs");
X	if( RM ){
X		unspool(Setup_xfer, Sendjob, Allsent, Send_error);
X	} else {
X		unspool(Printinit, Printjob, Printfinal,Printerror);
X	}
X	if(Debug>2)log( XLOG_DEBUG, "Startprinter: work done" );
X	setstatus( "work done at %s", Time_str() );
X	Closelockfile(LO,Lfd);
X	exit( 0 );
X}
X
X
X/***********************************************************
X * unspool( init, jobhandler, closer)
X * 
X * do{
X *   check queue for new jobs
X *   jobdone = 0
X *   for(n = 0;n < Jobcount; ++n)
X *      if queue needs to be resorted then
X *         set jobdone and break from "for" loop;
X *      while not successful and retry count is less than a limit do
X *         init();
X *         success = jobhandler(job n);
X *     -- note: job can be busy (no action), done successfully,
X *              done unsuccessfully and should be abandoned,
X *              or done unsuccessfully and should be repeated
X *      if action was done then set jobdone and remove job
X *          else call closer();
X * }while( jobdone )
X * call closer()
X ***********************************************************/
X
unspool( init, dojob, closer, err )
X	int (*init)();
X	int (*dojob)();
X	void (*closer)();
X	void (*err)();
X{
X	int n;				/* job number */
X	int retries;		/* number of retries */
X	int success;		/* job success status */
X	struct queue *q;	/* job entry  */
X	int jobdone;		/* job done in this pass */
X	FILE *cfp;			/* control file */
X	int init_done;	/* initialization done */
X
X	/*
X	 * the big loop
X	 */
X	init_done = 0;
X	do{
X		/*
X		 * search the spool directory for more work.
X		 */
X		Jobcount = Getq();
X		/*
X		 * reset "update queue order" flag
X		 */
X		if(fstat(fileno(Lfd), &LO_statb ) < 0 ){
X			logerr_die( XLOG_NOTICE,"unspool: cannot stat %s", LO);
X		}
X		if(Debug>5)log(XLOG_DEBUG,"unspool: '%s' perms 0%o",LO,
X			LO_statb.st_mode);
X		if(fchmod(fileno(Lfd), (int)(LO_statb.st_mode & CLEAR_REQUE)) < 0){
X			logerr_die( XLOG_NOTICE,"unspool: cannot chmod '%s'", LO);
X		}
X		jobdone = 0;
X		/*
X		 * scan the queue
X		 */
X		for(n=0; n < Jobcount; ++n ){
X			q = &Queue[n];
X			/*
X			 * lock the control file
X			 */
X			if( (cfp = Lockcf(q->q_name) )!= NULL ){
X				Setlockfile( LO, Lfd, getpid(), q->q_name );
X				/*
X				 * try printing this file until successful,
X				 *  number of attempts exceeds limit, or abort
X				 * try sending indefinately until successful
X				 */
X				success = JFAIL;
X				for( retries = 0;
X					success == JFAIL && retries <= RT;
X					++retries ){
X					/*
X					 * STDIO file error reset, needed on some implementations
X					 */
X					clearerr( cfp );
X					/*
X					 * seek to the start of the file
X					 */
X					if( fseek( cfp, 0L, 0 ) < 0 ){
X						logerr_die(XLOG_INFO,"unspool: fseek failed (%s)",
X							q->q_name );
X					}
X					/*
X					 * update status information
X					 */
X					if(Debug)log(XLOG_DEBUG,"unspool: doing %s, %d retry",
X						q->q_name,retries);
X					/*
X					 * initialize
X					 */
X					if( init_done == 0 ){
X						init_done = (*init)();
X						if( init_done != JSUCC ){
X							setstatus( "initialization failure, %s",Last_errormsg);
X							return;
X						}
X					}
X					setstatus( "processing, active job started %s, attempt %d",
X						Time_str(), retries+1);
X					/*
X					 * try to print the job
X					 */
X					success = (*dojob)(cfp, q);
X				}
X				if(Debug>4)log(XLOG_DEBUG,"unspool: %s status %d", q->q_name,
X					success );
X				if( success == JFAIL ){
X					(*err)();
X					init_done = 0;
X				}
X				jobdone = 1;
X				Remove_job( cfp, q );
X				(void)fclose(cfp);
X			}
X			/*
X			 * collect any garbage
X			 */
X			Reapchild();
X		}
X		/*
X		 * collect any garbage
X		 */
X		Reapchild();
X	} while( jobdone );
X	/*
X	 * collect any garbage
X	 */
X	Reapchild();
X	/*
X	 * queue finished
X	 */
X	if(Debug>0)log(XLOG_DEBUG, "unspool: no more work to do" );
X	(*closer)();
X}
X
X/***************************************************************************
X * Start_server()
X * start multiple servers for a single queue.  The SV printcap parameter
X * has a list of the servers.  These servers use the spool queues
X * directory,  and have a lock file in the server directory.
X * This routine will extract the names of each server,  fork a process
X * for it,  and then will read the printcap information for the server
X * from the queue.
X * The printer names are separated by commas.
X ***************************************************************************/
X
Start_server()
X{
X	char *ps;
X	char *last;
X	int pid;
X	
X	last = 0;
X	ps = SV;
X	while( ps ){
X		Printer = ps;
X		if( last = index( ps, ',' ) ){
X			*last = 0;
X			ps = last+1;
X		} else {
X			ps = 0;
X		}
X		if( ps ){
X			if( (pid = fork()) < 0 ){
X				logerr_die( XLOG_INFO, "Start_server: fork failed" );
X			} else if( pid == 0 ){
X				ps = 0;
X			}
X		}
X	}
X	if( Set_pc_entry(Printer, All_pc_vars, All_pc_len ) == 0){
X		fatal( XLOG_INFO, "trying to start non-existent server" );
X	}
X	LO = Printer;
X	if(Debug>3)log(XLOG_DEBUG,"Start_server: started" );
X}
END_OF_FILE
if test 10002 -ne `wc -c <'src/startprinter.c'`; then
    echo shar: \"'src/startprinter.c'\" unpacked with wrong size!
fi
# end of 'src/startprinter.c'
fi
echo shar: End of archive 7 \(of 16\).
cp /dev/null ark7isdone
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