Although this article strongly references SCO
Unix printing, the background and trouble-shooting tips are
valuable on any Unix/Linux platform.
One of our clients is a family-owned and operated independent
insurance agency. The business was founded in the early
1950's, and was computerized around 1980. Professional
service and conservative management have produced steady growth,
resulting in constantly increasing data processing demands, as well
as an increased reliance on remote access and connectivity.
Another agency that we support referred this client to us in early
2001, right around the time they had determined that their
information processing technology was in need of
modernization. Needless to say ,
we wasted little time getting to it. :-)
Insurance is all about processing
information—a stupendous amount
of it. Accordingly, our
client handles a large volume of data on a daily basis.
Events of the last several years have substantially altered the
insurance landscape and thus our client's information processing
needs have become more complicated. As a result, they have
presented us with numerous opportunities to tackle interesting
technical problems. The subject agency currently
operates from three geographically dispersed offices, two of which
are satellite locations whose local systems communicate with the
central office via the Internet. In each office, one or more
Windows 2000 workstations are networked to one of our Uni-FITM Ultra160 UNIX
servers (one of which is AMD
Opteron powered—it's a
speedy little bugger), running SCO OpenServer
Release 5 (OSR5) and Samba for Windows
connectivity. Ironically, part of the solution to
our client's remote printing problem already existed at the main
office—it just wasn't
immediately apparent. There, printers are attached to the
local subnet and are driven through the standard OSR5
lp subsystem. The
network interface is handled by a custom driver named nlpcatd, which I had concocted some years ago during a
fit of annoyance caused by a particularly frustrating battle with
OSR5's built-in HPNP
(Hewlett-Packard Network Printing). The RLP
(Remote
Line
Printer)
client/server subsystem that will be described herein addresses
each of the above items. Before continuing, here are some
weasel words to entertain you. In order to better implement
RLP, you should know something
about how OSR5 runs your printers. With some of the above information
digested, I will now turn to specifics. The steps shown in blue are
standard OSR5 lp subsystem
operations, while those in red
are added by implementing RLP. Recall that
lp.catmerely writes on its
standard output, which means that in the above scheme , it has no
idea that it is not actually talking to a printer device. In
other words, as far as the lp subsystem is concerned, absolutely nothing that
it knows about has changed in any way, shape or fashion. What
has changed is what happens to the data stream after it
leaves lp.cat.
Here it goes to a fifo instead
of to a real device like /dev/lp0. This is the key to rerouting the data
stream onto the network. The "pump" in the above analogy
is lp.cat and the
"suction" is provided by nlpcatd. As data flows through the fifo,
nlpcatd will transfer it on
to the network and to the target printer. Mechanisms that are part of the TCP
protocol will assure that nlpcatd sends data to the printer only as fast as it can
accept it (a procedure called flow control). If the printer
goes off-line for any reason, such as because it has run out of
paper, nlpcatd will
patiently wait until someone shows up to refill the paper tray and
place the printer back into service. Ditto if the network
connection is temporarily broken. When all data has been
sent, nlpcatd will
disconnect from the printer and the cycle will
repeat. Setting up RLP on a typical OSR5 system is
straightforward. You will need to gather some information
about each RLP controlled
printer, and then perform some administrative tasks to get
everything working. The information you will need is as
follows: With the above information at hand,
you should proceed as follows:
In this article, and the one that will follow, I would like to
describe how we solved a particularly challenging issue facing this
client, using nothing more than good, old-fashioned UNIX methods
and know-how. Although
the topic of this article is a new method for implementing
distributed printing, you may find it useful to know something
about this client's system and what it was that led to our working
out a new remote printing subsystem for them. If you'd rather
get to the meat of the matter, just skip
ahead.BACKGROUND
Each office's server is the local Windows log-in server and master
browser, and also provides Windows printing
services. The main
office's server acts as the Windows primary domain controller and domain
master browserfor the entire
agency, and is also the central data repository. Windows
drive letter mappings that are established when a user logs in
provide varying degrees of access to insurance data, and also
institute Mozilla roaming
profiles. We laid out this system with the basic premise
that insurance agencies make money by writing policies and
servicing their clients, not by managing and troubleshooting
computers. Therefore, a lot of effort has been expended to
make this system secure, easy to use and reasonably
fool-proof.
Day-to-day agency management is performed with Redshaw Elite, which
is host-based, vertical software that was developed some 25 years
ago to run on Wang MVP minicomputers. During the 1980's,
Redshaw became an insurance industry standard and thousands of
agencies ran their operations on it. Around 1990, the
software was ported to UNIX
(originally SCO UNIX 3.2), using Kerridge Computer's idiosyncratic
KCML interpreter
to execute the Wang MVP BASIC programs that make up the
package. An officially supported OSR5 implementation was
never produced, although the
UNIX 3.2 version of KCML can be run in the OSR5 environment.
At the time of its UNIX port, it was thought that Redshaw would
eventually fade away and various Microsoft-based equivalents would
take over. Hence significant development came to a halt in
the mid-1990's. Although any number of Windows-based agency
management packages are now available, Redshaw is still in common
use, remarkable considering
that it is an old character-based app. The most-often cited reason for this is
that being host-based and character-oriented, Redshaw is a friendly
and stable package with modest resource requirements
—nothing runs on the client except a
terminal emulator—and that i t
performs at a level which makes the Windows equivalents look like
sumo wrestlers trying to compete in Olympic pole vaulting.
This is not to say that Redshaw is computer nirvana for overworked
insurance agents. For one thing, there's that screwball KCML
interpreter to consider—it se
ems to have been designed by Lucifer himself, what with dongle
protection, the unique and obtuse Wang MVP BASIC dialect, and a
very strange system interface. Also, Redshaw's data storage
methods emulate the old Wang MVP "platter" setup, which grossly
under-utilizes the capabilities of modern UNIX filesystems,
especially in the area of the maximum amount of live data that can
be accessed in a Redshaw session. And, of course, ongoing
development no longer exists.
More seriously, Redshaw is not network-aware, a natural consequence
of its age. It is possible for a remote client to Telnet into
the server and start a session. However, Redshaw
knows nothing about NFS or other
standard UNIX network services, and only understands locally attached
printers. The latter
limitation is particularly onerous, as Redshaw cannot talk
to lpd (li ne printer
daemon) printers, thanks to the odd method by which the KCML
interpreter interacts with the lp subsystem. The result is that while it is possible
for a remote client to run Redshaw over the Internet, it is not
possible to send printer output back to that client using orthodox
methods.
Up until recently, remote printing from Redshaw wasn't an issue
with our client, as only one of the two satellite offices was in
operation, and it was staffed only by appointment. If the
agent at that office needed hardcopy, s/he would print to one of
the printers controlled by the Redshaw host in the main office and
then have someone there fax over the results—naturally a cumbersome and inconvenient
procedure, and not practical with certain types of forms (e. g.,
auto insurance ID cards).
When our client indicated that they were going to staff the first
satellite office full time and were planning to open another
location, Redshaw's remote printing problems suddenly became a
major malfunction, and a solution had to be
devised.
"rlp01">REMOTE LINE PRINTING
Prior to writing my own code, I had perused this site (and a few
others) seeking a solution that didn't require HPNP. Many
that I investigated involved the use of modified printer interface
scripts that put Kevin Smith's handy netcat
utility to work sending packets to the
printer s. I was
reluctant to adopt this approach, as the use of custom printer
interface scripts can open the door to hard-to-solve coding errors,
as well as possible loss of functionality due to someone
substituting a different script for the modified version.
Also, it was clear that the result would not be particularly
portable to non-SCO systems. Did I mention security issues
that could arise with using a filter like netcat
to print to a printer over the
Internet? After mulling
over this stuff for a while, I decided to head off in another
direction.
My analysis of the situation identified three
requirements:
I have been running various
incarnations of RLP
on our main office file and print
server (currently OSR 5.0.6 with Samba 2.2.12) since mid-2000 without any
significant incidents. I have even used the latest version
of RLP to print
stuff on my clients' printers from here in my office (in once case,
I sent a client an invoice by printing it on his printer from my
office—thereby saving the cost
of an envelope and stamp). Based on this experience, I believe I have
developed a workable arrangement that any reasonably competent UNIX
administrator can implement on his/her OSR5 machine(s), or with a
little modification, on Linux or other UNIX hosts.
In this first article, I will address the driving of printers that
are directly exposed to a network and that listen for data on a
particular TCP port—this
describes many networked printers, both those with built-in
networking and those that are attached to an external print
server. The next article will describe the scheme I contrived
for driving a printer that is under the control of another UNIX or
Linux server, without involving lpd. Although RLP does not use it, you should obtain a copy
of netcat
and learn how it
works. You will discover netcat to be a very useful network diagnostic tool (I've
used it to debug router problems, among other things), as
well as a handy device for getting acquainted with some of the
interesting aspects of communicating through a
network. You should also
obtain a copy of Jeff Liebermann's print
server port number list, which information will be required in
order to configure your system to use RLP. All of this will be explained in
due course.DISCLAIMERS
While I have no reason at this time to suspect that there are any
fatal flaws in what I am about to present, I guarantee nothing. Furthermore, before you get all excited
about setting up your own RLP
subsystem and linking all your
friends' and family's printers to your home network, please be
certain that you fully understand the security implications of
exposing your system (and theirs) to the
Internet. If you choose to implement anything described
in this article, you do so at your own risk. I take
no responsibility for anything
that might go wrong, explode, start fires, annoy your dog, bankrupt
your business or otherwise ruin your day.
Please keep in mind the part about being a "reasonably competent UNIX
administrator." If
this doesn't describe you,
please seek professional
help. I may respond
to reasonable questions posted in the Wiki comment section
following this article, but complaints of the form "It doesn't
work, UNIX/Linux sucks and I'm going back to Windows!" will be
politely ignored—by me,
anyhow.
<Smile>
Incidentally, I have been known to express that exact sentiment on
occasion, but with "UNIX/Linux" and "Windows" interchanged.
RLP is freeware. It is
not in the public domain and has not been released under the
GNU
General Public License (GPL). You are permitted to use
and distribute RLP to your
heart's delight, provided
copyright notices and attribution remain intact. If you wish to bundle RLP with your commerical package you may do so
but MAY NOT charge your
customer for RLP. You
didn't pay for it and neither should he. :-)
Copying, redistribution and/or quoting of this article is also
permitted, provided author and source attribution are given and the
guidelines of this
website's operatorare
observed. If you decide my code is a classic example of
compiler abuse and decide to rewrite it from top to bottom, please
consider that RLP is an ongoing
project and is likely to change in some way in the future.
Any such changes will probably render independent modifications
invalid.
OSR5 PRINTING
Conventional OSR5 printing involves the use of the
lp subsystem to communicate with one or more
printers hardwired to EIA-232 (serial) and/or Centronics (parallel)
ports on the host machine. Printing is initiated by writing
something to lp's
standard input or by passing one or more filenames to be printed as
command line arguments to lp. In either case, lp willhandle
all of the subterranean mumbo-jumbo required to drive the target
printer and report back with a job ID, such as
hp2300a_1147. In more
academic terms, lpprovides a layer of abstraction between the user
application and the physical device on which printed output is to
appear. Hence the application doesn't need to know anything
about the way the printer is hooked up to the server in order to
print.
Interposed between lp and the target printer is a file called an
interface script, in which the incantations required to control the
printer are contained (incidentally, an interface script
is not a driver).
When a print request is submitted, the statements in the interface
script will be executed to process command line options passed
to lp
as part of the print request and to
arrange for the data flow to find its way to the target
printer. OSR5 ships with
a variety of interface scripts (called models) that support common
printer types, the appropriate script being selected at the time
the printer is configured into the system.
Also configured during printer installation is the device to which
the output will be sent, defined by filesystem names such as
/dev/lp0 or /dev/tty1a14. In OSR5, actual communication with the
device is normally handled by a filter called lp.cat, which is executed by the interface
script. lp.cat writes on its standard output, normally directed to the device file associated
with the target printer. However,
lp.cat's output can be
redirected, such as to the local subnet. This is the basis
for printing to network attached printers.
As mentioned before, what started me on the road to RLP was trouble with the HPNP component of the
standard OSR5 printing software. HPNP is a cantakerous
conglomeration of code that will often fail to
performdue to its reliance upon SNMP (Simple NetworkManagement Protocol, with Stupid often being substituted for
Simple). SNMP is not
universally implemented in printers and print servers, and unless
changes are made to the HPNP operation to account for this,
non-SNMP aware printers may not respond to HPNP at all, and, of
course, won't print.
All in all, my take on standard OSR5 network printing via HPNP is
that it is a poorly designed arrangement, a Rube Goldberg-ish
mishmash that was apparently concocted by an inebriated gorilla
wielding a crowbar and sledge hammer. In my opinion, the
whole mess flies in the face of good UNIX
practice.IT's ALL IN THE
PLUMBING
The data flow that occurs when a job is submitted to an
RLP controlled network printer
looks something like this:
A short digression: a fifo (First In,
First Out)or named pipe
is nothing more than a conduit for data. Using an obvious
plumbing analogy, something delivers water to a pump at one end of
the fifo, the pump pushes it through, and something else sucks the
water out of the other end and delivers it to yet another
location. If the pump
runs out of water and stops pumping, suction will stop and
wait. Conversely, if the pipe fills up because suction has
stopped, the pump will likewise stop and wait.
SETTING UP LOCAL RLP
Although the
printer's TCP port number is something that is usually hard coded
into its network interface, a few manufacturers allow you to set
the port to anything desired. If your print server is such a
unit, do not use any port number below
1024, a s such ports are considered privileged (aka
"well-known") and are not acceptable to
nlpcatd.
If possible, assign a port number higher than 49151, as such ports
are "dynamic" and are guaranteed to not be used by anything in
particular. Ports between 1024 and 49151 inclusive are
referred to as "registered" and many are assigned to specific
entities. If you use a registered port number and then later
install other software that happens to use that registered number,
you may be in for an unpleasant suprise.
mkfifo -m 660
/dev/<lp_dest>
# example nlpcatd.conf file # hp2300a rp00 hpjd0 d laser in Pete's office hp3000a rp01 hpjd0 d inkjet by Mary's desk oki395a rp02.somewhere.com hpdj0 d dot matrix in Chicago warehouse
At this point, you should be ready
to see if your RLP subsystem is
functional
Checking out your handiwork for
proper operation needs to be accomplished before unleashing your
new RLP service on your
unsuspecting users. The first step is to manually start
nlpcatd, for which you must
be logged in as root,
to determine that your configuration is correct.
The formal command line syntax recognized by
nlpcatd is:
All arguments are optional and have
the following meanings:
For the purposes of testing the
initial setup, start nlpcatd with the -l and -P options. If you have correctly configured your
system, you should see a PID reported for each printer followed by
the shell prompt. Also, a log for each printer should have been
started in whatever directory you chose.
If there is are problems at
start-up, nlpcatd will
complain in various ways. Errors such as a missing configuration
file or an improper log directory name will cause an immediate
abort. Errors in individual configuration entries will prevent a
daemon associated with the affected printer from starting. For
example, if nlpcatd cannot resolve a host name to an IP address
and/or a service name to a TCP port, the daemon will immediately
fail, but will not affect others that have already been started.
Another source of failure would be a name mismatch between a
printer and its associated fifo. Yet another would be incorrect
permissions and ownerships on fifos. If something like this happens, stop the
other nlpcatd daemons
with kill <PID> , fix whatever it is that caused the error(s) and
restart nlpcatd.
Once you have
nlpcatdstarted, the next step
is to see if something can be printed at each printer. Issue the
command echo "This is is a
test.\f\c" > /dev/<lp_dest> for each nlpcatd defined printer. The target printer should
immediately print This is a test. and eject a page. If all defined printers pass
this test, nlpcatd is
fully functional and any subsequent printing problems will most
likely be due to improper lp subsystem configuration.
Next, try printing something to
each printer via the lp subsystem. If a printer fails to respond but did
respond to the direct write to fifo test described above, carefully
examine the lp subsystem configuration for that printer. Also,
recall the caveat mentioned earlier about an Stty
statement in the printer's lp
subsystem configuration file. Generally speaking, if a daemon for
any given printer succeeds in starting and logs the correct
configuration data for that printer, you should be able to print.
Obviously, errors such as improper IP addresses, improper TCP
service definitions, etc., will prevent your printers from
responding.
With logging enabled, entries take
on the following format:
All of this should be
self-explanatory.
Once you are satisfied that your
new RLP subsystem is okay you
need to arrange for nlpcatd to automatically start at boot time. The best
way to do this is to create a small shell script in the
/etc/rc2.d subdirectory.
The following assumes that the default configuration file pathname
(/usr/local/etc/nlpcatd.conf) is to be used:
Make sure this script is owned
by root:sys and
has rwxr-x--- permissions. I suggest that you name it
S99nlpcat to assure that
everything else associated with starting network services has been
completed first. Startup
commentary will be written into
/etc/rc2.d/messages/S99nlpcat.log. Look in ther e if you have trouble
getting nlpcatd to
start at boot time.
Well, most anything associated with
networking can go wrong, and nlpcatd is no exception. There are a number of possible errors that may
occur once an nlpcatd daemon has been spawned. Fatal errors
include:
Non-fatal errors
include:
Failure to print could also be
caused by lp subsystem
configuration woes. If a direct write to a fifo produces printer
output, yet submitting a print job through lp
does not, check the
following:
Well, this about covers network
printing for now. In the next article, I will present the other
half of RLP, which will allow
you to securely print to printers controlled by the
lp subsystem on another host.
Stay tuned!
Got something to add? Send me email.
More Articles by BigDumbDinosaur © 2011-03-17 BigDumbDinosaur
Don't get suckered in by the comments … they can be terribly misleading. (Dave Storer)
---January 3, 2005
Not sure I entirely understand this:
"Prior to writing my own code, I had perused this site (and a few others) seeking a solution that didn't require HPNP. Many that I investigated involved the use of modified printer interface scripts that put Kevin Smith's handy netcat utility to work sending packets to the printer s. I was reluctant to adopt this approach, as the use of custom printer interface scripts can open the door to hard-to-solve coding errors, as well as possible loss of functionality due to someone substituting a different script for the modified version. Also, it was clear that the result would not be particularly portable to non-SCO systems. "
Netcat can be used in exactly the same way as this - reading a fifo created by a standard interface. And as the source code is available, how is it less portable?
Great article though.
---January 3, 2005
Well, I agree, but for one thing this does add more configuration capability..
--TonyLawrence
"Netcat can be used in exactly the same way as this..."
Actually, netcat cannot be used in the same way, which I thought I had explained in the article (I guess I better reread it and see what I forgot to include).
netcat reads from its standard input, which means that something else would have to connect the fifo to netcat's STDIN (e.g., cat fifo | netcat -h host -p port). Otherwise, netcat would have to be modified so an input source could be specified as a command line option, a mod I had considered prior to writing nlpcatd. I scrapped that thought because it would have resulted in multiple versions of netcat floating around, and problems would have inevitably ensued when someone tried to use the wrong version to do what I described in the article.
Aside from how to get data from the fifo to netcat, another concern I had was netcat's willingness to connect to any port. While this capability is very useful in many contexts, remote printing is not one of them. As I described in the article, I wanted to avoid the use of privileged ports, which by inference, meant I wanted to enforce the use of registered or dynamic ports only. I could not do that with netcat.
Third consideration: netcat's debugging wasn't what I was looking for. Being a general purpose filter, netcat's logging is also general purpose. I needed a different form of logging. Again, I could have reworked netcat to achive this, but didn't for the reasons explained above.
Fourth consideration: netcat cannot translate service names to port numbers. Using port numbers to identify services is not good practice, for the same reason one shouldn't use IP addresses to refer to machines. Once more, this capability could have been added...
Fifth consideration: as soon as netcat is started it connects to the remote host, which means a continuous network connection is maintained, active or inactive. If a system has, say, 50 printers (a bank I used to service had 48 printers, all attached to the network, so I'm not blowing smoke here) that's 50 network sockets in simultaneous and continuous use. Printers spend much of their time doing nothing -- which means the open network connections are also doing nothing, and uselessly consuming system resources.
In contrast, nlpcatd does not consume network resources until there's work to be done, and releases those resources as soon as all data received from the fifo has been forwarded to the printer. With one or two printers, this might not seem so important to you. Consider that 50 printer system, however, and your thinking will quickly change. Network resource allocation is an expensive process and if enough happens at one time, can cause a system to drag its tail.
Sixth consideration: netcat's error handling isn't sufficiently robust, given the nature of the task at hand. netcat will abort in the face of some network errors from which recovery is otherwise possible.
"And as the source code is available, how is it less portable?"
The portability issue to which I was referring was that of relying on customized interface scripts and/or undocumented lp subsystem modifications to redirect printer output to the network. Although I geared my package to OSR5, I was also thinking in terms of other UNIXish systems, where the lp subsystem could take on a different form.
--BigDumbDinosaur
Connecting to a fifo:
while true
do
exec
netcat -h host -p 9100
done
but otherwise, yes, I agree.
--TonyLawrence
"but otherwise, yes, I agree."
I must've missed something here. <Grin> To what is it you're agreeing? Pardon the dunderheadedness on my part.
--BigDumbDinosaur
---January 3, 2005
Well, I'm agreeable to most things, but in this case I was agreeing with your comments as to why netcat wasn't suitable for your requirements..
:-)
--TonyLawrence
---January 4, 2005
Tony -
The RLP Printing Block Diagram in this article does not appear on the fullstyle.html page. It does appear on the individual article page.
--Bob
Printer Friendly Version
Simplified SCO_OSR5 Printing Copyright © January 2005 BigDumbDinosaur
Have you tried Searching this site?
This is a Unix/Linux resource website. It contains technical articles about Unix, Linux and general computing related subjects, opinion, news, help files, how-to's, tutorials and more.
Contact us
Printer Friendly Version