Simplified OSR5 Printing

Although this article strongly references SCO Unix printing, the background and trouble-shooting tips are valuable on any Unix/Linux platform.


By BigDumbDinosaur, BCS Technology Limited

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 informationa 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.

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.


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 poweredit's a speedy little bugger), running SCO OpenServer Release 5 (OSR5) and Samba for Windows connectivity.

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 requirementsnothing runs on the client except a terminal emulatorand 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.


Ironically, part of the solution to our client's remote printing problem already existed at the main officeit 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).

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

  • Achieve transparent operation without regard to how printers are exposed on the network.  Operation should be the same whether a printer is networked through internal hardware, is a parallel port model attached to a print server device (e.g., a Hewlett-Packard JetDirect), or is a unit controlled by the lpsubsystem of another UNIX or Linux server.  Implied in this requirement was that operation should work over the Internet as well as on the local subnet, assuming that suitable routing existed.

  • Prevent unauthorized connections to printers.  Obviously, security is always a major concern on anything that is exposed to the Internet.  My security approach would be two-fold: authenticate incoming connections to printers against a list of authorized clients, and restrict TCP port usage to the registered or dynamic range.   The latter would obviate the need to relax firewall packet filtering rules, thus minimizing the likelihood of an intrusion through a privileged port.

  • Eliminate the need to modify lp subsystemfiles.  Many of the methods described in other articles have involved the modification of printer interface scripts to redirect output to programs like netcat and thus on to the network.  As I said before, I felt that the package would be more portable if it could be made to work with whatever interface scripts were provided with the standard operating system installation.

The RLP (Remote Line Printer) client/server subsystem that will be described herein addresses each of the above items.

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 officethereby 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.


Before continuing, here are some weasel words to entertain you.

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.


In order to better implement RLP, you should know something about how OSR5 runs your printers.

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, which is executed by the interface script. writes on its standard output, normally directed to the device file associated with the target printer.  However,'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 perform
due 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.


With some of the above information digested, I will now turn to specifics.

The data flow that occurs when a job is submitted to an RLP controlled network printer looks something like this:

RLP Printing Block Diagram

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  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.

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.  I
f 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.

The "pump" in the above analogy is 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:

  • lpsubsystem destination name.  This is the name by which the lp susbsystem "knows" the printer, and may be any name that makes sense to you.  The scheme I like to use is <model><suffix>, where <model> is a synopsis of the make and model of the printer, and <suffix>is a single letter of the alphabet.  For example, if there are two Hewlett-Packard LaserJet 2300 printers, the first would be designated hp2300a and the second hp2300b.  A Mannesman-Tally 6050 impact line printer would be named mt6050a.  On OSR5, the lp subsystem imposes a 14 character limit on destination names, and allowable characters are A-Z, a-z, 0-9 and the underscore.  I recommend that you do not use uppercase letters.  In paragraphs that follow, I will refer to the lp subsystem destination name as < lp_dest>.

  • Host name.  The host name is also something that you think up, subject to the limits imposed by the operating system.  The naming convention I use is rp00 for the first defined printer, rp01for the second, etc.  If the printer or the host server that controls it is not in the local domain, use a fully qualified domain name, such as  In any case, I do not suggest using the lp destination name as a host name, because it is possible to create an lp destination name that is incompatible with the host naming rules that the operating system enforces.  In paragraphs that follow, I will refer to the host name as <host> .

  • IP address.  Each networked printer must have a unique IP address, which you usually assign when you configure the printer for the first time.  For private, non-routable subnets, like a office LAN, the IP address will be something like or  I generally work backwards with printer IP addresses: for example, on our office system, rp00 is, rp01 is, and so forth.  If a printer is to be exposed to the Internet (that is to say, connected directly to a gateway to the Internet), it will need a routable, public IP address, which you can get from your Internet service provider.  This is not a recommended setup, since most networkable printers have little or no built-in security.  You don't want the neighborhood script kiddie sending suggestive remarks or risquè pictures to your printer, right?  :-)

  • TCP port number.  The majority of networked printers in use today operate by listening for connections on a specific TCP port  and transcribing any incoming data into hardcopy (don't confuse a TCP port with a hardware port on a computerthey're two entirely different things).  There is no universal standard for assigning TCP ports to network printers, so you will need to consult this list or contact the manufacturer of your printer to determine the correct port numbers.  Note that RLP cannot print to a printer that doesn't work as I just described.  If your printer is in that category you can stop reading right here.

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.

  • Service name.  A service name is a menmonic that is used to refer to a TCP port number.  For example, smtp (Simple Mail Transport Protocol) is the service name that refers to TCP port 25 (through which E-mail arrives and leaves).  You will need to associate service names with the TCP ports on which your printers are listening.  For example, an H-P JetDirect 300x print server, which is equipped with one parallel port, listens on TCP port 9100, to which I would assign the service name hpjd0.  H-P's 500x print server is fitted with three parallel ports and listens on TCP ports 9100, 9101 and 9102.  Logical (to me, at any rate) service names would be hpjd0, hpjd1 and hpjd2.  Obviously, you can pick any service names you want, as long as they are uniquecheck /etc/services to verify that you are not creating duplicates.  In paragraphs that follow, I will refer to this name as <service>.

With the above information at hand, you should proceed as follows:

  • Place a copy of nlpcatdinto any convenient location on your system, such as /usr/local/bin.  Be sure nlpcatd is owned by bin:lp and has rwsr-s--- permissions (chmod 6750 nlpcatd will do it).  You should also obtain a copy of  nlpcatd's configuration file nlpcatd.conf and use it as a model for your own version.

  • Define a fifo for each RLP controlled printer.  The OSR5 command to do so is:

mkfifo -m 660 /dev/<lp_dest>

For example:

mkfifo -m 660 /dev/hp2300a

Be sure that any fifos thus created exactly match the lp subsystem destination name of the associated printer, are owned by bin:lp and have rwrw----- permissions.

  • Create the nlpcatd.conffile and place it in any convenient location on your system.  It should be owned by root:lp and have rw-r--r-- permissions.  The compiled in (default) pathname for this file is /usr/local/etc/nlpcatd.conf.  However, you may specify an alternate pathname as a command line argument to nlpcatd when it is started.

nlpcatd.conf provides the information need by nlpcatdto locate the network printers.  The internal structure of this file is straightforward in design, consisting of a one line entry for each defined printer, with space or tab delimited fields:

<lp_dest> <host> <service> <type> <comment>

All fields are case-sensitive.  The <lp_dest>, <host> and <service> entries have already been discussed.  The <type> field should be d for a printer directly exposed to a network (whether on the local subnet or somewhere on the Internet).  For example, an H-P JetDirect-equipped printer would be a d type , even if attached to the Internet on a remote router.  The other type would be sfor a printer that is controlled by the spooler of a foreign host.  This type of setup will be discussed in the next article.

Here's an example of a properly formatted nlpcatd.conf:
    # example nlpcatd.conf file
    hp2300a  rp00                hpjd0  d  laser in Pete's office
    hp3000a  rp01                hpjd0  d  inkjet by Mary's desk
    oki395a  hpdj0  d  dot matrix in Chicago warehouse

Anything after the fourth field is treated as a comment and is ignored. The octothorpe (#) normally us ed to delimit a comment is not required unless the comment is the only thing on a line. Blank lines are okay.

  • Create a <host>entry in /etc/hosts for each defined printer. A proper entry for a printer with the host name rp00, assigned the IP address, would be: rp00

If your system relies upon DNS to resolve host names, be sure suitable A and PTR records are created for each network printer.

  • Create a <service> entry in /etc/servicesfor each defined network print service. A proper entry for a service name hpjd0 associated with port 9100 would be:

hpdj0 9100/tcp # H-P JetDirect parallel port 1

Only one service definition per service should be made, regardless of how many printers listen on that service. A terse comment explaining what service is being supported should be made at the end of each service entry. Look at other entries in /etc/services for guidance.

  • Define each printer in the lpsubsystem. On OSR5 the appropriate command syntax to set up a new printer is:

lpadmin -p -b 0 -c "<comment>" -m <model> -o nobanner -v /dev/<lp_dest> <lp_dest>

where <comment> is a reasonable terse description of the printer (e.g., "Mary's inkjet -- HP3000"the double quotes are required) and <model> is the interface script to be used with this printer. You can determine which model scripts are available by looking in /var/spool/lp/model. The -v /dev/<lp_dest> argument tells lpadmin that the device associated with the printer is the fifo that was created earlier.


If you decide to use scoadmin functions to define your printers instead of the above lpadminincantation, there is a little "gotcha" that you will need to consider. Associated with each printer that you define is a configuration file named /var/spool/lp/admins/lp/printers/<lp_dest>/configuration . By default, scoadmin will place an Stty statement in this file, for example, Stty: 9600 cs8 -parenb. Remove this statement from the file before attempting to use the printer.

  • Verify that each printer is attached to your network, is powered up and on-line. Yeah, I know. This step is rather obvious. However, I have "f ixed" more than a few "dead" printers by merely applying powerand placing them on line, or by plugging in the network patch cord that was neatly coiled up right behind the unit. :-)

If you aren't sure that everything is as it should be, try pinging any suspect printers or try connecting to them with netcat (netcat -dh <host> -p <port>, where <port> is a TCP port number), which will also verify that the TCP port number you set up in /etc/services is in fact the correct one.

At this point, you should be ready to see if your RLP subsystem is functional

TESTING 1 2 3...

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:

nlpcatd [-V]|[-c <conf>] [-l <logdir>] [-P]

All arguments are optional and have the following meanings:

-V Causes nlpcatd to report its version on STDOUT and exit. Four tab delimited fields will displayed: the program name, version number, compile date and time, and the source author. This option cannot be combined with any other.

-c <conf> As explained before, nlpcatd, by default, looks for a file named /usr/local/etc/nlpcatd.conffor configuration information. If you prefer to locate this file elsewhere or give it a different name, specified the fully qualified pathname in <conf>. nlpcatd will complain and abort if it cannot open the file

-l <logdir> If specified, nlpcatd will log debug chatter into a file named <dir>/log.<lp_dest>, with a separate log maintained for each printer. For example, if <dir> is /usr/local/adm and the printer is hp2300a, the log file will be /usr/local/adm/log.hp2300a. The directory specified by <dir> must already have been defined and bin must have write permission on it.

You should use the logging option sparingly, as a busy system may rapidly inflate log files. If you wish, you can start nlpcatd with logging enabled, and later turn it off or on by sending a SIGHUP to each daemon that was started. Each time logging is toggled an entry to that effect will be written into the log. If logging was not enabled at startup, SIGHUP will have no effect.

-P When nlpcatd starts, it will spawn a separate daemon for each printer defined in nlpcatd.conf. -P will cause nlpcatd to announce on STDOUT the process ID (PID) and printer associated with each daemon that was started. The tab separated display will appear similar to the following:

504 hp2300a
505 hp3000a
506 oki395a

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:

========================= =========
nlpcatd V1.4 Configuration Summary
2004/12/21 16:18:29
========================= =========
process ID : 8362
config file : /usr/local/etc/nlpcatd.conf
printer : hp2250a
host name : rp00
service : hpjd0
printer type: direct connect
FIFO name : /dev/hp2250a
host IP info:
========================= =========
main(): *** waiting for activity ***
openfifo(): /dev/hp2250a opened for reading on (0)
socket(): AF_INET socket opened on (1)
connect(): connected to
write(): 85199 bytes transferred
shutdown(): disconnected from
main(): (1) closed
main(): (0) closed
main(): *** waiting for activity ***

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:

#@(#) nlpcatd startup
nlppath=/usr/local/bin ; # execution path
logdir=/usr/local/adm # where logs will be written

[ -x "$nlppath/$nlpcatd" ] && { # if nlpcatd is executable
$nlppath/$nlpcatd -l $logdir -P || {
echo "${nlpcatd}: error $?: unable to start\a" 1>&2
exit 1
echo "! *** network line printer services starte d ***"
exit 0

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:

  • Failure to resolve a printer host name or service. Did you forget to make an entry into /etc/hosts and/or /etc/services? If you are relying on DNS to resolve your host names, is it properly configured and running (you can check the latter with ndc status)? Try using nslookup to see if your system can, in fact, resolve the printer host name to an IP address.

  • Use of a privileged port. For security reasons, nlpcatd will not allow connections to take place over a privileged (well-known) port, that is, port numbers below 1024. Check your /etc/services entries to be sure you didn't associate a privileged port with one of your printer service names.

  • Failure to open the fifo associated with a printer. Obvious reasons include: the fifo doesn't exist, isn't in the /dev subdirectory or has the wrong name. Less obvious are ownership and permissions issues. Fifos must be owned by bin:lp and have rw-rw---- permissions.

  • Failure to obtain a network socket. Each time nlpcatd attempts to contact a printer it must first set up a data structure to establish a network connection. The available number of network sockets is limited by how the kernel has been configured, and it is conceivable that a socket will not be available when requested. Since any system that would experience this sort of error is running on the ragged edge of reliability, nlpcatd will take the safe route and terminate.

Non-fatal errors include:

  • Unable to contact host. This could be caused by almost anything, including the aforementioned cases of no power to the printer or no connection to the network. It could also be the result of changing an IP address after nlpcatd has started (currently, nlpcatd only resolves the host at startup and thereafter expects the IP address to remain staticthat will change in a forthcoming revision). If the connection is through the I nternet, then all sorts of interesting possibilities will crop up, most of which will be out of your control. nlpcatd is relentless, however, as it will repeatedly attempt to contact the host, trying at 15 second intervals.

  • Socket write error. Exactly why this would occur, I couldn't say for sure. However, if such errors start to pop up in the logs, it's probably time to take a good look at your network and see if your hardware is misbehaving. You might have a faulty hub or switch that is occasionally mangling or dropping packets for you. Or perhaps a cable run is flaky. Of course, if the connection is over the Internet, many more factors will get into the picture, for example, propagation delays. Again, nlpcatd will make repeated attempts to write to the printer.

  • EOT with no data. This simply means that something opened the input end of the fifo and then closed it without actually writing anything. You can simulate such a condition with cat > /dev/<lp_dest> and then typing Ctrl-D to break the connection (don't type anything else).

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:

  • Is the lpscheduler running? Again, this seems obvious but should be checked.

  • Has the printer been defined in lp? Yes, another obvious one, but mistakes do happen.

  • Does the printer definition point to the correct fifo? lp will obediently send output to any place you tell it to--including /dev/null.

  • Is there an Sttystatement in the printer's configuration file? You can't set stty parameters on a fifo, so such a statement will cause failure.

  • Does the user who can't print have access rights to the printer? If only root can print, this would be the first thing to investigate.

  • Did you use the correct interface script (model) for the printer in question? One more obvious thing that should be checked.

  • Are you correctly invoking lp? Depending on the application that is trying to print, you may need to specify the -c option to lp if a submitted job fails to print for no other apparent reason. It could be that the file being printed is being deleted too soon after being submitted to lp. This type of failure will often produce some kind of cryptic complaint from lp about missing files.


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.

(OLDER) <- More Stuff -> (NEWER) (NEWEST)

Printer Friendly Version

-> -> Simplified OSR5 Printing

Increase ad revenue 50-250% with Ezoic

More Articles by © BigDumbDinosaur

---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..


"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.


Connecting to a fifo:

while true


netcat -h host -p 9100


but otherwise, yes, I agree.


"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.


---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..



---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.


Kerio Samepage

Have you tried Searching this site?

Unix/Linux/Mac OS X support by phone, email or on-site: Support Rates

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

privacy policy