This chapter includes:

Overview of printing

The simplest way to print a text file is to send it directly to a printer. For example, if your printer is attached to your computer's parallel port, you could simply type:

cat file > /dev/par

but there are a few problems with this:

It's better to use spooling. When you spool a print job, it's placed in a queue until its turn comes up to be printed.

Neutrino provides two separate mechanisms for print spooling:

If you want to use the lpr family, you have to set up the printer-configuration file, /etc/printcap.

You can use lpr, spooler, or both, depending on how you've set up your machine and network:

Another difference is that the lpd daemon manages all of the defined printers; spooler manages one printer, but you can run more than one instance of spooler at a time.

Printing with lpr

The lpr line-printer system supports:

To print a file using the line-printer system, you need:

Note: You need to log in as root to set up the lpr system.

User interface

The line-printer system consists mainly of the following files and commands:

The lp family

Printing with the lpr utilities.

Printer daemon that does all the real work.
Program to enter a job in a printer queue.
Spooling queue examination program.
Program to delete jobs from a queue.
Program to administer printers and spooling queues; only root can use this utility.
A master database that describes printers directly attached to a machine and printers accessible across a network. It describes the available printers and how to communicate with them, and it specifies the values for important items (e.g. the spooling directory).

lpd — printer daemon

The lpd program, which you typically invoke at boot time from the /etc/rc.d/rc.local file (see the Controlling How Neutrino Starts chapter), acts as a master server for coordinating and controlling the spooling queues configured in the /etc/printcap file. When it starts, lpd makes a single pass through the /etc/printcap database, restarting any printers that have jobs. In normal operation, lpd listens for service requests on a socket within the Internet domain (under the “printer” service specification) for requests for printer access.

The daemon spawns a copy of itself to process the request; the master daemon continues to listen for new requests. The daemons use simple text files as lock files for synchronization; the parent daemon uses /usr/spool/output/lpd.lock, while its children use a .lock file in the printer's spool directory, as specified in the printcap file.

Clients communicate with lpd using a simple transaction-oriented protocol. Authentication of remote clients is done based on the “privileged port” scheme employed by rshd. See Access control,” below.

lpr — start a print job

The lpr command lets you put a print job in a local queue and notifies the local lpd daemon that new jobs are waiting in the spooling area. The daemon either schedules the job to be printed locally, or if printing remotely, attempts to forward the job to the appropriate machine. If the printer can't be opened or the destination machine can't be reached, the job remains queued until the work can be completed.

lprq — show printer queue

The lprq program works recursively backwards, displaying the queue of the machine with the printer and then the queue(s) of the machine(s) that lead to it. This utility has these forms of output:

lprrm — remove jobs from a queue

The lprrm command deletes jobs from a spooling queue. If necessary, lprrm first kills a running daemon that's servicing the queue and restarts it after the required files are removed. When removing jobs destined for a remote printer, lprrm acts like lprq, except it first checks locally for jobs to remove and then tries to remove files in queues off-machine.

Note: You can remove only your own print jobs from the queue.

lprc — printer-control program

The lprc program is used to control the operation of the line-printer system. For each printer configured in /etc/printcap, lprc may be used to:

The lprc program gives the root user local control over printer activity. Here are the program's major commands and their intended uses (see the Utilities Reference entry for the command format and full list of commands).

Enable printing and ask lpd to start printing jobs.
Terminate an active spooling daemon on the local host immediately and then disable printing (preventing new daemons from being started by lpr). You typically use the abort command to forcibly restart a hung printer daemon (e.g. when lprq reports that a daemon is present, but nothing is happening).

The abort command doesn't remove any jobs from the spool queue; for this, use lprrm.

enable and disable
Turn spooling in the local queue on or off, in order to allow or prevent lpr from putting new jobs in the spool queue.

For example, you may want to use the disable command when testing new printer filters, because this lets root print, but prevents anyone else from doing so. The other main use of this option is to prevent users from putting jobs in the queue when the printer is expected to be unavailable for a long time.

Allow ordinary users to restart printer daemons when lprq reports that no daemon is present.
Halt a spooling daemon after the current job completes; this also disables printing. This is a clean way to shut a printer down for maintenance. Note that users can still enter jobs in a spool queue while a printer is stopped.
Place selected jobs at the top of a printer queue. You can use this command to promote high-priority jobs (lpr places jobs in the queue in the order they were received).

Spooling directories

Each node you wish to print from must have a spooling directory to hold the files to be printed. By default, the pathname for this directory is /usr/spool/output/lpd (you can change the pathname of the spooling directory in the /etc/printcap file). If this directory doesn't exist, you must create it on all nodes.

Note: The lpd daemon doesn't work without a spooling directory, and it doesn't tell you why. That's why it's a good idea to run the system logger (see syslogd in the Utilities Reference) when you're trying to debug printing problems; then you can check for error messages in /var/log/syslog.

Access control

The printer system maintains protected spooling areas so that users can't circumvent printer accounting or remove files other than their own:

Network manager

If you want to print on a remote printer, you need to run the Neutrino network manager, io-pkt*. This manager loads shared objects (DLLs) to provide the protocols and device drivers needed.

For example, to load the TCP/IP stack and a device driver suitable for Ethernet adapters compatible with NE-2000,, start io-pkt* like this:

io-pkt-v4 -dne2000

Note: If you're using a TCP/IP stack like this, you might want to configure your network interface to specify the type and number of your NIC, and the IP address and netmask for your TCP/IP interface. For more information, see TCP/IP Networking.

Printer capabilities: /etc/printcap

Before you can print anything, the nodes must know something about the specific printer being used (as a minimum, where the printer is located). A description of the printer is kept in a file named /etc/printcap on each node. The /etc/printcap database contains one or more entries per printer.

Note: This file isn't present when you first install Neutrino; you have to create one to suit your printing needs.

This section describes the basic fields; for information on the others, see /etc/printcap in the Utilities Reference.

A typical setup

Here's a basic /etc/printcap file that you can modify:

lpt1|tpptr|printer in Docs department:\

Each entry in the /etc/printcap file describes a printer. Comments start with number sign (#). An entry consists of a number of fields delimited by colons (:). In the example above, each field is on a separate line, but you can string the fields together on one line as long as they each start and end with a colon.

Here's what each line means:

lpt1|tpptr|printer in Docs department:\
The known names for the printer, separated by | (bar) characters. The last name is the only name that can include spaces; it's a long name that fully identifies the printer.

Entries may continue onto multiple lines by giving a \ (backslash) as the last character of a line. Empty fields may be included for readability.

The name of the device to open for output (the default is /dev/lp).
The spooling directory (the default is /usr/spool/output/lpd). Each printer should have a separate spooling directory; if it doesn't, jobs are printed on different printers, depending on which printer daemon starts first. By convention, the name of the spooling directory has the same name as its associated printer.

Note: Make sure you create the named spooling directory before you print.

A file to take printing error messages (by default, errors are sent to the console).

Note: Sometimes errors that are sent to standard error output don't appear in the log file. We highly recommend that you use the system-logger daemon, syslogd.

Remove the default limits on the size of the spooling buffer.
Suppress the printing of the burst header, a page that lists the user ID and job information about the print job.

Printers on serial lines

When you connect a printer via a serial line, you must set the proper baud rate and terminal modes. The following example is for a DecWriter III printer connected locally via a 1200 baud serial line.

lp|LA-180 DecWriter III:\
The name of the file to open for output.
The baud rate for the tty line.
Flags that set CRMOD, no parity, and XTABS.
Print a formfeed character when the queue empties. This is handy when the printer has continuous paper, because you can tear the paper off when the print job finishes instead of first having to take the printer offline and manually advance the paper.
Use a filter program called lpf for printing the files (see Filters,” below).
Write any error messages to the file /usr/adm/lpd-errs, instead of to the console.

Remote printers

Printers that reside on remote hosts should have an empty lp entry. For example, the following /etc/printcap entry directs output to the printer named lp on the machine named ucbvax:

lp|default line printer:\

The rm entry is the name of the remote machine to connect to; this name must be a known hostname for a machine on the network. The rp capability indicates that the name of the remote printer is lp (you can leave it out in this case, because this is the default value). The sd entry specifies /usr/spool/vaxlpd as the spooling directory instead of the default pathname, /usr/spool/output/lpd.


Filters are used to handle device dependencies and accounting functions:

Output filters
Used when accounting isn't needed or when all text data must be passed through a filter.

An output filter isn't suitable for accounting purposes because it's started only once, all text files are filtered through it, it doesn't pass owners' login names, and it doesn't identify the beginnings and ends of jobs.

Input filters
Started for each file printed and do accounting if there's an af field in the printer's printcap entry. If there are fields for both input and output filters, the output filter is used only to print the banner page; it's then stopped to allow input filters to access the printer.
Other filters
Used to convert files from one form to another. For example:

The tf entry specifies /usr/lib/rvcat as the filter to use when printing troff output. This filter is needed to set the device into print mode for text and into plot mode for printing troff files and raster images. Note that the page length is set to 58 lines by the pl entry for 8.5″ by 11″ fanfold paper.

To enable accounting, add an af filter to the varian entry, like this:


Note: Neutrino doesn't provide print filters; you have to either port them from another UNIX-type OS or write your own. If you don't want to do this, you can use the spooling system, which provides print drivers for specific families of currently popular printers. See spooler in the Utilities Reference and Printing with spooler,” below).

The lpd daemon spawns the filters; their standard input is the data to be printed; their standard output is the printer. Standard error is attached to the lf file for logging errors (or you can use syslogd). A filter must return an exit code of 0 if there were no errors, 1 if the job should be reprinted, or 2 if the job should be thrown away.

When lprrm sends a SIGINT signal to the lpd process that controls the printing, lpd sends a SIGINT signal to all filters and their descendants. Filters that need to do cleanup operations, such as deleting temporary files, can trap this signal.

The arguments lpd passes to a filter depend on the filter type:

Some /etc/printcap examples

This section gives you some examples to show you how to set up your printer descriptions; see also /etc/printcap in the Utilities Reference.

USB printer

If you've attached a USB printer to your machine and started the USB stack and devu-prn as described in USB devices in the Connecting Hardware chapter, you should set up the /etc/printcap file to be something like this:

hpps: \

This file gives the name hpps to the USB printer, identifies the file to open as /dev/usbpar0 (or whatever device devu-prn created), and identifies the spooling directory as /usr/spool/output/hpps.

To access this printer, specify lpr -Phpps or set the PRINTER environment variable to hpps.

Note: Make sure that the spooling directory exists.

Single printer

Let's assume we have two nodes, node1 and node2, and node1 has a printer connected to /dev/par1:

Single printer

The /etc/printcap file on node1 might be as follows:


This file simply gives the name lpt1 to the printer connected to /dev/par1. It doesn't need to describe any other capabilities, because the default settings suffice. To access this printer from node1, specify lpr -Plpt1 or set the PRINTER environment variable to lpt1.

Note: Make sure the spooling directory exists, and that there's an entry for node2 in the /etc/hosts.lpd file on node1.

The /etc/printcap file on node2 might be as follows:


This file specifies the remote host with the printer named lpt1 to be node1. The local printer name, rlpt1, is used by local clients and could be the same as the remote name, lpt1.

Make sure there's an entry for node1 in /etc/hosts.

Multiple printers

Now, let's add another printer to node1, this time connected to /dev/par2:

Multiple printers

You should define multiple printers carefully because the default capabilities aren't suitable for all printers. For example, use the sd field to specify a unique spool directory for each printer.

The /etc/printcap file on node1 now looks like this:



This specifies the following these printers:

Make sure there's an entry for node2 in the /etc/hosts.lpd file on node1.

To refer to these two printers remotely from node2, create a /etc/printcap file on node2 that looks like this:



This specifies the two printers we just located on node1 with the names to be used on node2. Make sure there's an entry for node1 in /etc/hosts.

Local and remote printers

What if we now want to move one of the two printers (say lpt2) from node1 to node2?

Local and remote printers

We have to change the /etc/printcap file on both nodes. Likewise, we need to change /etc/printcap on any other network nodes we wished to print from:

Make sure you have entries for node1 and node2 in the /etc/hosts file on each node. You also need entries in the /etc/hosts.lpd file on node1 and node2 for each node that you want to be able to use the printers.

If you've set up your remote printing network according to the examples given, you should be able to send a file in /tmp/test on node2 to the printer attached to node1 using a command like this:

lpr -h -Plpt1 /tmp/test

Here's what happens:

  1. You enter the lpr command to print a file remotely.
  2. The lpr utility requests printing service.
  3. The lpd daemon on node2 hears the request, spawns a copy of itself to service the request, and then creates a spooling subdirectory to hold the files to be printed.
  4. The spawned lpd daemon places the print job in the spooler as two files: a data file containing the file to be printed and a header file containing information about the print job (to be printed as an optional front sheet).
  5. The spawned lpd daemon processes the spooled print jobs in the order they were received; it starts sending data packets containing the print job to the remote lpd daemon.
  6. The lpd daemon on node1 receives the packets as a printing request, and after checking that the request is from an approved node, spawns a copy of itself to service the request and also creates a spooling subdirectory to hold the files to be printed. (If the request isn't from an approved source, a refusal message is sent back to the source address.)
  7. The spawned lpd collects the data packets, places the print job into the spooler queue, and then sends the print jobs, in the order they were received, to the printer you specified.

Remote printing to a printer on another network

Using TCP/IP and lpr, you can print a file on a remote printer connected to a server on another network. You just have to set up your Neutrino network node for remote printing and the remote server for TCP/IP and handling printers compatible with lpr.

For instance, let's suppose you want to print /root/, a PostScript file on a node on your Neutrino network, but the only Postscript printer available (windows_printer) is connected to a Windows server with an IP address of

First, make sure that the Windows server is configured for TCP/IP printing and that the printer is compatible with lpr. Then, as root, on your Neutrino node:

  1. Add a printer description in /etc/printcap, like this:
  2. Add a new line in /etc/hosts, like this:      windows_server
  3. Create the spool directory:
    mkdir /usr/spool/output/lpd/rlpt4
  4. Start lpd.

To print a PostScript file on the printer, type:

lpr -Prlpt4

Remote printing to a TCP/IP-enabled printer using lpr

A TCP/IP-enabled printer doesn't need an attached computer to provide print services; the printer itself provides the services. So, you use the same basic steps described above, with the following minor alterations:

This example shows that the name of the remote machine (in this case, the actual printer) is tcpip_printer and the spool directory is /usr/spool/output/lpd/rlpt2. Note that the remote printer is specified as /ps, which is the name some network printers use for accepting PostScript files. You need to find out the name your printer wants you to use; it may require different names for different types of print file format (e.g. PostScript and text files).

Make sure you've created your spool directory — that's about it. Follow the usual steps described in Local and remote printers,” and you should be able to print to your remote printer using a command line like this:

lpr -Prlpt2 /root/

This sends a PostScript file named /root/ to the remote printer named tcpip_printer located at the IP address,

Note: To keep it simple, we've taken the easy way out in this example by sending a PostScript file to a PostScript printer. It's easy because the formatting is embedded in the PostScript text. You might have to filter the print file to get your printer to work using lpr; you can specify the filter to use in the /etc/printcap entry for the printer (for more information on this, see Filters).

Printing with spooler

Neutrino provides the spooler utility as an alternative printing mechanism to the standard, UNIX-like lp* family. Photon applications use spooler for printing, and use a filter to convert Photon draw-stream (phs) output into the form that the printer understands.

Setting up spooler

The spooler utility is usually started by an enumerator when you start Neutrino (see Controlling How Neutrino Starts). The utility manages one printer, but you can run more than one instance of spooler.

When you start spooler (or the system starts it):

The /etc/printers directory includes general configuration files for the most popular types of printers currently in use, including:

Printer(s) Configuration file Photon filter
Canon bjc.cfg phs-to-bjc
Epson epson.cfg phs-to-escp2
Epson IJS epijs.cfg phs-to-ijs
Hewlett-Packard pcl.cfg phs-to-pcl
PostScript ps.cfg phs-to-ps

There's also a special filter, phs-to-bmp, that converts a Photon draw-stream file into a BMP. The configuration files specify the possible and default settings for the printer, as well as which filter is appropriate for it.

When you print from a Photon application, the application sends the file to be printed to the /dev/printers/printer_name/spool directory. The Photon application may construct another configuration file for the printer that you selected, depending on optional information that you provide.

If you have a file that's already in a form that the printer understands or for which there's a filter, you can print it by copying it into the raw spooling directory:

cp my_file /dev/printers/printer_name/raw

When the spooler sees the print job in /dev/printers/printer_name/raw, it copies the job file to the spooling directory, /var/spool/printers/ and invokes the appropriate filter, which prepares the file and then sends it to the printer.


Printing with spooler.

Normally, spooler stores a file to be printed in a directory on disk, then tells the filter where to get the file. If you need to cut down on disk memory, you can use the -F option of spooler to disable the spooling of print files. This option causes the spooler to send sections of a file to be printed directly to a FIFO buffer in piecemeal fashion; the filter receives data to be printed from the FIFO and prints that part of the file. When the buffer has been emptied, spooler loads the next section of the file into the buffer, and so on until the whole file has been printed.

If you ask a Photon application for a print preview, it sends the output to the preview utility. If you want to view or manage the print queue, start prjobs from the command line, or select Utilities-->Print Manager from the Launch menu. For more information, see the Utilities Reference.

Printing on a USB printer

If you've attached a USB printer to your machine and started the USB stack and devu-prn as described in USB devices in the Connecting Hardware chapter, you need to start an instance of spooler to manage it (for example in /etc/rc.d/rc.local).

Note: QNX Neutrino doesn't currently enumerate USB printers.

To set up your USB printer, do the following:

  1. Create /usr/spool/output/device, where device is the device that devu-prn created for the printer (e.g. usbpar0).
  2. Start spooler, specifying the printer's device. For example:
    spooler -d /dev/usbpar0

    Your printer should now appear in /dev/printers.

Remote printing over Qnet

To print across Qnet, print to /net/nodename/dev/printers/printer_name/spool. The spooler program for the printer must be running on nodename.

Remote printing over TCP/IP

If you want to set up spooler to print on a remote printer, you can pipe the print job to lpr. This takes advantage of the fact that the filter sends the print job to the printer; you just name the remote printer in the filter command line of the configuration file used by spooler.

To try it, first get your remote printer working using lpr (see Remote printing to a TCP/IP-enabled printer using lpr), then do the following:

  1. Copy the configuration file from the printer you want to use (in this case, a PostScript printer):
    cp /etc/printers/ps.cfg /etc/printers/test.cfg
  2. Find the filter command lines in test.cfg; they look like this:
    Filter   =   phs:$d:phs-to-ps
    Filter   =   raw:$d:cat

    These filter command lines are in the form:


    The phs filter command line tells the filter to process .phs files by sending them through a filter called phs-to-ps before sending them on to the destination passed by spooler. The raw filter command is for utilities that already produce the correct output for the printer.

  3. Change the phs filter command line from this:
    Filter  =   phs:$d:phs-to-ps

    to this:

    Filter  =   phs:ps:phs-to-ps
  4. Add a line to tell the filter to send all PostScript files to the remote printer, rlpt2:
    Filter    ps:$d:lpr -Prlpt2

    What you've done is change the destination from that given by spooler to ps, so that after the .phs file has been converted to a ps type by phs-to-ps, it goes to the ps filter. Then the ps filter line you added sends PostScript files to lpr, forcing output to the remote printer (just as you did in Remote printing to a TCP/IP-enabled printer using lpr).

    You might be wondering what happened to the destination passed by spooler ($d). Well, that is discarded because lpr (unlike phs-to-ps) doesn't return the job to the filter but completes it itself.

  5. Finally, start a new instance of spooler, telling it the pathname of your new configuration file (in this case /etc/printers/test.cfg) and the name of the printer you want to use (in this case rlpt2), like this:
    spooler -d /dev/null -c /etc/printers/test.cfg -n rlpt2 &

    The -n option specifies the name of the printer, which appears in a Photon application's Print dialog.

  6. If you want to start spooler like this whenever you boot your machine, add the above command to your /etc/rc.d/rc.local file. For more information, see Controlling How Neutrino Starts.

Now, you should be able to print your PostScript file on your remote TCP/IP-enabled printer, either from Photon or from the command line.

Note: For configuration files for printing with lpr, SAMBA, and NCFTP, see the Examples appendix.


Understanding lpr error messages

The following error messages from the lp* print utilities may help you troubleshoot your printing problems:

lpr error messages

lpr: filename: copyfile is too large
The submitted file was larger than the printer's maximum file size, as defined by the mx capability in its printcap entry.
lpr: printer: unknown printer
The printer wasn't found in the /etc/printcap database, perhaps because an entry is missing or incorrect.
lpr: printer: jobs queued, but cannot start daemon
The connection to lpd on the local machine failed, probably because the printer server has died or isn't responding. The superuser can restart lpd by typing:

You can also check the state of the master printer daemon:

sin -P lpd

Another possibility is that the user ID for lpr isn't root and its group ID isn't daemon. You can check by typing:

ls -lg /usr/bin/lpr
lpr: printer: printer queue is disabled
This means the queue was turned off with the lprc disable command (see lprc — printer-control program) to prevent lpr from putting files in the queue. This is usually done when a printer is going to be down for a long time. The superuser can turn the printer back on using lprc.

lprq error messages

waiting for printer to become ready (offline ?)
The daemon couldn't open the printer device. This can happen for several reasons (e.g. the printer is offline or out of paper, or the paper is jammed). The actual reason depends on the meaning of error codes returned by the system device driver; some printers can't supply enough information to distinguish when a printer is offline or having trouble, especially if connected through a serial line.

Another possible cause of this message is that some other process, such as an output filter, has an exclusive open on the device: all you can do in this case is kill off the offending program(s) and restart the printer with lprc.

printer is ready and printing
The lprq program checks to see if a daemon process exists for the printer and prints the file status located in the spooling directory. If the daemon isn't responding, the root user can use lprc to abort the current daemon and start a new one.
waiting for host to come up
This implies that there's a daemon trying to connect to the remote machine named host to send the files in the local queue. If the remote machine is up, lpd on the remote machine is probably dead or hung and should be restarted.
sending to host
The files should be in the process of being transferred to the remote host. If not, root should use lprc to abort and restart the local daemon.
Warning: printer is down
The printer has been marked as being unavailable with lprc.
Warning: no daemon present
The lpd process overseeing the spooling queue, as specified in the lock file in that directory, doesn't exist. This normally occurs only when the daemon has unexpectedly died. Check the error log file for the printer and the syslogd log to diagnose the problem. To restart an lpd, type:
lprc restart printer
no space on remote; waiting for queue to drain
This implies that there isn't enough disk space on the remote machine. If the file is large enough, there will never be enough space on the remote (even after the queue on the remote is empty). The solution here is to move the spooling queue or make more free space on the remote machine.

lprrm error messages

lprrm: printer: cannot restart printer daemon
This case is the same as when lpr prints that the daemon can't be started.

lprc error messages

couldn't start printer
This case is the same as when lpr reports that the daemon can't be started.
cannot examine spool directory
Error messages beginning with cannot are usually because of incorrect ownership or protection mode of the lock file, spooling directory, or lprc program.

lpd error messages

The lpd utility can log many different messages using syslogd. Most of these messages are about files that can't be opened and usually imply that the /etc/printcap file or the protection modes of the files are incorrect. Files may also be inaccessible if people bypass the lpr program.

In addition to messages generated by lpd, any of the filters that lpd spawns may log messages to the syslog file or to the error log file (the file specified in the lf entry in /etc/printcap). If you want to debug problems, run syslogd.

Troubleshooting remote printing problems

If the file you send doesn't print, you may get an error message from one of the lp* print utilities; see Understanding lpr error messages.” If you don't get an error message, check the following: