Contributed by &a.kelly; LPD controls everything about a host's printers. It's
responsible for a number of things:
If you're the sole user of your system, you may be
wondering why you should bother with the spooler when you
don't need access control, header pages, or printer
accounting. While it's possible to enable direct access to
a printer, you should use the spooler anyway since
To use printers with the LPD spooling system, you'll need
to set up both your printer hardware and the LPD software.
This document describes two levels of setup:
This section tells how to configure printer hardware and the
LPD software to use the printer. It teaches the basics:
This section tells about the various ways you can connect a
printer to your PC. It talks about the kinds of ports and
cables, and also the kernel configuration you may need to
enable FreeBSD to speak to the printer.
If you've already connected your printer and have
successfully printed with it under another operating system,
you can probably skip to section .
Nearly all printers you can get for a PC today support
one or both of the following interfaces:
To hook up a printer using a parallel interface, connect
the Centronics cable between the printer and the
computer. The instructions that came with the printer, the
computer, or both should give you complete guidance.
Remember which parallel port you used on the computer. The
first parallel port is /dev/lpt0 to FreeBSD; the second is
/dev/lpt1, and so on.
To hook up a printer using a serial interface, connect
the proper serial cable between the printer and the
computer. The instructions that came with the printer,
the computer, or both should give you complete guidance.
If you're unsure what the ``proper serial cable'' is, you
may wish to try one of the following alternatives:
This section describes the software setup necessary to
print with the LPD spooling system in FreeBSD.
Here's an outline of the steps involved:
The operating system kernel is compiled to work with a
specific set of devices. The serial or parallel interface
for your printer is a part of that set. Therefore, it
might be necessary to add support for an additional serial
or parallel port if your kernel isn't already configured
for one.
To find out if the kernel you're currently using supports a serial
interface, type
Even though the kernel may support communication along
a serial or parallel port, you'll still need a software
interface through which programs running on the system
can send and receive data. That's what entries in the
/dev directory are for.
When you're using the parallel interface, you can
choose whether FreeBSD should use interrupt-driven or
polled communication with the printer.
Before proceeding to configure the spooling system,
you should make sure the operating system can
successfully send data to your printer. It's a lot
easier to debug printer communication and the spooling
system separately.
To test the printer, we'll send some text to it. For
printers that can immediately print characters sent to
them, the program
%!PS
100 100 moveto 300 300 lineto stroke
310 310 moveto
/Helvetica findfont 12 scalefont setfont
(Is this thing working?) show
showpage
This section tells you how to check if FreeBSD can
communicate with a printer connected to a parallel port.
This section tells you how to check if FreeBSD can
communicate with a printer on a serial port.
At this point, your printer should be hooked up, your
kernel configured to communicate with it (if necessary),
and you've been able to send some simple data to the
printer. Now, we're ready to configure LPD to control
access to your printer.
You configure LPD by editing the file
/etc/printcap. The LPD spooling system reads
this file each time the spooler is used, so updates to the
file take immediate effect.
The format of the /etc/printcap. The format is identical to other
capability files like /usr/share/misc/termcap and
/etc/remote. For complete information about the
format, see the cgetent(3).
The simple spooler configuration consists of the following steps:
The first (easy) step is to pick a name for your
printer. It really doesn't matter whether you choose
functional or whimsical names since you can also provide
a number aliases for the printer.
At least one of the printers specified in the
/etc/printcap should have the alias
/etc/printcap file. The name of
the printer should start in the leftmost column.
Separate each alias with a vertical bar and put a colon
after the last alias.
In the following example, we start with a skeletal
/etc/printcap that defines two printers (a
Diablo 630 line printer and a Panasonic KX-P4455
PostScript laser printer):
The LPD spooling system will by default print a
/etc/printcap The next step in the simple spooler setup is to make a
/var/spool In section , we identified which
entry in the /dev directory FreeBSD will use
to communicate with the printer. Now, we tell LPD
that information. When the spooling system has a job
to print, it will open the specified device on behalf
of the filter program (which is responsible for
passing data to the printer).
List the /dev entry pathname in the
/etc/printcap file using the /etc/printcap:
For printers on serial ports, LPD can set up the bps
rate, parity, and other serial communication parameters
on behalf of the filter program that sends data to the
printer. This is advantageous since
We're now ready to tell LPD what text filter to use to
send jobs to the printer. A .
For our simple printer setup, the text filter can be a
small shell script that just executes /bin/cat
to send the job to the printer. FreeBSD comes with
another filter called .
First, let's make the shell script
/usr/local/libexec/if-simple be a simple text
filter. Put the following text into that file with your
favorite text editor:
You've reached the end of the simple LPD setup.
Unfortunately, congratulations are not quite yet in
order, since we've still got to test the setup and
correct any problems. To test the setup, try printing
something. To print with the LPD system, you use the
command to generate some
test text.
Type:
After performing the simple test with
Have FreeBSD's serial line driver
automatically convert LF to CR+LF. Of course,
this works with printers on serial ports
/etc/printcap This section tells you how to use printers you've setup with
FreeBSD. Here's an overview of the user-level commands:
To print files, type
When you print with If you change your mind about printing a job, you can
remove the job from the queue with the
To remove the job from a specific printer, add the The The following The following options to
This example prints three copies of These options to for information about
setting up header pages.
As an administrator for your printers, you've had to
install, set up, and test them. Using the
This section describes filters for printing specially
formatted files, header pages, printing across networks, and
restricting and accounting for printer usage.
Although LPD handles network protocols, queuing, access
control, and other aspects of printing, most of the
).
However, in order to take advantage of format conversion,
printer accounting, specific printer quirks, and so on, you
should understand how filters work. It will ultimately be
the filter's responsibility to handle these aspects. And the
bad news is that most of the time /usr/libexec/lpr/lpf,
that works with many printers that can print plain text.
(It handles backspacing and tabs in the file, and does
accounting, but that's about all it does.) There are also
several filters and filter components in the FreeBSD ports
collection.
Here's what you'll find in this section:
As mentioned before, a filter is an executable program
started by LPD to handle the device-dependent part of
communicating with the printer.
When LPD wants to print a file in a job, it starts a
filter program. It sets the filter's standard input to
the file to print, its standard output to the printer, and
its standard error to the error logging file (specified in
the /etc/printcap, or
/dev/console by default).
Which filter LPD starts and the filter's arguments depend
on what's listed in the /etc/printcap file and
what arguments the user specified for the job on the
for
details).
There are three kinds filters you can specify in
/etc/printcap:
If you're the only user of your computer and PostScript
(or other language-based) printer, and you promise to
never send plain text to your printer and to never use
features of various programs that will want to send plain
text to your printer, then you don't need to worry about
this section at all.
But, if you would like to send both PostScript and plain
text jobs to the printer, then you're urged to augment
your printer setup. To do so, we have the text filter
detect if the arriving job is plain text or PostScript.
All PostScript jobs must start with ); if not,
it should be shortly. You can fetch, build and install it
yourself, of course. After installing /etc/printcap:
PostScript is the After completing the simple setup described in , the
first thing you'll probably want to do is install
conversion filters for your favorite file formats
(besides plain ASCII text).
Conversion filters make printing various kinds of
files easy. As an example, suppose we do a lot of work
with the TeX typesetting system, and we have a
PostScript printer. Every time we generate a DVI file
from TeX, we can't print it directly until we convert
the DVI file into PostScript. The command sequence
goes like this:
You should install the conversion filters you expect
to use. If you print a lot of DVI data, then a DVI
conversion filter is in order. If you've got plenty of
troff to print out, then you probably want a troff
filter.
The following table summarizes the filters that LPD
works with, their capability entries for the
/etc/printcap file, and how to invoke them with
the
/etc/printcap
File type Capability lpr option
------------ ------------- ----------
cifplot cf -c
DVI df -d
plot gf -g
ditroff nf -n
FORTRAN text rf -f
troff tf -t
raster vf -v
plain text if none, -p, or -l
In our example, using /etc/printcap.
Despite what others might contend, formats like FORTRAN
text and plot are probably obsolete. At your site, you
can give new meanings to these or any of the formatting
options just by installing custom filters. For example,
suppose you'd like to directly print Printerleaf files
(files from the Interleaf desktop publishing program),
but will never print plot files. You could install a
Printerleaf conversion filter under the Since conversion filters are programs you install
outside of the base FreeBSD installation, they should
probably go under /usr/local. The directory
/usr/local/libexec is a popular location, since
they they're specialized programs that only LPD will
run; regular users shouldn't ever need to run them.
To enable a conversion filter, specify its pathname
under the appropriate capability for the destination
printer in /etc/printcap.
In our example, we'll add the DVI conversion filter to
the entry for the printer named /etc/printcap file again, with the new
#
# /etc/printcap for host rose - added df filter for bamboo
#
rattan|line|diablo|lp|Diablo 630 Line Printer:\
:sh:sd=/var/spool/lpd/rattan:\
:lp=/dev/lpt0:\
:if=/usr/local/libexec/if-simple:
bamboo|ps|PS|S|panasonic|Panasonic KX-P4455 PostScript v51.4:\
:sh:sd=/var/spool/lpd/bamboo:\
:lp=/dev/ttyd5:fs#0x82000e1:xs#0x820:rw:\
:if=/usr/local/libexec/psif:\
:df=/usr/local/libexec/psdf:
The DVI filter is a shell script named
/usr/local/libexec/psdf. Here's that script:
Since there's no fixed set of steps to install
conversion filters, let me instead provide more
examples. Use these as guidance to making your own
filters. Use them directly, if appropriate.
This example script is a raster (well, GIF file,
actually) conversion filter for a Hewlett Packard
LaserJet III-Si printer:
All these conversion filters accomplish a lot for your
printing environment, but at the cost forcing the user
to specify (on the The LPD spooling system supports one other type of
filter that we've not yet explored: an output filter. An
output filter is intended for printing plain text only,
like the text filter, but with many simplifications. If
you're using an output filter but no text filter, then
The program /usr/libexec/lpr/lpf that comes
with FreeBSD binary distribution is a text filter (input
filter) that can indent output (job submitted with /etc/printcap file. It uses
these values to determine how much text can fit on a page
and how many pages were in a user's job. For more
information on printer accounting, see .
If you've got .
In the , we turned off header pages by specifying
/etc/printcap file. To enable header pages for
a printer, just remove the
#!/bin/sh
#
# hpof - Output filter for Hewlett Packard PCL-compatible printers
# Installed in /usr/local/libexec/hpof
printf "\033&ero;k2G" || exit 2
exec /usr/libexec/lpr/lpf
Specify the path to the output filter in the for more information.
Here's an example /etc/printcap file for the printer
#
# /etc/printcap for host orchid
#
teak|hp|laserjet|Hewlett Packard LaserJet 3Si:\
:lp=/dev/lpt0:sd=/var/spool/lpd/teak:mx#0:\
:if=/usr/local/libexec/hpif:\
:vf=/usr/local/libexec/hpvf:\
:of=/usr/local/libexec/hpof:
Now, when users print jobs to
for more /etc/printcap.
By enabling header pages, LPD will produce a Using LPD's built-in header pages enforces a particular
paradigm when it comes to printer accounting: header pages
must be
As described above, LPD can generate a plain text header
page suitable for many printers. Of course, PostScript
can't directly print plain text, so the header page
feature of LPD is useless---or mostly so.
One obvious way to get header pages is to have every
conversion filter and the text filter generate the header
page. The filters should should use the user and host
arguments to generate a suitable header page. The
drawback of this method is that users will always get a
header page, even if they submit jobs with
#!/bin/sh
#
# make-ps-header - make a PostScript header page on stdout
# Installed in /usr/local/libexec/make-ps-header
#
#
# These are PostScript units (72 to the inch). Modify for A4 or
# whatever size paper you're using:
#
page_width=612
page_height=792
border=72
#
# Check arguments
#
if [ $# -ne 3 ]; then
echo "Usage: `basename $0` FreeBSD supports networked printing: sending jobs to
remote printers. Networked printing generally refers to two
different things:
The LPD spooling system has built-in support for sending
jobs to other hosts also running LPD (or are compatible
with LPD). This feature enables you to install a printer
on one host and make it accessible from other hosts. It
also works with printers that have network interfaces that
understand the LPD protocol.
To enable this kind of remote printing, first install a
printer on one host, the . Do any
advanced setup in that you need. Make sure
to test the printer and see if it works with the features
of LPD you've enabled.
If you're using a printer with a network interface that's
compatible with LPD, then the /etc/printcap Often, when you buy a network interface card for a
printer, you can get two versions: one which emulates a
spooler (the more expensive version), or one which just
lets you send data to it as if you were using a serial or
parallel port (the cheaper version). This section tells
how to use the cheaper version. For the more expensive
one, see the previous section .
The format of the /etc/printcap file lets you
specify what serial or parallel interface to use, and (if
you're using a serial interface), what baud rate, whether
to use flow control, delays for tabs, conversion of
newlines, and more. But there's no way to specify a
connection to a printer that's listening on a TCP/IP or
other network port.
To send data to a networked printer, you need to develop a
communications program that can be called by the text and
conversion filters. Here's one such example: the script
#!/usr/bin/perl
#
# netprint - Text filter for printer attached to network
# Installed in /usr/local/libexec/netprint
#
$#ARGV eq 1 || die "Usage: $0 This section gives information on restricting printer
usage. The LPD system lets you control who can access a
printer, both locally or remotely, whether they can print
multiple copies, how large their jobs can be, and how large
the printer queues can get.
The LPD system makes it easy for users to print multiple
copies of a file. Users can print jobs with /etc/printcap file. When users submit jobs
with the You can control who can print to what printers by using
the UNIX group mechanism and the /etc/printcap. Just place the users you want to
have access to a printer in a certain group, and then name
that group in the If you have many users accessing the printers, you
probably need to put an upper limit on the sizes of the
files users can submit to print. After all, there's only
so much free space on the filesystem that houses the
spooling directories, and you also need to make sure
there's room for the jobs of other users.
LPD enables you to limit the maximum byte size a file in a
job can be with the
#
# /etc/printcap for host rose
#
#
# No limit on job size:
#
rattan|line|diablo|lp|Diablo 630 Line Printer:\
:sh:sd=/var/spool/lpd/rattan:\
:lp=/dev/lpt0:\
:if=/usr/local/libexec/if-simple:
#
# Limit of five megabytes:
#
bamboo|ps|PS|S|panasonic|Panasonic KX-P4455 PostScript v51.4:\
:sh:sd=/var/spool/lpd/bamboo:sc:rg=artists:mx#5000:\
:lp=/dev/ttyd5:fs#0x82000e1:xs#0x820:rw:\
:if=/usr/local/libexec/psif:\
:df=/usr/local/libexec/psdf:
Again, the limits apply to the local users only. If
you've set up access to your printers remotely, remote
users won't get those limits. You'll need to specify the
/etc/printcap
files as well. See section for
more information on remote printing.
There's another specialized way to limit job sizes from
remote printers; see section .
The LPD spooling system provides several ways to restrict
print jobs submitted from remote hosts:
So, you need to charge for printouts. And why not? Paper
and ink cost money. And then there are maintenance
costs---printers are loaded with moving parts and tend to
break down. You've examined your printers, usage patterns,
and maintenance fees and have come up with a per-page (or
per-foot, per-meter, or per-whatever) cost. Now, how do you
actually start accounting for printouts?
Well, the bad news is the LPD spooling system doesn't
provide much help in this department. Accounting is highly
dependent on the kind of printer in use, the formats being
printed, and .
Generally, there are two ways to do accounting:
FreeBSD comes with two programs that can get you set up
with simple periodic accounting right away. They are the
text filter , and
), LPD
starts the text and the conversion filters with the name
of the accounting file to use on the filter command
line. The filters can use this argument to know where
to write an accounting file entry. The name of this
file comes from the /etc/printcap, and if not specified as an
absolute path, is relative to the spooling directory.
LPD starts In order to perform even remotely accurate accounting,
you need to be able to determine how much paper a job
uses. This is the essential problem of printer
accounting.
For plain text jobs, the problem's not that hard to solve:
you count how many lines are in a job and compare it to
how many lines per page your printer supports. Don't
forget to take into account backspaces in the file which
overprint lines, or long logical lines that wrap onto one
or more additional physical lines.
The text filter )
takes into account these things when it does accounting.
If you're writing a text filter which needs to do
accounting, you might want to examine If you've been reading straight through this manual, by now
you've learned just about everything there is to know about
the LPD spooling system that comes with FreeBSD. You can
probably appreciate many of its shortcomings, which naturally
leads to the question: ``What other spooling systems are out
there (and work with FreeBSD)?''
Unfortunately, I've located only
I'd like to thank the following people who've assisted in
the development of this document:
printer:dv=/dev/ttyd2:br#19200:pa=none
#
# /etc/printcap for host rose
#
rattan|line|diablo|lp|Diablo 630 Line Printer:
bamboo|ps|PS|S|panasonic|Panasonic KX-P4455 PostScript v51.4:
In this example, the first printer is named
#
# /etc/printcap for host rose - identified what devices to use
#
rattan|line|diablo|lp|Diablo 630 Line Printer:\
:sh:sd=/var/spool/lpd/rattan:\
:lp=/dev/lpt0:
bamboo|ps|PS|S|panasonic|Panasonic KX-P4455 PostScript v51.4:\
:sh:sd=/var/spool/lpd/bamboo:\
:lp=/dev/ttyd5:
If you don't specify the /etc/printcap file, LPD uses
/dev/lp as a default. /dev/lp
currently doesn't exist in FreeBSD.
If the printer you're installing is connected to a
parallel port, skip to the section . Otherwise,
be sure to follow the instructions in the next section.
#!/bin/sh
#
# if-simple - Simple text input filter for lpd
# Installed in /usr/local/libexec/if-simple
#
# Simply copies stdin to stdout. Ignores all filter arguments.
/bin/cat &ero;&ero; exit 0
exit 2
Make the file executable:
#
# /etc/printcap for host rose - added text filter
#
rattan|line|diablo|lp|Diablo 630 Line Printer:\
:sh:sd=/var/spool/lpd/rattan:\
:lp=/dev/lpt0:\
:if=/usr/local/libexec/if-simple:
bamboo|ps|PS|S|panasonic|Panasonic KX-P4455 PostScript v51.4:\
:sh:sd=/var/spool/lpd/bamboo:\
:lp=/dev/ttyd5:fs#0x82000e1:xs#0x820:\
:if=/usr/local/libexec/if-simple:
#!/bin/sh
#
# if-simple - Simple text input filter for lpd
# Installed in /usr/local/libexec/if-simple
#
# Simply copies stdin to stdout. Ignores all filter arguments.
# Writes a form feed character (\f) after printing job.
/bin/cat &ero;&ero; printf "\f" &ero;&ero; exit 0
exit 2
#!/bin/sh
#
# hpif - Simple text input filter for lpd for HP-PCL based printers
# Installed in /usr/local/libexec/hpif
#
# Simply copies stdin to stdout. Ignores all filter arguments.
# Tells printer to treat LF as CR+LF. Writes a form feed character
# after printing job.
printf "\033&ero;k2G" &ero;&ero; cat &ero;&ero; printf "\f" &ero;&ero; exit 0
exit 2
Here's an example /etc/printcap from
a host called orchid. It has a single printer
attached to its first parallel port, a Hewlett
Packard LaserJet 3Si named
#
# /etc/printcap for host orchid
#
teak|hp|laserjet|Hewlett Packard LaserJet 3Si:\
:lp=/dev/lpt0:sh:sd=/var/spool/lpd/teak:mx#0:\
:if=/usr/local/libexec/hpif:
#!bin/sh
#
# DVI to PostScript printer filter
# Installed in /usr/local/libexec/psdf
#
# Invoked by lpd when user runs lpr -d
#
exec /usr/local/bin/dvips -f | /usr/local/libexec/lprps "$@"
This script runs ) with the arguments LPD passed to this script.
#!/bin/sh
#
# hpvf - Convert GIF files into HP/PCL, then print
# Installed in /usr/local/libexec/hpvf
PATH=/usr/X11R6/bin:$PATH; export PATH
giftopnm | ppmtopgm | pgmtopbm | pbmtolj -resolution 300 \
&& exit 0 \
|| exit 2
It works by converting the GIF file into a portable
anymap, converting that into a portable graymap,
converting that into a portable bitmap, and converting
that into LaserJet/PCL-compatible data.
Here's the /etc/printcap file with an entry for
a printer using the above filter:
#
# /etc/printcap for host orchid
#
teak|hp|laserjet|Hewlett Packard LaserJet 3Si:\
:lp=/dev/lpt0:sh:sd=/var/spool/lpd/teak:mx#0:\
:if=/usr/local/libexec/hpif:\
:vf=/usr/local/libexec/hpvf:
The following script is a conversion filter for troff
data from the groff typesetting system for the
PostScript printer named
#!/bin/sh
#
# pstf - Convert groff's troff data into PS, then print.
# Installed in /usr/local/libexec/pstf
#
exec grops | /usr/local/libexec/lprps "$@"
The above script makes use of
#!/bin/sh
#
# pstf - Convert groff's troff data into PS, then print.
# Installed in /usr/local/libexec/pstf
#
exec grops
That's it. Here's the entry we need to add to
/etc/printcap to enable the filter:
#!/bin/sh
#
# hpdf - Print DVI data on HP/PCL printer
# Installed in /usr/local/libexec/hpdf
PATH=/usr/local/bin:$PATH; export PATH
#
# Define a function to clean up our temporary files. These exist
# in the current directory, which will be the spooling directory
# for the printer.
#
cleanup() {
rm -f hpdf$$.dvi
}
#
# Define a function to handle fatal errors: print the given message
# and exit 2. Exiting with 2 tells LPD to don't try to reprint the
# job.
#
fatal() {
echo "$@" 1>&ero;2
cleanup
exit 2
}
#
# If user removes the job, LPD will send SIGINT, so trap SIGINT
# (and a few other signals) to clean up after ourselves.
#
trap cleanup 1 2 15
#
# Make sure we're not colliding with any existing files.
#
cleanup
#
# Link the DVI input file to standard input (the file to print).
#
ln -s /dev/fd/0 hpdf$$.dvi || fatal "Cannot symlink /dev/fd/0"
#
# Make LF = CR+LF
#
printf "\033&ero;k2G" || fatal "Cannot initialize printer"
#
# Convert and print. Return value from dvilj2p doesn't seem to be
# reliable, so we ignore it.
#
dvilj2p -M1 -q -e- dfhp$$.dvi
#
# Clean up and exit
#
cleanup
exit 0
#!/bin/sh
#
# DVI to PostScript printer filter
# Installed in /usr/local/libexec/psdf
#
# Invoked by lpd when user runs lpr -d
#
orig_args="$@"
fail() {
echo "$@" 1>&ero;2
exit 2
}
while getopts "x:y:n:h:" option; do
case $option in
x|y) ;; # Ignore
n) login=$OPTARG ;;
h) host=$OPTARG ;;
*) echo "LPD started `basename $0` wrong." 1>&ero;2
exit 2
;;
esac
done
[ "$login" ] || fail "No login name"
[ "$host" ] || fail "No host name"
( /u/kelly/freebsd/printing/filters/make-ps-header $login $host "DVI File"
/usr/local/bin/dvips -f ) | eval /usr/local/libexec/lprps $orig_args
Notice how the filter has to parse the argument list in
order to determine the user and host name. The parsing
for the other conversion filters is identical. The text
filter takes a slightly different set of arguments, though
(see section ).
As we've mentioned before, the above scheme, though fairly
simple, disables the ``suppress header page'' option (the
: write an output
filter that parses the LPD-generated header page and
produces a PostScript version. If the user submits the
job with
#!/bin/sh
#
# diablo-if-net - Text filter for Diablo printer `scrivener' listening
# on port 5100. Installed in /usr/local/libexec/diablo-if-net
#
exec /usr/libexec/lpr/lpf "$@" | /usr/local/libexec/netprint scrivener 5100
#
# /etc/printcap for host rose - restricted group for bamboo
#
rattan|line|diablo|lp|Diablo 630 Line Printer:\
:sh:sd=/var/spool/lpd/rattan:\
:lp=/dev/lpt0:\
:if=/usr/local/libexec/if-simple:
bamboo|ps|PS|S|panasonic|Panasonic KX-P4455 PostScript v51.4:\
:sh:sd=/var/spool/lpd/bamboo:sc:rg=artists:\
:lp=/dev/ttyd5:fs#0x82000e1:xs#0x820:rw:\
:if=/usr/local/libexec/psif:\
:df=/usr/local/libexec/psdf:
Let's leave the other example /etc/printcap file
(for the host orchid) alone. Of course, anyone on orchid
can print to
orchid
violet
madrigal.fishbaum.de
This means rose will accept requests from the hosts
orchid, violet, and madrigal.fishbaum.de. If any
other host tries to access rose's LPD, LPD will
refuse them.