Integrating under Solaristm; LP
Norman A. Jacobs
Sun Microsystems, Inc.
Background
On occasion, third party developers and customers find a need to integrate
support for a new printer, or a need to perform some new data transformation
under LP. When doing so, they read through the available documentation
in the AnswerBook under the Solaristm; Administrator's Guide.
From there, they can get a basic understanding of how an LP server operates,
but some of the important specifics are missing. Also, limitations and
interface commitment levels are not described. This page attempts to provide
a more complete description of LP server facilities, operation and integration.
Introduction
At the core of the ability to print under Solaristm; is a service
referred to at the LP service. The LP service has changed considerably
between the releases of Solaristm; 2.5.1, and Solaristm;
2.6. The changes between these releases include a significant architectural
shift, as well as a philosophical shift. With these shifts came the reimplementation,
replacement or elimination of faulty services with newer, more flexible
and more efficient components. These change are primarily centered around
the client side functionality and networking support. As of this writing,
the LP server (lpsched) remains pretty much in tact. It is this server
that is being highlighted here. All of the other work done to Solaristm;
LP is described in a separate paper "Solaristm; Printing - Near
Term Directions".
System Overview
The primary purpose of the Solaristm; LP server is to provide
print spooling to users for dedicated print devices. This is done through
the cooperation of a number of facilities under a single process. These
facilities include a specialized queue manager, a filtering (data transformation/matching)
interface, a backed (printer/communication) interface, a faulting interface,
a alerting/notification interface, a media management interface, and more.
A number of simple illustrations will provide a better understanding of
how the various LP server components hang together
Let's start with job submission. When a request to print is made,
the requester contacts the LP server (lpsched), with a copy of the print
request. The first this the scheduler does is take this request and
validate that the request can be handled. This is done by validating
that the requester has access to the destination and that the data contained
in the request can can be transformed into a format that the destination
can handle. Once the request has been validated, the server accepts
the request and informs the
requester that it has done so. From there, the real work begins.
If the request is already in a format that is acceptable to the destination
device, or if the transformation to an acceptable format only requires
slow filtering, then the job is placed in the destination's queue for printing.
However, if the transformation requires a slow filter to perform the transformation,
the print job is placed in a filtering queue, so they can be transformed
before being queued to the destination. Once the job reaches the
top of the destinations
print queue, the scheduler (lpsched) starts a child process to manage
the printing of the job. This child process in turn opens and locks
the print device and starts child process to pass this open device and
run the interface script. It is the interface script that actually
runs any fast filters and completes processing of the job. At any
time during this processing, the interface script can detect and report
error conditions and recovery from error conditions. This information
is reported back to the scheduler using lp.cat. Upon receipt of an
error condition from the interface script, the scheduler will use the configured
alerting mechanism for the destination to alert the administrator and/or
user. Upon receipt of an "all clear" from the interface script, the
scheduler will terminate it's alerting and continue processing normally.
Interfaces
Filtering
The Solaristm; LP server supports two different types of print
filters. The first type of filter are referred to as "slow" filters. Slow
filters are intended to be used when the data transformation is likely
to take longer than it will take to print the data. This filtering is run
"out-of-band", before the print request is actually scheduled to print,
so the printer isn't stuck waiting for the data to be transformed.
The second type of filtering available under LP is "fast" filtering.
This type of filtering is intended to be used when direct interaction with
the printer is required, or when the transformation is not likely to be
a bottleneck. Fast filters run in-line, on the way to the printer.
Filters are configured under LP using the lpfilter(1M)
command. This command takes in a filter description file and configures
a filter under lpsched. The filter description file and it's format are
described reasonably well in the Answerbook and on-line man pages.
When adding filters to a Solaristm; LP server, there are a
couple of important things to understand. First and foremost, a filter
will only run if it is required to run for the job to print. Second, filters
may be required to run either to convert data to a format acceptable to
a printer, or to fold in special required, options called modes.
For further information on writing and integrating filters, see the
LP filters web page, lpfilter(1M)
man page and/or LP Filtering web page,
the lpfilter(1M) man page, and/or
the System
Administrators Guide in the Answerbook.
Back-end
One very important interface in the Solaristm; LP server is it's
back-end interface. It is this interface that ultimately runs and communicates
the print job to the printer. The interface itself is simply a call out
to an external program. This program can be written in any language, compiled,
interpreted, whatever. The most common method of implementing this program
is via a shell script, because of this, the interface is generally referred
to as an interface script.
An interface script has a variety of inputs. The first set of input
are the command line arguments. These arguments supply the printer name,
request-id, user, title, number of copies, an options list, and the list
of files to print. With the exception of the options list, each of these
pieces of information is supplied in a separate command line argument.
The options list is supplied as a single command line argument, but it
can contain multiple options.
Another input the the interface script is the calling environment. The
lp server takes great care when constructing a calling environment for
an interface script to run in. This environment contains information about
character set the printer is to use, any fast filter that should be run
in-line to the printer, localization information, printer type, time zone
information, and a token to be used when communicating status back to the
scheduler. Each of these pieces of information are stored in environment
variables that can be accessed via getenv(3C)
in C or $VARIABLE in most shell languages.
A critical, input to the interface script is actually the set of open
files descriptors. When lpsched starts the interface script, it opens up
the actual print device for the script and passes the opened device to
the script as standard output. Standard error is actually an output. It
is a back channel to lpsched that can be used to communicate error information
back to the scheduler.
The last input to the interface script is an asynchronous input. That
is, the input can be supplied to the interface script at any time while
it is running. This input is supplied via signals. Actually, the only signal
that will be supplied from the scheduler is the SIGTERM (15) signal. This
signal is supplied when the scheduler wants the interface script to stop
what it's doing and terminate. It is usually supplied when the scheduler
is being shutdown, or someone is attempting to perform maintenance on the
printer.
Along with all of the above inputs to the interface script, it can communicate
information back to the scheduler via a couple of outputs. The first output,
which is described above, is the ability to send text messages back to
the scheduler via standard error. These messages are used, verbatim, as
the printer status message for lpstat. The second output is the exit code
of the interface script. The exit status of the interface script communicates
whether the script completed successfully, it failed and the job should
reprint, or it failed and the job should be tossed out.
For further information on interface scripts, how they work, and how
to write them, see the Interface Script
web page and/or the System
Administrators Guide in the Answerbook.
Faulting
As mentioned above, when an error is detected while passing a print job
to an output device, the interface script reports this error back to the
scheduler. This is done through the faulting interface. The
faulting interface is largely made up of a single program external to the
scheduler. This program, lp.tell, sends messages back from the interface
script to lpsched using the scheduler's communication FIFO. The messages
contain a
type (fault, clear fault), destination, key, and some amount of textual
information. It is these messages that trigger the alerting/notification
process in the scheduler. As stated, lp.cat is the program that passes
these messages to the scheduler. lp.tell is a relatively simple program.
It is placed in the process pipeline by an interface script while communicating
with the output device. It reads back the status messages from the
communication program (described below), makes a determination as to whether
the message is an error or not, and send a message to the scheduler.
Alerting/Notification
Upon detection of an error condition or when user interaction is required,
the LP server will attempt to perform a notification. This notification
is a simple call-out to an external program. It is configured under
LP using the lpadmin(1M)
command. Since alerting is done via a call-out, this program can
perform any task. Depending on the configuration, the notification
can occur a single time or at X minute intervals while the error condition
or requirement for user interaction persists. An interesting example
using audio alerts is provided in the PRINTtoys package.
For further information on writing and integrating notification programs,
see the LP Notification web page,
the lpadmin(1M) man page, and/or
the System
Administrators Guide in the Answerbook.
Forms (Media)
The LP server comes with built-in support for arbitrary preprinted media.
This media support, refered to as form support, allows end users to select
the media they require loaded in the printer at the time a print job is
printed. By default, all print jobs have no media selection when
submitted. For a use to request a type of media, the must supply
a media/form name using the '-f' option to lp when submitting the job.
Also, the server for the printer must have a defintion of the requested
media, the destination must be allowed to mount the media, and the user
must be allowed to use the media. If the media isn't present on the
destination at the time the job is ready to print, the LP server will hold
the job and request an operator to mount the media on the destination.
Once mounted, the operator must use lpadmin(1M) to notifiy the LP server
that the media has been placed in the printer.
For further information on integrating media/forms support, see the
LP Forms web page, the lpadmin(1M)
man page, lpforms(1M) man page,
and/or the System
Administrators Guide in the Answerbook.
Communication
Although, communication with the printer is handled via the back-end interface
script, the interface scripts supplied with Solaristm; run one
of three different programs to do the actual communication. These
three communication programs send print data to the output device and gather
status where possible. The program chosen to communicate with the
printer depends on the interfaces script run and the type of printer being
communicated with.
postio
The first program that may used to communicate with a printer is "postio".
Postio is used to communicate with PostScripttm; (PS, PSR) printers
attached to a serial port or parallel port (BPP, SPIF, ECPP). It
is configured under the standard interface script and reports back errors
via this interface script to lpsched. The errors it reports depend
largely on the connectivity to the printer. If the printer is connected
to a serial port, postio will send a '^t' PostScripttm; status
request to the printer and retrieve the printer's response before each
block of data is sent to the printer. This has the effect of providing
any error that the printer can generate. If the printer is connected
to a parallel port, postio assumes the connection to the printer is unidirectional.
Since it is believed to be unidirectional, the results of a '^t' status
request could not be retrieved. Instead, postio checks the pin status
from the parallel port itself. This allows postio to discern and
return the following error conditions: power off, off-line, paper out,
and busy.
lp.cat
lp/cat is used to communicate with all other locally attached printers.
It is also configured to run under the standard interface script and report
back errors via this script. Again, the errors detected and reported
back depend on the type of connection to the printer. If the printer
is connected to a parallel port, it can return the same types of errors
that postio did when it communicated with a printer on a parallel port.
If the printer is hooked up to a serial port, the reporting is essentially
limited to "can't communicate with printer". This is because many
serially connected printers don't support any form of status request.
With the exception of PostScripttm; printers, those that do support
a status request do so in a vendor specific manner.
Now, having said all of this, there is one small lie here. A serial
port is not always a serial port. In some cases people build elaborate
mechanisms to make their pie, pty, socket, driver, etc. appear to software
as a tty. Some simply push the ldterm streams modules on the stack.
If the device responds "correctly" to isatty(3C),
it is considered a serial port by postio and lp.cat. Both postio
and lp.cat check if the endpoint type using the following:
is is a BPP parallel port, -> use the
BPP port pin status
is it an ECPP parallel port -> use the ECPP
port status
is it a SPIF parallel port -> use the
SPIF port status
is is a tty
-> use '^t' status under postio (act like a dumb connection under lp.cat)
it must be dumb.
-> just send data in blocks, if we hang, report an error
netpr
One final program that is used to communicate with printers is netpr.
netpr is new to Solaristm; 2.6 and allows the LP system communicate
with network attached printers. It is capable of sending job data
to printers that implement the BSD Print
protocol (RFC-1179) or printers that can take a straight TCP stream
of print data. This program is configured to run under the "netstandard"
interface script, which is also new to Solaristm; 2.6. As
is the case with lp.cat communicating via a serial port, this programs
ability to detect and report more than rudimentary error conditions is
limited. Again, status results returned from network attached printers
are generally returns using vendor specific mechanisms and/or formats.
It is this that limits netpr's error reporting to transport related errors
only.
Which interfaces are Public?
Well, under Solaristm;, the only public printing related interfaces
are those described in the SVID or XPG4. These interfaces are lp(1),
lpstat(1),
and cancel(1). They include
client side functionality only. That being said, any of the interfaces
described here can be used to integrate support under the LP system with
the understanding the interfaces will change or be removed eventually.
Actually, this proclamation was made with the release of Solaristm;
2.3.
Solaristm; is a registered trademark of Sun Microsystems
Incorprated
PostScript is a registered trademark of Adobe Systems
Incorporated
Any other trademarks, service marks, etc that I may have
inadvertently used are property of their respective owners.