This chapter includes:
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:
You can use either, or both, depending on how you've set up your machine and network:
In this case, the device enumeration that the system does when it boots automatically starts spooler (see "Device enumeration" in Controlling How Neutrino Starts). We supply configuration files, in /etc/printers, for the most commonly used printers.
If you want to use the lpr family, you have to set up the printer-configuration file, /etc/printcap.
In order to print remotely, you have to set up some configuration files whether you use the lpr family or spooler.
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.
The lpr line-printer system supports:
To print a file using the line-printer system, you need:
|You need to log in as root to set up the lpr system.|
The line-printer system consists mainly of the following files and commands:
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.
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.
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:
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.
|You can remove only your own print jobs from the queue.|
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).
The abort command doesn't remove any jobs from the spool queue; for this, use lprrm.
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.
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.
|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.|
The printer system maintains protected spooling areas so that users can't circumvent printer accounting or remove files other than their own:
Users must be in the group lprgroup to submit jobs to the specified printer. The default is to allow all users access. Note that once the files are in the local queue, they can be printed locally or forwarded to another host, depending on the configuration.
The host on which a client resides must be present in /etc/hosts.equiv or /etc/hosts.lpd, and the request message must come from a reserved port number.
|Other utilities, such as rlogin, also use /etc/hosts.equiv to determine which hosts are equivalent. The /etc/hosts.lpd file is used only to control which hosts have access to the printers.|
To allow access only to those remote users with accounts on the local host, use the rs field in the printer's entry in /etc/printcap:
If you want to print on a remote printer, you need to run the Neutrino network manager, io-net. This manager loads shared objects (DLLs) to provide the protocols and device drivers needed.
For example, to load the full TCP/IP stack npm-tcpip.so and a device driver suitable for Ethernet adapters compatible with NE-2000, devn-ne2000.so, start io-net like this:
io-net -dne2000 -ptcpip
|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.|
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.
|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.
Here's a basic /etc/printcap file that you can modify:
lpt1|tpptr|printer in Docs department:\ :lp=/dev/par1:\ :sd=/usr/spool/output/lpt1:\ :lf=/usr/adm/lpd-errs:\ :mx#0:\ :sh:
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:
Entries may continue onto multiple lines by giving a \ (backslash) as the last character of a line. Empty fields may be included for readability.
|Make sure you create the named spooling directory before you print.|
|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.|
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:\ :lp=/dev/lp:br#1200:fs#06320:\ :tr=\f:of=/usr/lib/lpf:lf=/usr/adm/lpd-errs:
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:\ :lp=:rm=ucbvax:rp=lp:sd=/usr/spool/vaxlpd:
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:
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.
va|varian|Benson-Varian:\ :lp=/dev/va0:sd=/usr/spool/vad:of=/usr/lib/vpf:\ :tf=/usr/lib/rvcat:mx#2000:pl#58:px=2112:py=1700:tr=\f:
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:
va|varian|Benson-Varian:\ :lp=/dev/va0:sd=/usr/spool/vad:of=/usr/lib/vpf:\ :if=/usr/lib/vpf:tf=/usr/lib/rvcat:af=/usr/adm/vaacct:\ :mx#2000:pl#58:px=2112:py=1700:tr=\f:
|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:
filter -wwidth -llength
The width and length values come from the pw and pl entries in the /etc/printcap database.
filter [-c] -wwidth -llength -iindent -nlogin -hhost acct_file
The optional -c flag is used only when control characters are to be passed uninterpreted to the printer (when using the -l option of lpr to print the file). The -w and -l parameters are the same as for of filters. The -n and -h parameters specify the login name and hostname of the job owner. The last argument is the name of the accounting file from /etc/printcap.
filter -xwidth -ylength -nlogin -hhost acct_file
The -x and -y options specify the horizontal and vertical page size in pixels (from the px and py entries in the /etc/printcap file). The rest of the arguments are the same as for if filters.
This section gives you some examples to show you how to set up your printer descriptions; see also /etc/printcap in the Utilities Reference.
Let's assume we have two nodes, node1 and node2, and node1 has a printer connected to /dev/par1:
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.
|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.
Now, let's add another printer to node1, this time connected to /dev/par2:
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:
lpt1:\ :lp=/dev/par1:sd=/usr/spool/output/lpt1: lpt2:\ :lp=/dev/par2:sd=/usr/spool/output/lpt2:
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:
lpt1:\ :rm=node1:rp=lpt1:sd=/usr/spool/output/lpt1:lp=: lpt2:\ :rm=node1:rp=lpt2:sd=/usr/spool/output/lpt2:lp=:
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.
What if we now want to move one of the two printers (say lpt2) from node1 to node2?
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:
lpt1:\ :lp=/dev/par1:sd=/usr/spool/output/lpt1: lpt2:\ :rm=node2:rp=lpt2:sd=/usr/spool/output/lpt2:
lpt1:\ :rm=node1:rp=lpt1:sd=/usr/spool/output/lpt1: lpt2:\ :lp=/dev/par1:sd=/usr/spool/output/lpt2:
lpt1:\ :rm=node1:rp=lpt1:sd=/usr/spool/output/lpt1: lpt2:\ :rm=node2:rp=lpt2:sd=/usr/spool/output/lpt2:
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:
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/junk.ps, 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 10.2.1.8.
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:
rlpt4:\ :rm=windows_server:lp=:rp=windows_printer:\ :sd=/usr/spool/output/lpd/rlpt4:
To print a PostScript file on the printer, type:
lpr -Prlpt4 junk.ps
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/junk.ps
This sends a PostScript file named /root/junk.ps to the remote printer named tcpip_printer located at the IP address, 10.2.0.4.
|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").|
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.
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|
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/printer_name.host and invokes the appropriate filter, which prepares the file and then sends it to the printer.
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 selectfrom the Launch menu. For more information, see the Utilities Reference.
To print across Qnet, print to /net/nodename/dev/printers/printer_name/spool. The spooler program for the printer must be running on nodename.
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:
cp /etc/printers/ps.cfg /etc/printers/test.cfg
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.
Filter = phs:$d:phs-to-ps
Filter = phs:ps:phs-to-ps
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.
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.
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.
Select the correct printer (in this example, rlpt2) in the Select Printer dialog box.
Copy the print file to the directory that spooler uses:
cp /root/my_file.ps /dev/printers/rlpt2/spool/
|For configuration files for printing with lpr, SAMBA, and NCFTP, see the Examples appendix.|
The following error messages from the lp* print utilities may help you troubleshoot your printing problems:
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
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.
lprc restart printer
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.
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: