29397ffde5
Submitted by: Philippe Charnier <charnier@lirmm.fr>
3877 lines
142 KiB
Plaintext
3877 lines
142 KiB
Plaintext
<!-- This is an SGML document in the linuxdoc DTD describing
|
|
Printing with FreeBSD. By Sean Kelly, 1995.
|
|
|
|
$Id: printing.sgml,v 1.2 1995/10/01 22:16:19 jfieber Exp $
|
|
|
|
The FreeBSD Documentation Project
|
|
|
|
<!DOCTYPE linuxdoc PUBLIC "-//FreeBSD//DTD linuxdoc//EN">
|
|
|
|
<article>
|
|
<title> Printing with FreeBSD
|
|
<author> Sean Kelly <tt/kelly@fsl.noaa.gov/
|
|
<date> 30 September 1995, (c) 1995
|
|
|
|
<abstract> This document describes printing with FreeBSD. It
|
|
tells how to set up printer hardware, how to configure FreeBSD
|
|
to use printers, and how to control the print queue and print
|
|
a variety of file formats. </abstract>
|
|
|
|
<toc>
|
|
-->
|
|
|
|
<chapt><heading>Printing<label id="printing"></heading>
|
|
|
|
<p><em>Contributed by &a.kelly;<newline>30 September 1995</em>
|
|
|
|
In order to use printers with FreeBSD, you'll need to set
|
|
them up to work with the Berkeley line printer spooling
|
|
system, also known as the LPD spooling system. It's the
|
|
standard printer control system in FreeBSD. This section
|
|
introduces the LPD spooling system, often simply called LPD.
|
|
|
|
If you're already familiar with LPD or another printer
|
|
spooling system, you may wish to skip to section <ref
|
|
id="printing:intro:setup" name="Setting up the spooling
|
|
system">.
|
|
|
|
<sect><heading>What the Spooler Does<label
|
|
id="printing:intro:spooler"></heading>
|
|
|
|
<p> LPD controls everything about a host's printers. It's
|
|
responsible for a number of things:
|
|
|
|
<itemize>
|
|
<item>It controls access to attached printers and
|
|
printers attached to other hosts on the network.
|
|
|
|
<item>It enables users to submit files to be printed;
|
|
these submissions are known as <em/jobs/.
|
|
|
|
<item>It prevents multiple users from accessing a printer
|
|
at the same time by maintaining a <em/queue/ for each
|
|
printer.
|
|
|
|
<item>It can print <em/header pages/ (also known as
|
|
<em/banner/ or <em/burst/ pages) so users can easily
|
|
find jobs they've printed in a stack of printouts.
|
|
|
|
<item>It takes care of communications parameters for
|
|
printers connected on serial ports.
|
|
|
|
<item>It can send jobs over the network to another LPD
|
|
spooler on another host.
|
|
|
|
<item>It can run special filters to format jobs to be
|
|
printed for various printer languages or printer
|
|
capabilities.
|
|
|
|
<item>It can account for printer usage.
|
|
</itemize>
|
|
|
|
Through a configuration file, and by providing the special
|
|
filter programs, you can enable the LPD system to do all or
|
|
some subset of the above for a great variety of printer
|
|
hardware.
|
|
|
|
<sect><heading>Why You Should Use the Spooler<label
|
|
id="printing:intro:why"></heading>
|
|
|
|
<p> 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
|
|
|
|
<itemize>
|
|
<item>LPD prints jobs in the background; you don't have
|
|
to wait for data to be copied to the printer.
|
|
|
|
<item>LPD can conveniently run a job to be printed
|
|
through filters to add date/time headers or convert a
|
|
special file format (such as a TeX DVI file) into a
|
|
format the printer will understand. You won't have to do
|
|
these steps manually.
|
|
|
|
<item>Many free and commercial programs that provide a
|
|
print feature usually expect to talk to the spooler on
|
|
your system. By setting up the spooling system, you'll
|
|
more easily support other software you may later add or
|
|
already have.
|
|
</itemize>
|
|
|
|
<sect><heading>Setting Up the Spooling System<label
|
|
id="printing:intro:setup"></heading>
|
|
|
|
<p> 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:
|
|
|
|
<itemize>
|
|
<item>See section <ref name="Simple Printer Setup"
|
|
id="printing:simple"> to learn how to connect a
|
|
printer, tell LPD how to communicate with it, and
|
|
print plain text files to the printer.
|
|
|
|
<item>See section <ref name="Advanced Printer Setup"
|
|
id="printing:advanced"> to find out how to print a
|
|
variety of special file formats, to print header
|
|
pages, to print across a network, to control access to
|
|
printers, and to do printer accounting.
|
|
</itemize>
|
|
|
|
|
|
<sect><heading>Simple Printer Setup<label
|
|
id="printing:simple"></heading>
|
|
|
|
<p> This section tells how to configure printer hardware and the
|
|
LPD software to use the printer. It teaches the basics:
|
|
|
|
<itemize>
|
|
<item>Section <ref id="printing:hardware" name="Hardware
|
|
Setup"> gives some hints on connecting the printer to a
|
|
port on your computer.
|
|
|
|
<item>Section <ref id="printing:software" name="Software
|
|
Setup"> shows how to setup the LPD spooler configuration
|
|
file <tt>/etc/printcap</tt>.
|
|
</itemize>
|
|
|
|
If you're setting up a printer that uses a network protocol
|
|
to accept data to print instead of a serial or parallel interface,
|
|
see <ref id="printing:advanced:network:net-if" name="Printers
|
|
With Networked Data Stream Interaces">.
|
|
|
|
Although this section is called ``Simple Printer Setup,'' it's
|
|
actually fairly complex. Getting the printer to work with
|
|
your computer and the LPD spooler is the hardest part. The
|
|
advanced options like header pages and accounting are fairly
|
|
easy once you get the printer working.
|
|
|
|
<sect1><heading>Hardware Setup<label id="printing:hardware"></heading>
|
|
|
|
<p> 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 <ref id="printing:software"
|
|
name="Software Setup">.
|
|
|
|
<sect2><heading>Ports and Cables<label
|
|
id="printing:ports"></heading>
|
|
|
|
<p> Nearly all printers you can get for a PC today support
|
|
one or both of the following interfaces:
|
|
|
|
<itemize>
|
|
<item><em/Serial/ interfaces use a serial port on your
|
|
computer to send data to the printer. Serial
|
|
interfaces are common in the computer industry and
|
|
cables are readily available and also easy to
|
|
construct. Serial interfaces sometimes need special
|
|
cables and might require you to configure somewhat
|
|
complex communications options.
|
|
|
|
<item><em/Parallel/ interfaces use a parallel port on
|
|
your computer to send data to the printer. Parallel
|
|
interfaces are common in the PC market. Cables are
|
|
readily available but more difficult to construct by
|
|
hand. There are usually no communications options
|
|
with parallel interfaces, making their configuration
|
|
exceedingly simple.
|
|
|
|
<p> Parallel interfaces are sometimes known as
|
|
``Centronics'' interfaces, named after the connector
|
|
type on the printer.
|
|
</itemize>
|
|
|
|
In general, serial interfaces are slower than parallel
|
|
interfaces. Parallel interfaces usually offer just
|
|
one-way communication (computer to printer) while serial
|
|
gives you two-way. Many newer parallel ports can also
|
|
receive data from the printer, but only few printers need
|
|
to send data back to the computer. And FreeBSD doesn't
|
|
support two-way parallel communication yet.
|
|
|
|
Usually, the only time you need two-way communication with
|
|
the printer is if the printer speaks PostScript.
|
|
PostScript printers can be very verbose. In fact,
|
|
PostScript jobs are actually programs sent to the printer;
|
|
they needn't produce paper at all and may return results
|
|
directly to the computer. PostScript also uses
|
|
two-way communication to tell the computer about problems,
|
|
such as errors in the PostScript program or paper jams.
|
|
Your users may be appreciative of such information.
|
|
Furthermore, the best way to do effective accounting with
|
|
a PostScript printer requires two-way communication: you
|
|
ask the printer for its page count (how many pages it's
|
|
printed in its lifetime), then send the user's job, then
|
|
ask again for its page count. Subtract the two values and
|
|
you know how much paper to charge the user.
|
|
|
|
So, which interface should you use?
|
|
|
|
<itemize>
|
|
<item>If you need two-way communication, use a serial
|
|
port. FreeBSD does not yet support two-way
|
|
communication over a parallel port.
|
|
|
|
<item>If you don't need two-way communication and can
|
|
pick parallel or serial, prefer the parallel
|
|
interface. It keeps a serial port free for other
|
|
peripherals---such as a terminal or a modem---and is
|
|
faster most of the time. It's also easier to
|
|
configure.
|
|
|
|
<item>Finally, use whatever works.
|
|
</itemize>
|
|
|
|
|
|
<sect2><heading>Parallel Ports<label id="printing:parallel"></heading>
|
|
|
|
<p> 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.
|
|
|
|
<sect2><heading>Serial Ports<label id="printing:serial"></heading>
|
|
|
|
<p> 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:
|
|
<itemize>
|
|
<item>A <em/modem/ cable connects each pin of the
|
|
connector on one end of the cable straight through to
|
|
its corresponding pin of the connector on the other
|
|
end. This type of cable is also known as a DTE-to-DCE
|
|
cable.
|
|
|
|
<item>A <em/null-modem/ cable connects some pins
|
|
straight through, swaps others (send data to receive
|
|
data, for example), and shorts some internally in each
|
|
connector hood. This type of cable is also known as a
|
|
DTE-to-DTE cable.
|
|
|
|
<item>A <em/serial printer/ cable, required for some
|
|
unusual printers, is like the null modem cable, but
|
|
sends some signals to their counterparts instead of
|
|
being internally shorted.
|
|
</itemize>
|
|
|
|
You should also set up the communications parameters for
|
|
the printer, usually through front-panel controls or DIP
|
|
switches on the printer. Choose the highest bps (bits per
|
|
second, sometimes <em/baud rate/) rate that both your
|
|
computer and the printer can support. Choose 7 or 8 data
|
|
bits; none, even, or odd parity; and 1 or 2 stop bits.
|
|
Also choose a flow control protocol: either none, or
|
|
XON/XOFF (also known as <em/in-band/ or <em/software/)
|
|
flow control. Remember these settings for the software
|
|
configuration that follows.
|
|
|
|
<sect1><heading>Software Setup<label id="printing:software"></heading>
|
|
|
|
<p> This section describes the software setup necessary to
|
|
print with the LPD spooling system in FreeBSD.
|
|
|
|
Here's an outline of the steps involved:
|
|
<enum>
|
|
<item>Configure your kernel, if necessary, for the port
|
|
you're using for the printer; section <ref
|
|
id="printing:kernel" name="Kernel Configuration"> tells
|
|
you what you need to do.
|
|
|
|
<item>Set the communications mode for the parallel port,
|
|
if you're using a parallel port; section <ref
|
|
id="printing:parallel-port-mode" name = "Setting the
|
|
Communication Mode for the Parallel Port"> gives
|
|
details.
|
|
|
|
<item>Test if the operating system can send data to the
|
|
printer. Section <ref id="printing:testing"
|
|
name="Checking Printer Communications"> gives some
|
|
suggestions on how to do this.
|
|
|
|
<item>Set up LPD for the printer by modifying the file
|
|
<tt>/etc/printcap</tt>. Section <ref
|
|
id="printing:printcap" name="The /etc/printcap File">
|
|
shows you how.
|
|
</enum>
|
|
|
|
<sect2><heading>Kernel Configuration<label
|
|
id="printing:kernel"></heading>
|
|
|
|
<p> 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
|
|
<tscreen>
|
|
<tt>dmesg | grep sio</tt><it/N/
|
|
</tscreen>
|
|
where <it/N/ is the number of the serial port, starting
|
|
from zero. If you see output similar to the following
|
|
<tscreen><verb>
|
|
sio2 at 0x3e8-0x3ef irq 5 on isa
|
|
sio2: type 16550A
|
|
</verb></tscreen>
|
|
then the kernel supports the port.
|
|
|
|
To find out if the kernel supports a parallel interface,
|
|
type
|
|
<tscreen>
|
|
<tt>dmesg | grep lpt</tt><it/N/
|
|
</tscreen>
|
|
where <it/N/ is the number of the parallel port, starting
|
|
from zero. If you see output similar to the following
|
|
<tscreen><verb>
|
|
lpt0 at 0x378-0x37f on isa
|
|
</verb></tscreen>
|
|
then the kernel supports the port.
|
|
|
|
You might have to reconfigure your kernel in order for the
|
|
operating system to recognize and use the parallel or
|
|
serial port you're using for the printer.
|
|
|
|
To add support for a serial port, see the section on
|
|
kernel configuration. To add support for a parallel port,
|
|
see that section <em/and/ the section that follows.
|
|
|
|
<sect3><heading>Adding <tt>/dev</tt> Entries for the Ports
|
|
<label id="printing:dev-ports"></heading>
|
|
|
|
<p> 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
|
|
<tt>/dev</tt> directory are for.
|
|
|
|
<bf>To add a <tt>/dev</tt> entry for a port:</bf>
|
|
<enum>
|
|
<item>Become root with the <tt/su/ command. Enter
|
|
the root password when prompted.
|
|
|
|
<item>Change to the <tt>/dev</tt> directory:
|
|
<tscreen><verb>
|
|
cd /dev
|
|
</verb></tscreen>
|
|
|
|
<item>Type
|
|
<tscreen>
|
|
<tt> ./MAKEDEV</tt> <it/port/
|
|
</tscreen>
|
|
where <it/port/ is the device entry for the port you
|
|
want to make. Use <tt/lpt0/ for the first parallel
|
|
port, <tt/lpt1/ for the second, and so on; use
|
|
<tt/ttyd0/ for the first serial port, <tt/ttyd1/ for
|
|
the second, and so on.
|
|
|
|
<item>Type
|
|
<tscreen>
|
|
<tt>ls -l</tt> <it/port/
|
|
</tscreen>
|
|
to make sure the device entry got created.
|
|
</enum>
|
|
|
|
<sect3><heading>Setting the Communication Mode for the Parallel Port
|
|
<label id="printing:parallel-port-mode"></heading>
|
|
|
|
<p> When you're using the parallel interface, you can
|
|
choose whether FreeBSD should use interrupt-driven or
|
|
polled communication with the printer.
|
|
|
|
<itemize>
|
|
<item>The <em/interrupt-driven/ method is the default
|
|
with the GENERIC kernel. With this method, the
|
|
operating system uses an IRQ line to determine when
|
|
the printer's ready for data.
|
|
|
|
<item>The <em/polled/ method directs the operating
|
|
system to repeatedly ask the printer if it's ready
|
|
for more data. When it responds ready, the kernel
|
|
sends more data.
|
|
</itemize>
|
|
|
|
The interrupt-driven method is somewhat faster but uses
|
|
up a precious IRQ line. You should use whichever one
|
|
works.
|
|
|
|
You can set the communications mode in two ways: by
|
|
configuring the kernel or by using the <tt/lptcontrol/
|
|
program.
|
|
|
|
<bf>To set the communications mode by configuring the
|
|
kernel:</bf>
|
|
<enum>
|
|
<item>Edit your kernel configuration file. Look for
|
|
or add an <tt/lpt0/ entry. If you're setting up the
|
|
second parallel port, use <tt/lpt1/ instead. Use
|
|
<tt/lpt2/ for the third port, and so on.
|
|
<itemize>
|
|
<item>If you want interrupt-driven mode, add the <tt/irq/
|
|
specifer:
|
|
<tscreen>
|
|
<tt>device lpt0 at isa? port? tty irq <it/N/ vector lptintr</tt>
|
|
</tscreen>
|
|
where <it/N/ is the IRQ number for your
|
|
computer's parallel port.
|
|
|
|
<item>If you want polled mode, don't add the
|
|
<tt/irq/ specifier:
|
|
<tscreen>
|
|
<tt>device lpt0 at isa? port? tty vector lptintr</tt>
|
|
</tscreen>
|
|
</itemize>
|
|
<item>Save the file. Then configure, build, and
|
|
install the kernel, then reboot. See <ref id="kernelconfig"
|
|
name="kernel configuration"> for more details.
|
|
</enum>
|
|
|
|
<bf>To set the communications mode with
|
|
<tt/lptcontrol/:</bf>
|
|
<itemize>
|
|
<item>
|
|
Type
|
|
<tscreen>
|
|
<tt>lptcontrol -i -u <it/N/</tt>
|
|
</tscreen>
|
|
to set interrupt-driven mode for <tt/lpt<it/N//.
|
|
|
|
<item>
|
|
Type
|
|
<tscreen>
|
|
<tt>lptcontrol -p -u <it/N/</tt>
|
|
</tscreen>
|
|
to set polled-mode for <tt/lpt<it/N//.
|
|
</itemize>
|
|
You could put these commands in your
|
|
<tt>/etc/rc.local</tt> file to set the mode each time
|
|
your system boots. See lptcontrol(8) for more
|
|
information.
|
|
|
|
<sect3><heading>Checking Printer Communications<label
|
|
id="printing:testing"></heading>
|
|
|
|
<p> 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 <tt/lptest/ is perfect: it generates
|
|
all 96 printable ASCII characters in 96 lines.
|
|
|
|
For a PostScript (or other language-based) printer,
|
|
we'll need a more sophisticated test. A small
|
|
PostScript program, such as the following, will suffice:
|
|
<code>
|
|
%!PS
|
|
100 100 moveto 300 300 lineto stroke
|
|
310 310 moveto
|
|
/Helvetica findfont 12 scalefont setfont
|
|
(Is this thing working?) show
|
|
showpage
|
|
</code>
|
|
<em/Note:/ When this document refers to a printer
|
|
language, I'm assuming a language like PostScript, and
|
|
not Hewlett Packard's PCL. Although PCL has great
|
|
functionality, you can intermingle plain text with its
|
|
escape sequences. PostScript cannot directly print
|
|
plain text, and that's the kind of printer language for
|
|
which we must make special accomodations.
|
|
|
|
<sect4><heading>Checking a Parallel Printer<label
|
|
id="printing:checking:parallel"></heading>
|
|
|
|
<p> This section tells you how to check if FreeBSD can
|
|
communicate with a printer connected to a parallel port.
|
|
|
|
<bf>To test a printer on a parallel port:</bf>
|
|
<enum>
|
|
<item>Become root with <tt/su/.
|
|
<item>Send data to the printer.
|
|
<itemize>
|
|
<item>If the printer can print plain text, then
|
|
use <tt/lptest/. Type:
|
|
<tscreen>
|
|
<tt>lptest > /dev/lpt<it/N/</tt>
|
|
</tscreen>
|
|
where <it/N/ is the number of the parallel
|
|
port, starting from zero.
|
|
|
|
<item>If the printer understands PostScript or
|
|
other printer language, then send a small
|
|
program to the printer. Type
|
|
<tscreen>
|
|
<tt>cat > /dev/lpt<it/N/</tt>
|
|
</tscreen>
|
|
Then, line by line, type the program
|
|
<em/carefully/ as you can't edit a line once
|
|
you've pressed RETURN or ENTER. When you've
|
|
finished entering the program, press
|
|
CONTROL+D, or whatever your end of file key
|
|
is.
|
|
|
|
<p> Alternatively, you can put the program in
|
|
a file and type
|
|
<tscreen>
|
|
<tt>cat <it/file/ > /dev/lpt<it/N/</tt>
|
|
</tscreen>
|
|
where <it/file/ is the name of the file
|
|
containing the program you want to send to
|
|
the printer.
|
|
</itemize>
|
|
</enum>
|
|
|
|
You should see something print. Don't worry if the
|
|
text doesn't look right; we'll fix such things later.
|
|
|
|
<sect4><heading>Checking a Serial Printer<label
|
|
id="printing:checking:serial"></heading>
|
|
|
|
<p> This section tells you how to check if FreeBSD can
|
|
communicate with a printer on a serial port.
|
|
|
|
<bf>To test a printer on a serial port:</bf>
|
|
<enum>
|
|
<item>Become root with <tt/su/.
|
|
|
|
<item>Edit the file <tt>/etc/remote</tt>. Add the
|
|
following entry:
|
|
<tscreen>
|
|
<tt>printer:dv=/dev/<it/port/:br#<it/bps-rate/:pa=<it/parity/</tt>
|
|
</tscreen>
|
|
where <it/port/ is the device entry for the serial
|
|
port (<tt/ttyd0/, <tt/ttyd1/, etc.), <it/bps-rate/
|
|
is the bits-per-second rate at which the printer
|
|
communicates, and <it/parity/ is the parity
|
|
required by the printer (either <tt/even/,
|
|
<tt/odd/, <tt/none/, or <tt/zero/).
|
|
<p>
|
|
Here's a sample entry for a printer connected
|
|
via a serial line to the third serial port at
|
|
19200 bps with no parity:
|
|
<code>
|
|
printer:dv=/dev/ttyd2:br#19200:pa=none
|
|
</code>
|
|
|
|
<item>Connect to the printer with <tt/tip/. Type:
|
|
<tscreen><verb>
|
|
tip printer
|
|
</verb></tscreen>
|
|
If this step doesn't work, edit the file
|
|
<tt>/etc/remote</tt> again and try using
|
|
<tt>/dev/cuaa<it/N/</tt> instead of
|
|
<tt>/dev/ttyd<it/N/</tt>.
|
|
|
|
<item>Send data to the printer.
|
|
<itemize>
|
|
<item>If the printer can print plain text, then
|
|
use <tt/lptest/. Type:
|
|
<tscreen><verb>
|
|
~$lptest
|
|
</verb></tscreen>
|
|
|
|
<item>If the printer understands PostScript or
|
|
other printer language, then send a small
|
|
program to the printer. Type the program,
|
|
line by line, <em/very carefully/ as
|
|
backspacing or other editing keys may be
|
|
significant to the printer. You may also need
|
|
to type a special end-of-file key for the
|
|
printer so it knows it received the whole
|
|
program. For PostScript printers, press
|
|
CONTROL+D.
|
|
|
|
<p> Alternatively, you can put the program in
|
|
a file and type
|
|
<tscreen>
|
|
<tt>˜><it/file/</tt>
|
|
</tscreen>
|
|
where <it/file/ is the name of the file
|
|
containing the program. After <tt/tip/
|
|
sends the file, press any required
|
|
end-of-file key.
|
|
</itemize>
|
|
</enum>
|
|
|
|
You should see something print. Don't worry if the
|
|
text doesn't look right; we'll fix that later.
|
|
|
|
<sect2><heading>Enabling the Spooler: The <tt>/etc/printcap</tt> File
|
|
<label id="printing:printcap"></heading>
|
|
|
|
<p> 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
|
|
<tt>/etc/printcap</tt>. 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 <tt/printcap/ file is straightforward.
|
|
Use your favorite text editor to make changes to
|
|
<tt>/etc/printcap</tt>. The format is identical to other
|
|
capability files like <tt>/usr/share/misc/termcap</tt> and
|
|
<tt>/etc/remote</tt>. For complete information about the
|
|
format, see the cgetent(3).
|
|
|
|
The simple spooler configuration consists of the following steps:
|
|
<enum>
|
|
<item>Pick a name (and a few convenient aliases) for
|
|
the printer, and put them in the
|
|
<tt>/etc/printcap</tt> file; see <ref
|
|
id="printing:naming" name="Naming the Printer">.
|
|
|
|
<item>Turn off header pages (which are on by default)
|
|
by inserting the <tt/sh/ capability; see <ref
|
|
id="printing:no-header-pages" name="Suppressing Header
|
|
Pages">.
|
|
|
|
<item>Make a spooling directory, and specify its
|
|
location with the <tt/sd/ capability; see <ref
|
|
id="printing:spooldir" name="Making the Spooling
|
|
Directory">.
|
|
|
|
<item>Set the <tt>/dev</tt> entry to use for the
|
|
printer, and note it in <tt>/etc/printcap</tt> with
|
|
the <tt/lp/ capability; see <ref id="printing:device"
|
|
name="Identifying the Printer Device">. Also, if the
|
|
printer's on a serial port, set up the communication
|
|
parameters with the <tt/fs/, <tt/fc/, <tt/xs/, and
|
|
<tt/xc/ capabilities; see <ref id="printing:commparam"
|
|
name="Configuring Spooler Communications Parameters">.
|
|
|
|
<item>Install a plain text input filter; see <ref
|
|
id="printing:textfilter" name="Installing the Text
|
|
Filter">
|
|
|
|
<item>Test the setup by printing something with the
|
|
<tt/lpr/ command; see <ref id="printing:trying"
|
|
name="Trying It Out"> and <ref
|
|
id="printing:troubleshooting" name="Troubleshooting">.
|
|
</enum>
|
|
|
|
<em/Note:/ Language-based printers, such as PostScript
|
|
printers, can't directly print plain text. The simple
|
|
setup outlined above and described in the following
|
|
sections assumes that if you're installing such a printer
|
|
you'll print only files that the printer can understand.
|
|
|
|
Users often expect that they can print plain text to any
|
|
of the printers installed on your system. Programs that
|
|
interface to LPD to do their printing usually make the
|
|
same assumption. If you're installing such a printer and
|
|
want to be able to print jobs in the printer language
|
|
<em/and/ print plain text jobs, you're strongly urged to
|
|
add an additional step to the simple setup outlined above:
|
|
install an automatic plain-text--to--PostScript (or other
|
|
printer language) conversion program. Section <ref
|
|
id="printing:advanced:if-conversion" name="Accomodating
|
|
Plain Text Jobs on PostScript Printers"> tells how to do
|
|
this.
|
|
|
|
<sect3><heading>Naming the Printer<label
|
|
id="printing:naming"></heading>
|
|
|
|
<p> 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
|
|
<tt>/etc/printcap</tt> should have the alias
|
|
<tt/lp/. This is the default printer's name. If users
|
|
don't have the PRINTER environment variable nor
|
|
specify a printer name on the command line of any of the
|
|
LPD commands, then <tt/lp/ will be the default printer
|
|
they get to use.
|
|
|
|
Also, it's common practice to make the last alias for a
|
|
printer be a full description of the printer, including
|
|
make and model.
|
|
|
|
Once you've picked a name and some common aliases, put
|
|
them in the <tt>/etc/printcap</tt> 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
|
|
<tt>/etc/printcap</tt> that defines two printers (a
|
|
Diablo 630 line printer and a Panasonic KX-P4455
|
|
PostScript laser printer):
|
|
<code>
|
|
#
|
|
# /etc/printcap for host rose
|
|
#
|
|
rattan|line|diablo|lp|Diablo 630 Line Printer:
|
|
|
|
bamboo|ps|PS|S|panasonic|Panasonic KX-P4455 PostScript v51.4:
|
|
</code>
|
|
In this example, the first printer is named <tt/rattan/
|
|
and has as aliases <tt/line/, <tt/diablo/, <tt/lp/, and
|
|
<tt/Diablo 630 Line Printer/. Since it has the alias
|
|
<tt/lp/, it's also the default printer. The second is
|
|
named <tt/bamboo/, and has as aliases <tt/ps/, <tt/PS/,
|
|
<tt/S/, <tt/panasonic/, and <tt/Panasonic KX-P4455
|
|
PostScript v51.4/.
|
|
|
|
<sect3><heading>Suppressing Header Pages<label
|
|
id="printing:no-header-pages"></heading>
|
|
|
|
<p> The LPD spooling system will by default print a
|
|
<em/header page/ for each job. The header page contains
|
|
the user name who requested the job, the host from which
|
|
the job came, and the name of the job, in nice large
|
|
letters. Unfortunately, all this extra text gets in the
|
|
way of debugging the simple printer setup, so we'll
|
|
suppress header pages.
|
|
|
|
To suppress header pages, add the <tt/sh/ capability to
|
|
the entry for the printer in
|
|
<tt>/etc/printcap</tt>. Here's the example
|
|
<tt>/etc/printcap</tt> with <tt/sh/ added:
|
|
<code>
|
|
#
|
|
# /etc/printcap for host rose - no header pages anywhere
|
|
#
|
|
rattan|line|diablo|lp|Diablo 630 Line Printer:\
|
|
:sh:
|
|
|
|
bamboo|ps|PS|S|panasonic|Panasonic KX-P4455 PostScript v51.4:\
|
|
:sh:
|
|
</code>
|
|
Note how we used the correct format: the first line
|
|
starts in the leftmost column, and subsequent lines are
|
|
indented with a single TAB. Every line in an entry
|
|
except the last ends in a backslash character.
|
|
|
|
<sect3><heading>Making the Spooling Directory<label
|
|
id="printing:spooldir"></heading>
|
|
|
|
<p> The next step in the simple spooler setup is to make a
|
|
<em/spooling directory/, a directory where print jobs
|
|
reside until they're printed, and where a number of
|
|
other spooler support files live.
|
|
|
|
Because of the variable nature of spooling directories,
|
|
it's customary to put these directories under
|
|
<tt>/var/spool</tt>. It's not necessary to backup the
|
|
contents of spooling directories, either. Recreating
|
|
them is as simple as running <tt/mkdir/.
|
|
|
|
It's also customary to make the directory with a name
|
|
that's identical to the name of the printer, as shown
|
|
below:
|
|
<tscreen>
|
|
<tt>mkdir /var/spool/<it>printer-name</it></tt>
|
|
</tscreen>
|
|
However, if you have a lot of printers on your network,
|
|
you might want to put the spooling directories under a
|
|
single directory that you reserve just for printing with
|
|
LPD. We'll do this for our two example printers
|
|
<tt/rattan/ and <tt/bamboo/:
|
|
<tscreen><verb>
|
|
mkdir /var/spool/lpd
|
|
mkdir /var/spool/lpd/rattan
|
|
mkdir /var/spool/lpd/bamboo
|
|
</verb></tscreen>
|
|
|
|
<em/Note:/ If you're concerned about the privacy of jobs
|
|
that users print, you might want to protect the spooling
|
|
directory so it's not publicly accessible. Spooling
|
|
directories should be owned and be readable, writable,
|
|
and searchable by user daemon and group daemon, and no
|
|
one else. We'll do this for our example printers:
|
|
|
|
<tscreen><verb>
|
|
chown daemon.daemon /var/spool/lpd/rattan
|
|
chown daemon.daemon /var/spool/lpd/bamboo
|
|
chmod 770 /var/spool/lpd/rattan
|
|
chmod 770 /var/spool/lpd/bamboo
|
|
</verb></tscreen>
|
|
|
|
Finally, you need to tell LPD about these directories
|
|
using the <tt>/etc/printcap</tt> file. You specify the
|
|
pathname of the spooling directory with the <tt/sd/
|
|
capability:
|
|
<code>
|
|
#
|
|
# /etc/printcap for host rose - added spooling directories
|
|
#
|
|
rattan|line|diablo|lp|Diablo 630 Line Printer:\
|
|
:sh:sd=/var/spool/lpd/rattan:
|
|
|
|
bamboo|ps|PS|S|panasonic|Panasonic KX-P4455 PostScript v51.4:\
|
|
:sh:sd=/var/spool/lpd/bamboo:
|
|
</code>
|
|
Note that the name of the printer starts in the first
|
|
column but all other entries describing the printer
|
|
should be indented with a tab and each line escaped with
|
|
a backslash.
|
|
|
|
If you don't specify a spooling directory with <tt/sd/,
|
|
the spooling system will use <tt>/var/spool/lpd</tt> as
|
|
a default.
|
|
|
|
<sect3><heading>Identifying the Printer Device<label
|
|
id="printing:device"></heading>
|
|
|
|
<p> In section <ref id="printing:dev-ports" name="Adding
|
|
/dev Entries for the Ports">, we identified which
|
|
entry in the <tt>/dev</tt> 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 <tt>/dev</tt> entry pathname in the
|
|
<tt>/etc/printcap</tt> file using the <tt/lp/
|
|
capability.
|
|
|
|
In our running example, let's assume that <tt/rattan/ is
|
|
on the first parallel port, and <tt/bamboo/ is on a
|
|
sixth serial port; here are the additions to
|
|
<tt>/etc/printcap</tt>:
|
|
<code>
|
|
#
|
|
# /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:
|
|
</code>
|
|
|
|
If you don't specify the <tt/lp/ capability for a
|
|
printer in your <tt>/etc/printcap</tt> file, LPD uses
|
|
<tt>/dev/lp</tt> as a default. <tt>/dev/lp</tt>
|
|
currently doesn't exist in FreeBSD.
|
|
|
|
If the printer you're installing is connected to a
|
|
parallel port, skip to the section <ref name="Installing
|
|
the Text Filter" id="printing:textfilter">. Otherwise,
|
|
be sure to follow the instructions in the next section.
|
|
|
|
<sect3><heading>Configuring Spooler Communication
|
|
Parameters<label id="printing:commparam"></heading>
|
|
|
|
<p> 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
|
|
<itemize>
|
|
<item>It lets you try different communication
|
|
parameters by simply editing the
|
|
<tt>/etc/printcap</tt> file; you don't have to
|
|
recompile the filter program.
|
|
|
|
<item>It enables the spooling system to use the same
|
|
filter program for multiple printers which may have
|
|
different serial communication settings.
|
|
</itemize>
|
|
|
|
The following <tt>/etc/printcap</tt> capabilities
|
|
control serial communication parameters of the device
|
|
listed in the <tt/lp/ capability:
|
|
<descrip>
|
|
<tag/<tt>br#<it/bps-rate/</tt>/
|
|
|
|
Sets the communications speed of the device to
|
|
<it/bps-rate/, where <it/bps-rate/ can be 50, 75,
|
|
110, 134, 150, 200, 300, 600, 1200, 1800, 2400,
|
|
4800, 9600, 19200, or 38400 bits-per-second.
|
|
|
|
<tag/<tt>fc#<it/clear-bits/</tt>/
|
|
|
|
Clears the flag bits <it/clear-bits/ in the
|
|
<tt/sgttyb/ structure after opening the device.
|
|
|
|
<tag/<tt>fs#<it/set-bits/</tt>/
|
|
|
|
Sets the flag bits <it/set-bits/ in the <tt/sgttyb/
|
|
structure.
|
|
|
|
<tag/<tt>xc#<it/clear-bits/</tt>/
|
|
|
|
Clears local mode bits <it/clear-bits/ after opening
|
|
the device.
|
|
|
|
<tag/<tt>xs#<it/set-bits/</tt>/
|
|
|
|
Sets local mode bits <it/set-bits/.
|
|
</descrip>
|
|
For more information on the bits for the <tt/fc/,
|
|
<tt/fs/, <tt/xc/, and <tt/xs/ capabilities, see the file
|
|
<tt>/usr/include/sys/ioctl_compat.h</tt>.
|
|
|
|
When LPD opens the device specified by the <tt/lp/
|
|
capability, it reads the flag bits in the <tt/sgttyb/
|
|
structure; it clears any bits in the <tt/fc/ capability,
|
|
then sets bits in the <tt/fs/ capability, then applies
|
|
the resultant setting. It does the same for the local
|
|
mode bits as well.
|
|
|
|
Let's add to our example printer on the sixth serial
|
|
port. We'll set the bps rate to 38400. For the flag
|
|
bits, we'll set the TANDEM, ANYP, LITOUT, FLUSHO, and
|
|
PASS8 flags. For the local mode bits, we'll set the
|
|
LITOUT and PASS8 flags:
|
|
<tscreen><verb>
|
|
bamboo|ps|PS|S|panasonic|Panasonic KX-P4455 PostScript v51.4:\
|
|
:sh:sd=/var/spool/lpd/bamboo:\
|
|
:lp=/dev/ttyd5:fs#0x82000c1:xs#0x820:
|
|
</verb></tscreen>
|
|
|
|
|
|
<sect3><heading>Installing the Text Filter<label
|
|
id="printing:textfilter"></heading>
|
|
|
|
<p> We're now ready to tell LPD what text filter to use to
|
|
send jobs to the printer. A <em/text filter/, also
|
|
known as an <em/input filter/, is a program that LPD
|
|
runs when it has a job to print. When LPD runs the text
|
|
filter for a printer, it sets the filter's standard
|
|
input to the job to print, and its standard output to
|
|
the printer device specified with the <tt/lp/
|
|
capability. The filter is expected to read the job from
|
|
standard input, peform any necessary translation for the
|
|
printer, and write the results to standard output, which
|
|
will get printed. For more information on the text
|
|
filter, see section <ref id="printing:advanced:filters"
|
|
name="Filters">.
|
|
|
|
For our simple printer setup, the text filter can be a
|
|
small shell script that just executes <tt>/bin/cat</tt>
|
|
to send the job to the printer. FreeBSD comes with
|
|
another filter called <tt/lpf/ that handles backspacing
|
|
and underlining for printers that might not deal with
|
|
such character streams well. And, of course, you can
|
|
use any other filter program you want. The filter
|
|
<tt/lpf/ is described in detail in section <ref
|
|
id="printing:advanced:lpf" name="lpf: a Text Filter">.
|
|
|
|
First, let's make the shell script
|
|
<tt>/usr/local/libexec/if-simple</tt> be a simple text
|
|
filter. Put the following text into that file with your
|
|
favorite text editor:
|
|
<code>
|
|
#!/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
|
|
</code>
|
|
Make the file executable:
|
|
<tscreen><verb>
|
|
chmod 555 /usr/local/libexec/if-simple
|
|
</verb></tscreen>
|
|
|
|
And then tell LPD to use it by specifying it with the
|
|
<tt/if/ capability in <tt>/etc/printcap</tt>. We'll add
|
|
it to the two printers we have so far in the example
|
|
<tt>/etc/printcap</tt>:
|
|
<code>
|
|
#
|
|
# /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:
|
|
</code>
|
|
|
|
<sect3><heading>Trying It Out<label id="printing:trying"></heading>
|
|
|
|
<p> 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 <tt/lpr/, which submits a job for printing.
|
|
|
|
You can combine <tt/lpr/ with the <tt/lptest/ program,
|
|
introduced in section <ref id="printing:testing"
|
|
name="Checking Printer Communications"> to generate some
|
|
test text.
|
|
|
|
<bf>To test the simple LPD setup:</bf>
|
|
|
|
<p> Type:
|
|
<tscreen>
|
|
<tt>lptest 20 5 | lpr -P<it/printer-name/</tt>
|
|
</tscreen>
|
|
where <it/printer-name/ is a the name of a printer (or
|
|
an alias) specified in <tt>/etc/printcap</tt>. To test
|
|
the default printer, type <tt/lpr/ without any <tt/-P/
|
|
argument. Again, if you're testing a printer that
|
|
expects PostScript, send a PostScript program in that
|
|
language instead of using <tt/lptest/. You can do so by
|
|
putting the program in a file and typing <tt/lpr
|
|
<it/file//.
|
|
|
|
For a PostScript printer, you should get the results
|
|
of the program. If you're using <tt/lptest/, then your
|
|
results should look like the following:
|
|
|
|
<tscreen><verb>
|
|
!"#$%&ero;'()*+,-./01234
|
|
"#$%&ero;'()*+,-./012345
|
|
#$%&ero;'()*+,-./0123456
|
|
$%&ero;'()*+,-./01234567
|
|
%&ero;'()*+,-./012345678
|
|
</verb></tscreen>
|
|
|
|
To further test the printer, try downloading larger
|
|
programs (for language-based printers) or running
|
|
<tt/lptest/ with different arguments. For example,
|
|
<tt/lptest 80 60/ will produce 60 lines of 80 characters
|
|
each.
|
|
|
|
If the printer didn't work, see the next section, <ref
|
|
id="printing:troubleshooting" name="Troubleshooting">.
|
|
|
|
<sect3><heading>Troubleshooting<label
|
|
id="printing:troubleshooting"></heading>
|
|
|
|
<p> After performing the simple test with <tt/lptest/, you
|
|
might've gotten one of the following results instead of
|
|
the correct printout:
|
|
<descrip>
|
|
<tag/It worked, after awhile; or, it didn't eject a full sheet./
|
|
|
|
The printer printed the above, but it sat for awhile
|
|
and did nothing. In fact, you might've needed to
|
|
press a PRINT REMAINING or FORM FEED button on the
|
|
printer to get any results to appear.
|
|
|
|
If this is the case, the printer was probably
|
|
waiting to see if there was any more data for your
|
|
job before it printed anything. To fix this
|
|
problem, you can have the text filter send a FORM
|
|
FEED character (or whatever is necessary) to the
|
|
printer. This is usually sufficient to have the
|
|
printer immediately print any text remaining in its
|
|
internal buffer. It's also useful to make sure each
|
|
print job ends on a full sheet, so the next job
|
|
doesn't start somewhere on the middle of the last
|
|
page of the previous job.
|
|
|
|
The following replacement for the shell script
|
|
<tt>/usr/local/libexec/if-simple</tt> prints a form
|
|
feed after it sends the job to the printer:
|
|
<code>
|
|
#!/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
|
|
</code>
|
|
|
|
<tag/It produced the ``staircase effect.''/
|
|
|
|
You got the following on paper:
|
|
<tscreen><verb>
|
|
!"#$%&ero;'()*+,-./01234
|
|
"#$%&ero;'()*+,-./012345
|
|
#$%&ero;'()*+,-./0123456
|
|
</verb></tscreen>
|
|
You've become another victim of the <em/staircase
|
|
effect/, caused by conflicting interpretations of
|
|
what characters should indicate a new-line.
|
|
UNIX-style operating systems use a single character:
|
|
ASCII code 10, the line feed (LF). MS-DOS, OS/2,
|
|
and others uses a pair of characters, ASCII code 10
|
|
<em/and/ ASCII code 13 (the carriage return or CR).
|
|
Many printers use the MS-DOS convention for
|
|
representing new-lines.
|
|
|
|
When you print with FreeBSD, your text used just the
|
|
line feed character. The printer, upon seeing a
|
|
line feed character, advanced the paper one line,
|
|
but maintained the same horizontal position on the
|
|
page for the next character to print. That's what
|
|
the carriage return is for: to move the location of
|
|
the next character to print to the left edge of the
|
|
paper.
|
|
|
|
Here's what FreeBSD wants your printer to do:
|
|
<tscreen><verb>
|
|
Printer received CR Printer prints CR
|
|
Printer received LF Printer prints CR + LF
|
|
</verb></tscreen>
|
|
|
|
Here are some ways to achieve this:
|
|
<itemize>
|
|
<item>Use the printer's configuration switches or
|
|
control panel to alter its interpretation of
|
|
these characters. Check your printer's manual
|
|
to find out how to do this.
|
|
|
|
<p> <em/Note:/ If you boot your system into
|
|
other operating systems besides FreeBSD, you
|
|
may have to <em/reconfigure/ the printer to
|
|
use a an interpretation for CR and LF
|
|
characters that those other operating systems
|
|
use. You might prefer one of the other
|
|
solutions, below.
|
|
|
|
<item>Have FreeBSD's serial line driver
|
|
automatically convert LF to CR+LF. Of course,
|
|
this works with printers on serial ports
|
|
<em/only/. To enable this feature, set the
|
|
CRMOD bit in <tt/fs/ capability in the
|
|
<tt>/etc/printcap</tt> file for the printer.
|
|
|
|
<item>Send an <em/escape code/ to the printer to
|
|
have it temporarily treat LF characters
|
|
differently. Consult your printer's manual for
|
|
escape codes that your printer might support.
|
|
When you find the proper escape code, modify the
|
|
text filter to send the code first, then send
|
|
the print job.
|
|
|
|
<p> Here's an example text filter for printers
|
|
that understand the Hewlett-Packard PCL escape
|
|
codes. This filter makes the printer treat LF
|
|
characters as a LF and CR; then it sends the
|
|
job; then it sends a form feed to eject the
|
|
last page of the job. It should work with
|
|
nearly all Hewlett Packard printers.
|
|
|
|
<code>
|
|
#!/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
|
|
</code>
|
|
|
|
Here's an example <tt>/etc/printcap</tt> from
|
|
a host called orchid. It has a single printer
|
|
attached to its first parallel port, a Hewlett
|
|
Packard LaserJet 3Si named <tt/teak/. It's
|
|
using the above script as its text filter:
|
|
<code>
|
|
#
|
|
# /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:
|
|
</code>
|
|
</itemize>
|
|
|
|
<tag/It overprinted each line./
|
|
|
|
The printer never advanced a line. All of the lines
|
|
of text were printed on top of each other on one
|
|
line.
|
|
|
|
This problem is the ``opposite'' of the staircase
|
|
effect, described above, and is much rarer.
|
|
Somewhere, the LF characters that FreeBSD uses to
|
|
end a line are being treated as CR characters to
|
|
return the print location to the left edge of the
|
|
paper, but not also down a line.
|
|
|
|
Use the printer's configuration switches or control
|
|
panel to enforce the following interpretation of LF
|
|
and CR characters:
|
|
<tscreen><verb>
|
|
Printer received CR Printer prints CR
|
|
Printer received LF Printer prints CR + LF
|
|
</verb></tscreen>
|
|
|
|
<tag/The printer lost characters./
|
|
|
|
While printing, the printer didn't print a few
|
|
characters in each line. The problem might've
|
|
gotten worse as the printer ran, losing more and
|
|
more characters.
|
|
|
|
The problem is that the printer can't keep up with
|
|
the speed at which the computer sends data over a
|
|
serial line. (This problem shouldn't occur with
|
|
printers on parallel ports.) There are two ways to
|
|
overcome the problem:
|
|
<itemize>
|
|
<item>If the printer supports XON/XOFF flow
|
|
control, have FreeBSD use it by specifying the
|
|
TANDEM bit in the <tt/fs/ capability.
|
|
|
|
<item>If the printer supports carrier flow
|
|
control, specify the MDMBUF bit in the <tt/fs/
|
|
capability. Make sure the cable connecting the
|
|
printer to the computer is correctly wired for
|
|
carrier flow control.
|
|
|
|
<item>If the printer doesn't support any flow
|
|
control, use some combination of the NLDELAY,
|
|
TBDELAY, CRDELAY, VTDELAY, and BSDELAY bits in
|
|
the <tt/fs/ capability to add appropriate delays
|
|
to the stream of data sent to the printer.
|
|
</itemize>
|
|
|
|
<tag/It printed garbage./
|
|
|
|
The printer printed what appeared to be random
|
|
garbage, but not the desired text.
|
|
|
|
This is usually another symptom of incorrect
|
|
communications parameters with a serial printer.
|
|
Double-check the bps rate in the <tt/br/ capability,
|
|
and the parity bits in the <tt/fs/ and <tt/fc/
|
|
capabilities; make sure the printer is using the
|
|
same settings as specified in the
|
|
<tt>/etc/printcap</tt> file.
|
|
|
|
<tag/Nothing happened./
|
|
|
|
If nothing happened, the problem is probably within
|
|
FreeBSD and not the hardware. Add the log file
|
|
(<tt/lf/) capability to the entry for the printer
|
|
you're debugging in the <tt>/etc/printcap</tt> file.
|
|
For example, here's the entry for <tt/rattan/, with
|
|
the <tt/lf/ capability:
|
|
<tscreen><verb>
|
|
rattan|line|diablo|lp|Diablo 630 Line Printer:\
|
|
:sh:sd=/var/spool/lpd/rattan:\
|
|
:lp=/dev/lpt0:\
|
|
:if=/usr/local/libexec/if-simple:\
|
|
:lf=/var/log/rattan.log
|
|
</verb></tscreen>
|
|
Then, try printing again. Check the log file (in
|
|
our example, <tt>/var/log/rattan.log</tt>) to see
|
|
any error messages that might appear. Based on the
|
|
messages you see, try to correct the problem.
|
|
|
|
If you don't specify a <tt/lf/ capability, LPD uses
|
|
<tt>/dev/console</tt> as a default.
|
|
</descrip>
|
|
|
|
<sect><heading>Using Printers<label id="printing:using"></heading>
|
|
|
|
<p> This section tells you how to use printers you've setup with
|
|
FreeBSD. Here's an overview of the user-level commands:
|
|
<descrip>
|
|
<tag/<tt/lpr//
|
|
Print jobs
|
|
|
|
<tag/<tt/lpq//
|
|
Check printer queues
|
|
|
|
<tag/<tt/lprm//
|
|
Remove jobs from a printer's queue
|
|
|
|
</descrip>
|
|
|
|
There's also an administrative command, <tt/lpc/, described in
|
|
the section <ref id="printing:lpc" name="Administrating the
|
|
LPD Spooler">, used to control printers and their queues.
|
|
|
|
All three of the commands <tt/lpr/, <tt/lprm/, and <tt/lpq/
|
|
accept an option ``<tt/-P/ <it/printer-name/'' to specify on
|
|
which printer/queue to operate, as listed in the
|
|
<tt>/etc/printcap</tt> file. This enables you to submit,
|
|
remove, and check on jobs for various printers. If you don't
|
|
use the <tt/-P/ option, then these commands use the printer
|
|
specified in the PRINTER environment variable. Finally, if
|
|
you don't have a PRINTER environment variable, these commands
|
|
default to the printer named <tt/lp/.
|
|
|
|
Hereafter, the terminology <em/default printer/ means the
|
|
printer named in the PRINTER environment variable, or the
|
|
printer named <tt/lp/ when there's no PRINTER environment
|
|
variable.
|
|
|
|
<sect1><heading>Printing Jobs<label id="printing:lpr"></heading>
|
|
<p>
|
|
|
|
To print files, type
|
|
<tscreen>
|
|
<tt>lpr <it/filename.../</tt>
|
|
</tscreen>
|
|
This prints each of the listed files to the default printer.
|
|
If you list no files, <tt/lpr/ reads data to print from
|
|
standard input. For example, this command prints some
|
|
important system files:
|
|
<tscreen><verb>
|
|
lpr /etc/host.conf /etc/hosts.equiv
|
|
</verb></tscreen>
|
|
To select a specific printer, type
|
|
<tscreen>
|
|
<tt>lpr -P <it/printer-name/ <it/filename.../</tt>
|
|
</tscreen>
|
|
This example prints a long listing of the current directory
|
|
to the printer named <tt/rattan/:
|
|
<tscreen><verb>
|
|
ls -l | lpr -P rattan
|
|
</verb></tscreen>
|
|
Because no files were listed for the <tt/lpr/ command,
|
|
<tt/lpr/ read the data to print from standard input, which
|
|
was the output of the <tt/ls -l/ command.
|
|
|
|
The <tt/lpr/ command can also accept a wide variety of
|
|
options to control formatting, apply file conversions,
|
|
generate multiple copies, and so forth. For more
|
|
information, see the section <ref id="printing:lpr:options"
|
|
name="Printing Options">.
|
|
|
|
<sect1><heading>Checking Jobs<label id="printing:lpq"></heading>
|
|
|
|
<p> When you print with <tt/lpr/, the data you wish to print
|
|
is put together in a package called a <em/print job/, which
|
|
is sent to the LPD spooling system. Each printer has a
|
|
queue of jobs, and your job waits in that queue along with
|
|
other jobs from yourself and from other users. The printer
|
|
prints those jobs in a first-come, first-served order.
|
|
|
|
To display the queue for the default printer, type <tt/lpq/.
|
|
For a specific printer, use the <tt/-P/ option. For
|
|
example, the command
|
|
<tscreen><verb>
|
|
lpq -P bamboo
|
|
</verb></tscreen>
|
|
shows the queue for the printer named <tt/bamboo/. Here's
|
|
an example of the output of the <tt/lpq/ command:
|
|
<tscreen><verb>
|
|
bamboo is ready and printing
|
|
Rank Owner Job Files Total Size
|
|
active kelly 9 /etc/host.conf, /etc/hosts.equiv 88 bytes
|
|
2nd kelly 10 (standard input) 1635 bytes
|
|
3rd mary 11 ... 78519 bytes
|
|
</verb></tscreen>
|
|
This shows three jobs in the queue for <tt/bamboo/. The
|
|
first job, submitted by user kelly, got assigned <em/job
|
|
number/ 9. Every job for a printer gets a unique job
|
|
number. Most of the time you can ignore the job number, but
|
|
you'll need it if you want to cancel the job; see section
|
|
<ref id="printing:lprm" name="Removing Jobs"> for details.
|
|
|
|
Job number nine consists of two files; multiple files given
|
|
on the <tt/lpr/ command line are treated as part of a single
|
|
job. It's the currently active job (note the word
|
|
<tt/active/ under the ``Rank'' column), which means the
|
|
printer should be currently printing that job. The second
|
|
job consists of data passed as the standard input to the
|
|
<tt/lpr/ command. The third job came from user mary; it's a
|
|
much larger job. The pathname of the files she's trying to
|
|
print is too long to fit, so the <tt/lpq/ command just shows
|
|
three dots.
|
|
|
|
The very first line of the output from <tt/lpq/ is also
|
|
useful: it tells what the printer is currently doing (or at
|
|
least what LPD thinks the printer is doing).
|
|
|
|
The <tt/lpq/ command also support a <tt/-l/ option to
|
|
generate a detailed long listing. Here's an example of
|
|
<tt/lpq -l/:
|
|
<tscreen><verb>
|
|
waiting for bamboo to become ready (offline ?)
|
|
|
|
kelly: 1st [job 009rose]
|
|
/etc/host.conf 73 bytes
|
|
/etc/hosts.equiv 15 bytes
|
|
|
|
kelly: 2nd [job 010rose]
|
|
(standard input) 1635 bytes
|
|
|
|
mary: 3rd [job 011rose]
|
|
/home/orchid/mary/research/venus/alpha-regio/mapping 78519 bytes
|
|
</verb></tscreen>
|
|
|
|
<sect1><heading>Removing Jobs<label
|
|
id="printing:lprm"></heading>
|
|
|
|
<p> If you change your mind about printing a job, you can
|
|
remove the job from the queue with the <tt/lprm/ command.
|
|
Often, you can even use <tt/lprm/ to remove an active job,
|
|
but some or all of the job might still get printed.
|
|
|
|
To remove a job from the default printer, first use <tt/lpq/
|
|
to find the job number. Then type
|
|
<tscreen>
|
|
<tt/lprm <it/job-number//
|
|
</tscreen>
|
|
To remove the job from a specific printer, add the <tt/-P/
|
|
option. The following command removes job number 10 from
|
|
the queue for the printer <tt/bamboo/:
|
|
<tscreen><verb>
|
|
lprm -P bamboo 10
|
|
</verb></tscreen>
|
|
The <tt/lprm/ command has a few shortcuts:
|
|
<descrip>
|
|
<tag/lprm -/
|
|
|
|
Removes all jobs (for the default printer) belonging to
|
|
you.
|
|
|
|
<tag/lprm <it/user//
|
|
|
|
Removes all jobs (for the default printer) belonging to
|
|
<it/user/. The superuser can remove other users' jobs;
|
|
you can remove only your own jobs.
|
|
|
|
<tag/lprm/
|
|
|
|
With no job number, user name, or ``<tt/-/'' appearing
|
|
on the command line, <tt/lprm/ removes the currently
|
|
active job on the default printer, if it belongs to
|
|
you. The superuser can remove any active job.
|
|
</descrip>
|
|
|
|
Just use the <tt/-P/ option with the above shortcuts to
|
|
operate on a specific printer instead of the default. For
|
|
example, the following command removes all jobs for the
|
|
current user in the queue for the printer named <tt/rattan/:
|
|
|
|
<tscreen><verb>
|
|
lprm -P rattan -
|
|
</verb></tscreen>
|
|
|
|
<em/Note:/ If you're working in a networked environment,
|
|
<tt/lprm/ will let you remove jobs only from the host from
|
|
which the jobs were submitted, even if the same printer is
|
|
available from other hosts. The following command sequence
|
|
demonstrates this:
|
|
<code>
|
|
rose% lpr -P rattan myfile
|
|
rose% rlogin orchid
|
|
orchid% lpq -P rattan
|
|
Rank Owner Job Files Total Size
|
|
active seeyan 12 ... 49123 bytes
|
|
2nd kelly 13 myfile 12 bytes
|
|
orchid% lprm -P rattan 13
|
|
rose: Permission denied
|
|
orchid% logout
|
|
rose% lprm -P rattan 13
|
|
dfA013rose dequeued
|
|
cfA013rose dequeued
|
|
rose%
|
|
</code>
|
|
|
|
<sect1><heading>Beyond Plain Text: Printing Options<label
|
|
id="printing:lpr:options"></heading>
|
|
|
|
<p> The <tt/lpr/ command supports a number of options that
|
|
control formatting text, converting graphic and other file
|
|
formats, producing multiple copies, handling of the job, and
|
|
more. This section describes the options.
|
|
|
|
<sect2><heading>Formatting and Conversion Options<label
|
|
id="printing:lpr:options:format"></heading>
|
|
|
|
<p> The following <tt/lpr/ options control formatting of the
|
|
files in the job. Use these options if the job doesn't
|
|
contain plain text or if you want plain text formatted
|
|
through the <tt/pr/ utility.
|
|
|
|
For example, the following command prints a DVI file (from
|
|
the TeX typesetting system) named <tt/fish-report.dvi/
|
|
to the printer named <tt/bamboo/:
|
|
<tscreen><verb>
|
|
lpr -P bamboo -d fish-report.dvi
|
|
</verb></tscreen>
|
|
These options apply to every file in the job, so you can't
|
|
mix (say) DVI and ditroff files together in a job.
|
|
Instead, submit the files as separate jobs, using a
|
|
different conversion option for each job.
|
|
|
|
<em/Note:/ All of these options except <tt/-p/ and <tt/-T/
|
|
require conversion filters installed for the destination
|
|
printer. For example, the <tt/-d/ option requires the DVI
|
|
conversion filter. Section <ref
|
|
id="printing:advanced:convfilters" name="Conversion
|
|
Filters"> gives details.
|
|
|
|
<descrip>
|
|
<tag/<tt/-c// Print cifplot files.
|
|
|
|
<tag/<tt/-d// Print DVI files.
|
|
|
|
<tag/<tt/-f// Print FORTRAN text files.
|
|
|
|
<tag/<tt/-g// Print plot data.
|
|
|
|
<tag/<tt/-i <it/number///
|
|
|
|
Indent the output by <it/number/ columns; if you omit
|
|
<it/number/, indent by 8 columns. This option works
|
|
only with certain conversion filters.
|
|
|
|
<em/Note:/ Don't put any space between the <tt/-i/ and
|
|
the number.
|
|
|
|
<tag/<tt/-l//
|
|
|
|
Print literal text data, including control characters.
|
|
|
|
<tag/<tt/-n// Print ditroff (device indepdendent troff) data.
|
|
|
|
<tag/-p/
|
|
|
|
Format plain text with <tt/pr/ before printing. See
|
|
pr(1) for more information.
|
|
|
|
<tag/<tt/-T <it/title///
|
|
|
|
Use <it/title/ on the <tt/pr/ header instead of the
|
|
file name. This option has effect only when used with
|
|
the <tt/-p/ option.
|
|
|
|
<tag/<tt/-t// Print troff data.
|
|
|
|
<tag/<tt/-v// Print raster data.
|
|
|
|
</descrip>
|
|
|
|
Here's an example: this command prints a nicely
|
|
formatted version of the <tt/ls/ manual page on the
|
|
default printer:
|
|
<tscreen><verb>
|
|
zcat /usr/share/man/man1/ls.1.gz | troff -t -man | lpr -t
|
|
</verb></tscreen>
|
|
The <tt/zcat/ command uncompresses the source of the
|
|
<tt/ls/ manual page and passes it to the <tt/troff/
|
|
command, which formats that source and makes GNU troff
|
|
output and passes it to <tt/lpr/, which submits the job to
|
|
the LPD spooler. Because we used the <tt/-t/ option to
|
|
<tt/lpr/, the spooler will convert the GNU troff output
|
|
into a format the default printer can understand when it
|
|
prints the job.
|
|
|
|
<sect2><heading>Job Handling Options<label
|
|
id="printing:lpr:options:job-handling"></heading>
|
|
|
|
<p> The following options to <tt/lpr/ tell LPD to handle the
|
|
job specially:
|
|
|
|
<descrip>
|
|
<tag/-# <it/copies//
|
|
|
|
Produce a number of <it/copies/ of each file in the
|
|
job instead of just one copy. An administrator may
|
|
disable this option to reduce printer wear-and-tear
|
|
and encourage photocopier usage. See section <ref
|
|
id="printing:advanced:restricting:copies"
|
|
name="Restricting Multiple Copies">.
|
|
|
|
<p> This example prints three copies of <tt/parser.c/
|
|
followed by three copies of <tt/parser.h/ to the
|
|
default printer:
|
|
<tscreen><verb>
|
|
lpr -#3 parser.c parser.h
|
|
</verb></tscreen>
|
|
|
|
<tag/-m/
|
|
|
|
Send mail after completing the print job. With this
|
|
option, the LPD system will send mail to your account
|
|
when it finishes handling your job. In its message,
|
|
it will tell you if the job completed successfully or
|
|
if there was an error, and (often) what the error was.
|
|
|
|
<tag/-s/ Don't copy the files to the spooling directory,
|
|
but make symbolic links to them instead.
|
|
|
|
If you're printing a large job, you probably want to
|
|
use this option. It saves space in the spooling
|
|
directory (your job might overflow the free space on
|
|
the filesystem where the spooling directory resides).
|
|
It saves time as well since LPD won't have to copy
|
|
each and every byte of your job to the spooling
|
|
directory.
|
|
|
|
There is a drawback, though: since LPD will refer to
|
|
the original files directly, you can't modify or
|
|
remove them until they have been printed.
|
|
|
|
<em/Note:/ If you're printing to a remote printer, LPD
|
|
will eventually have to copy files from the local host
|
|
to the remote host, so the <tt/-s/ option will save
|
|
space only on the local spooling directory, not the
|
|
remote. It's still useful, though.
|
|
|
|
<tag/-r/
|
|
|
|
Remove the files in the job after copying them to the
|
|
spooling directory, or after printing them with the
|
|
<tt/-s/ option. Be careful with this option!
|
|
|
|
</descrip>
|
|
|
|
<sect2><heading>Header Page Options<label
|
|
id="printing:lpr:options:misc"></heading>
|
|
|
|
<p> These options to <tt/lpr/ adjust the text that normally
|
|
appears on a job's header page. If header pages are
|
|
suppressed for the destination printer, these options have
|
|
no effect. See section <ref name="Header Pages"
|
|
id="printing:advanced:header-pages"> for information about
|
|
setting up header pages.
|
|
|
|
<descrip>
|
|
<tag/-C <it/text//
|
|
|
|
Replace the hostname on the header page with
|
|
<it/text/. The hostname is normally the name of the
|
|
host from which the job was submitted.
|
|
|
|
<tag/-J <it/text//
|
|
|
|
Replace the job name on the header page with
|
|
<it/text/. The job name is normally the name of the
|
|
first file of the job, or ``stdin'' if you're printing
|
|
standard input.
|
|
|
|
<tag/-h/
|
|
|
|
Do not print any header page. <em/Note:/ At some
|
|
sites, this option may have no effect due to the way
|
|
header pages are generated. See <ref name="Header
|
|
Pages" id="printing:advanced:header-pages"> for
|
|
details.
|
|
|
|
</descrip>
|
|
|
|
<sect1><heading>Administrating Printers<label
|
|
id="printing:lpc"></heading>
|
|
|
|
<p> As an administrator for your printers, you've had to
|
|
install, set up, and test them. Using the <tt/lpc/ command,
|
|
you can interact with your printers in yet more ways. With
|
|
<tt/lpc/, you can
|
|
|
|
<itemize>
|
|
<item>Start and stop the printers
|
|
|
|
<item>Enable and disable their queues
|
|
|
|
<item>Rearrange the order of the jobs in each queue.
|
|
</itemize>
|
|
|
|
First, a note about terminology: if a printer is
|
|
<em/stopped/, it won't print anything in its queue. Users
|
|
can still submit jobs, which will wait in the queue until
|
|
the printer is <em/started/ or the queue is cleared.
|
|
|
|
If a queue is <em/disabled/, no user (except root) can
|
|
submit jobs for the printer. An <em/enabled/ queue allows
|
|
jobs to be submitted. A printer can be <em/started/ for a
|
|
disabled queue, in which case it'll continue to print jobs
|
|
in the queue until the queue is empty.
|
|
|
|
In general, you have to have root privileges to use the
|
|
<tt/lpc/ command. Ordinary users can use the <tt/lpc/
|
|
command to get printer status and to restart a hung printer
|
|
only.
|
|
|
|
Here is a summary of the <tt/lpc/ commands. Most of the
|
|
commands takes a <it/printer-name/ argument to tell on which
|
|
printer to operate. You can use <tt/all/ for the
|
|
<it/printer-name/ to mean all printers listed in
|
|
<tt>/etc/printcap</tt>.
|
|
|
|
<descrip>
|
|
<tag/<tt/abort <it/printer-name///
|
|
|
|
Cancel the current job and stop the printer. Users can
|
|
still submit jobs if the queue's enabled.
|
|
|
|
<tag/<tt/clean <it/printer-name///
|
|
|
|
Remove old files from the printer's spooling directory.
|
|
Occasionally, the files that make up a job aren't
|
|
properly removed by LPD, particularly if there have been
|
|
errors during printing or a lot of administrative
|
|
activity. This command finds files that don't belong in
|
|
the spooling directory and removes them.
|
|
|
|
<tag/<tt/disable <it/printer-name///
|
|
|
|
Disable queuing of new jobs. If the printer's started,
|
|
it will continue to print any jobs remaining in the
|
|
queue. The superuser (root) can always submit jobs,
|
|
even to a disabled queue.
|
|
|
|
This command is useful while you're testing a new
|
|
printer or filter installation: disable the queue and
|
|
submit jobs as root. Other users won't be able to
|
|
submit jobs until you complete your testing and reenable
|
|
the queue with the <tt/enable/ command.
|
|
|
|
<tag/<tt/down <it/printer-name/ <it/message...///
|
|
|
|
Take a printer down. Equivalent to <tt/disable/
|
|
followed by <tt/stop/. The <it/message/ appears as the
|
|
printer's status whenever a user checks the printer's
|
|
queue with <tt/lpq/ or status with <tt/lpc status/.
|
|
|
|
<tag/<tt/enable <it/printer-name///
|
|
|
|
Enable the queue for a printer. Users can submit jobs
|
|
but the printer won't print anything until it's started.
|
|
|
|
<tag/<tt/help <it/command-name///
|
|
|
|
Print help on the command <it/command-name/. With no
|
|
<it/command-name/, print a summary of the commands
|
|
available.
|
|
|
|
<tag/<tt/restart <it/printer-name///
|
|
|
|
Start the printer. Ordinary users can use this command
|
|
if some extraordinary circumstance hangs LPD, but they
|
|
can't start a printer stopped with either the <tt/stop/
|
|
or <tt/down/ commands. The <tt/restart/ command is
|
|
equivalent to <tt/abort/ followed by <tt/start/.
|
|
|
|
<tag/<tt/start <it/printer-name///
|
|
|
|
Start the printer. The printer will print jobs in its
|
|
queue.
|
|
|
|
<tag/<tt/stop <it/printer-name///
|
|
|
|
Stop the printer. The printer will finish the current
|
|
job and won't print anything else in its queue. Even
|
|
though the printer is stopped, users can still submit
|
|
jobs to an enabled queue.
|
|
|
|
<tag/<tt/topq <it/printer-name/ <it/job-or-username...///
|
|
|
|
Rearrange the queue for <it/printer-name/ by placing the
|
|
jobs with the listed <it/job/ numbers or the jobs
|
|
belonging to <it/username/ at the top of the queue. For
|
|
this command, you can't use <tt/all/ as the
|
|
<it/printer-name/.
|
|
|
|
<tag/<tt/up <it/printer-name///
|
|
|
|
Bring a printer up; the opposite of the <tt/down/
|
|
command. Equivalent to <tt/start/ followed by
|
|
<tt/enable/.
|
|
|
|
</descrip>
|
|
|
|
<tt/lpc/ accepts the above commands on the command line. If
|
|
you don't enter any commands, <tt/lpc/ enters an interactive
|
|
mode, where you can enter commands until you type <tt/exit/,
|
|
<tt/quit/, or end-of-file.
|
|
|
|
<sect><heading>Advanced Printer Setup<label
|
|
id="printing:advanced"></heading>
|
|
|
|
<p> This section describes filters for printing specially
|
|
formatted files, header pages, printing across networks, and
|
|
restricting and accounting for printer usage.
|
|
|
|
<sect1><heading>Filters<label
|
|
id="printing:advanced:filter-intro"></heading>
|
|
|
|
<p> Although LPD handles network protocols, queuing, access
|
|
control, and other aspects of printing, most of the
|
|
<em/real/ work happens in the <em/filters/. Filters are
|
|
programs that communicate with the printer and handle its
|
|
device dependencies and special requirements. In the simple
|
|
printer setup, we installed a plain text filter---an
|
|
extremely simple one that should work with most printers
|
|
(section <ref id="printing:textfilter" name="Installing the
|
|
Text Filter">).
|
|
|
|
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 <em/you/ have to provide
|
|
filters yourself. The good news is that many are generally
|
|
available; when they're not, they're usually easy to write.
|
|
|
|
Also, FreeBSD comes with one, <tt>/usr/libexec/lpr/lpf</tt>,
|
|
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:
|
|
|
|
<itemize>
|
|
<item>Section <ref id="printing:advanced:filters"
|
|
name="How Fitlers Work">, tries to give an overview of a
|
|
filter's role in the printing process. You should read
|
|
this section to get an understanding of what's happening
|
|
``under the hood'' when LPD uses filters. This
|
|
knowledge could help you anticipate and debug problems
|
|
you might encounter as you install more and more filters
|
|
on each of your printers.
|
|
|
|
<item>LPD expects every printer to be able to print plain
|
|
text by default. This presents a problem for PostScript
|
|
(or other language-based printers) which can't directly
|
|
print plain text. Section <ref
|
|
id="printing:advanced:if-conversion" name="Accomodating
|
|
Plain Text Jobs on PostScript Printers"> tells you what
|
|
you should do to overcome this problem. I recommend
|
|
reading this section if you have a PostScript printer.
|
|
|
|
<item>PostScript is a popular output format for many
|
|
programs. Even some people (myself included) write
|
|
PostScript code directly. But PostScript printers are
|
|
expensive. Section <ref id="printing:advanced:ps"
|
|
name="Simulating PostScript on Non-PostScript Printers">
|
|
tells how you can further modify a printer's text filter
|
|
to accept and print PostScript data on a
|
|
<em/non-PostScript/ printer. I recommend reading this
|
|
section if you don't have a PostScript printer.
|
|
|
|
<item>Section <ref id="printing:advanced:convfilters"
|
|
name="Conversion Filters"> tells about a way you can
|
|
automate the conversion of specific file formats, such
|
|
as graphic or typesetting data, into formats your
|
|
printer can understand. After reading this section,
|
|
you should be able to set up your printers such that
|
|
users can type <tt/lpr -t/ to print troff data, or
|
|
<tt/lpr -d/ to print TeX DVI data, or <tt/lpr -v/ to
|
|
print raster image data, and so forth. I recommend
|
|
reading this section.
|
|
|
|
<item>Section <ref id="printing:advanced:of" name="Output
|
|
Filters"> tells all about a not often used feature of
|
|
LPD: output filters. Unless you're printing header
|
|
pages (see <ref id="printing:advanced:header-pages"
|
|
name="Header Pages">), you can probably skip that
|
|
section altogether.
|
|
|
|
<item>Section <ref id="printing:advanced:lpf" name="lpf:
|
|
a Text Filter"> describes <tt/lpf/, a fairly complete
|
|
if simple text filter for line printers (and laser
|
|
printers that act like line printers) that comes with
|
|
FreeBSD. If you need a quick way to get printer
|
|
accounting working for plain text, or if you have a
|
|
printer which emits smoke when it sees backspace
|
|
characters, you should definitely consider <tt/lpf/.
|
|
</itemize>
|
|
|
|
<sect2><heading>How Filters Work<label
|
|
id="printing:advanced:filters"></heading>
|
|
|
|
<p> 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 <tt/lf/ capability in <tt>/etc/printcap</tt>, or
|
|
<tt>/dev/console</tt> by default).
|
|
|
|
Which filter LPD starts and the filter's arguments depend
|
|
on what's listed in the <tt>/etc/printcap</tt> file and
|
|
what arguments the user specified for the job on the
|
|
<tt/lpr/ command line. For example, if the user typed
|
|
<tt/lpr -t/, LPD would start the troff filter, listed in
|
|
the <tt/tf/ capability for the destination printer. If
|
|
the user wanted to print plain text, it would start the
|
|
<tt/if/ filter (this is mostly true: see <ref
|
|
id="printing:advanced:of" name="Output Filters"> for
|
|
details).
|
|
|
|
There are three kinds filters you can specify in
|
|
<tt>/etc/printcap</tt>:
|
|
<itemize>
|
|
<item>The <em/text filter/, confusingly called the
|
|
<em/input filter/ in LPD documentation, handles
|
|
regular text printing. Think of it as the default
|
|
filter. LPD expects every printer to be able to print
|
|
plain text by default, and it's the text filter's job
|
|
to make sure backspaces, tabs, or other special
|
|
characters don't confuse the printer.
|
|
|
|
If you're in an environment where you have to account
|
|
for printer usage, the text filter must also account
|
|
for pages printed, usually by counting the number of
|
|
lines printed and comparing that to the number of
|
|
lines per page the printer supports.
|
|
|
|
The text filter is started with the following argument
|
|
list:
|
|
<tscreen>
|
|
<tt>[-c] -w<it/width/ -l<it/length/ -i<it/indent/ -n <it/login/ -h <it/host/ <it/acct-file/</tt>
|
|
</tscreen>
|
|
where
|
|
<descrip>
|
|
<tag/<tt/-c//
|
|
|
|
appears if the job's submitted with <tt/lpr -l/
|
|
|
|
<tag/<tt/<it/width///
|
|
|
|
is the value from the <tt/pw/ (page width)
|
|
capability specified in <tt>/etc/printcap</tt>,
|
|
default 132
|
|
|
|
<tag/<tt/<it/length///
|
|
|
|
is the value from the <tt/pl/ (page length)
|
|
capability, default 66
|
|
|
|
<tag/<tt/<it/indent///
|
|
|
|
is the amount of the indentation from <tt/lpr -i/,
|
|
default 0
|
|
|
|
<tag/<tt/<it/login///
|
|
|
|
is the account name of the user printing the file
|
|
|
|
<tag/<tt/<it/host///
|
|
|
|
is the host name from which the job was submitted
|
|
|
|
<tag/<tt/<it/acct-file///
|
|
|
|
is the name of the accounting file from the <tt/af/
|
|
capability.
|
|
|
|
</descrip>
|
|
|
|
<item>A <em/conversion filter/ converts a specific file
|
|
format into one the printer can render onto paper.
|
|
For example, ditroff typesetting data can't be
|
|
directly printed, but you can install a conversion
|
|
filter for ditroff files to convert the ditroff data
|
|
into a form the printer can digest and print. Section
|
|
<ref id="printing:advanced:convfilters"
|
|
name="Conversion Filters"> tells all about them.
|
|
Conversion filters also need to do accounting, if you
|
|
need printer accounting.
|
|
|
|
Conversion filters are started with the following
|
|
arguments:
|
|
<tscreen>
|
|
<tt>-x<it/pixel-width/ -y<it/pixel-height/ -n <it/login/ -h <it/host/ <it/acct-file/</tt>
|
|
</tscreen>
|
|
where <it/pixel-width/ is the value from the <tt/px/
|
|
capability (default 0) and <it/pixel-height/ is the
|
|
value from the <tt/py/ capability (default 0).
|
|
|
|
<item>The <em/output filter/ is used only if there's no
|
|
text filter, or if header pages are enabled. In my
|
|
experience, output filters are rarely used. Section
|
|
<ref id="printing:advanced:of" name="Output Filters">
|
|
describe them. There are only two arguments to an
|
|
output filter:
|
|
<tscreen>
|
|
<tt>-w<it/width/ -l<it/length/</tt>
|
|
</tscreen>
|
|
which are identical to the text filters <tt/-w/ and
|
|
<tt/-l/ arguments.
|
|
</itemize>
|
|
|
|
Filters should also <em/exit/ with the following exit
|
|
status:
|
|
<descrip>
|
|
<tag/exit 0/
|
|
|
|
If the filter printed the file successfully.
|
|
|
|
<tag/exit 1/
|
|
|
|
If the filter failed to print the file but wants LPD
|
|
to try to print the file again. LPD will restart a
|
|
filter if it exits with this status.
|
|
|
|
<tag/exit 2/
|
|
|
|
If the filter failed to print the file and doesn't
|
|
want LPD to try again. LPD will throw out the file.
|
|
</descrip>
|
|
|
|
The text filter that comes with the FreeBSD release,
|
|
<tt>/usr/libexec/lpr/lpf</tt>, takes advantage of the page
|
|
width and length arguments to determine when to send a
|
|
form feed and how to account for printer usage. It uses
|
|
the login, host, and accounting file arguments to make the
|
|
accounting entries.
|
|
|
|
If you're shopping for filters, see if they're
|
|
LPD-compatible. If they are, they must support the
|
|
argument lists described above. If you plan on writing
|
|
filters for general use, then have them support the same
|
|
argument lists and exit codes.
|
|
|
|
<sect2><heading>Accommodating Plain Text Jobs on PostScript Printers
|
|
<label id="printing:advanced:if-conversion"></heading>
|
|
|
|
<p> 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 <tt/%!/ (for
|
|
other printer languages, see your printer documentation).
|
|
If those are the first two characters in the job, we have
|
|
PostScript, and can pass the rest of the job directly. If
|
|
those aren't the first two characters in the file, then
|
|
the filter will convert the text into PostScript and print
|
|
the result.
|
|
|
|
How do we do this?
|
|
|
|
If you've got a serial printer, a great way to do it is to
|
|
install <tt/lprps/. <tt/lprps/ is a PostScript printer
|
|
filter which performs two-way communication with the
|
|
printer. It updates the printer's status file with
|
|
verbose information from the printer, so users and
|
|
administrators can see exactly what the state of the
|
|
printer is (such as ``toner low'' or ``paper jam''). But
|
|
more importantly, it includes a program called <tt/psif/
|
|
which detects whether the incoming job is plain text and
|
|
calls <tt/textps/ (another program that comes with
|
|
<tt/lprps/) to convert it to PostScript. It then uses
|
|
<tt/lprps/ to send the job to the printer.
|
|
|
|
<tt/lprps/ should be part of the FreeBSD ports collection
|
|
(see <ref id="ports" name="The Ports Collection">); if not,
|
|
it should be shortly. You can fetch, build and install it
|
|
yourself, of course. After installing <tt/lprps/, just
|
|
specify the pathname to the <tt/psif/ program that's part
|
|
of <tt/lprps/. If you installed <tt/lprps/ from the ports
|
|
collection, use the following in the serial PostScript
|
|
printer's entry in <tt>/etc/printcap</tt>:
|
|
<tscreen><verb>
|
|
:if=/usr/local/libexec/psif:
|
|
</verb></tscreen>
|
|
You should also specify the <tt/rw/ capability; that tells
|
|
LPD to open the printer in read-write mode.
|
|
|
|
If you have a parralel PostScript printer (and therefore
|
|
can't use two-way communication with the printer, which
|
|
<tt/lprps/ needs), you can use the following shell script
|
|
as the text filter:
|
|
<code>
|
|
#!/bin/sh
|
|
#
|
|
# psif - Print PostScript or plain text on a PostScript printer
|
|
# Script version; NOT the version that comes with lprps
|
|
# Installed in /usr/local/libexec/psif
|
|
#
|
|
|
|
read first_line
|
|
first_two_chars=`expr "$first_line" : '\(..\)'`
|
|
|
|
if [ "$first_two_chars" = "%!" ]; then
|
|
#
|
|
# PostScript job, print it.
|
|
#
|
|
echo $first_line &ero;&ero; cat &ero;&ero; printf "\004" &ero;&ero; exit 0
|
|
exit 2
|
|
else
|
|
#
|
|
# Plain text, convert it, then print it.
|
|
#
|
|
( echo $first_line; cat ) | /usr/local/bin/textps &ero;&ero; printf "\004" &ero;&ero; exit 0
|
|
exit 2
|
|
fi
|
|
</code>
|
|
In the above script, <tt/textps/ is a program we installed
|
|
separately to convert plain text to PostScript. You can
|
|
use any text-to-PostScript program you wish. The FreeBSD
|
|
ports collection (see <ref id="ports" name="The Ports
|
|
Collection">) includes a full featured text-to-PostScript
|
|
program called <tt/a2ps/ that you might want to
|
|
investigate.
|
|
|
|
<sect2><heading>Simulating PostScript on Non-PostScript Printers
|
|
<label id="printing:advanced:ps"></heading>
|
|
|
|
<p> PostScript is the <it/de facto/ standard for high
|
|
quality typesetting and printing. PostScript is, however,
|
|
an <em/expensive/ standard. Thankfully, Alladin
|
|
Enterprises has a free PostScript workalike called
|
|
<it/Ghostscript/ that runs with FreeBSD. Ghostscript can
|
|
read most PostScript files and can render their pages onto
|
|
a variety of devices, including many brands of
|
|
non-PostScript printers. By installing Ghostscript and
|
|
using a special text filter for your printer, you can make
|
|
your non-PostScript printer act like a real PostScript
|
|
printer.
|
|
|
|
Ghostscript should be in the FreeBSD ports collection, if
|
|
you'd like to install it from there. You can fetch,
|
|
build, and install it quite easily yourself, as well.
|
|
|
|
To simulate PostScript, we have the text filter detect if
|
|
it's printing a PostScript file. If it's not, then the
|
|
filter will pass the file directly to the printer;
|
|
otherwise, it will use Ghostscript to first convert the
|
|
file into a format the printer will understand.
|
|
|
|
Here's an example: the following script is a text filter
|
|
for Hewlett Packard DeskJet 500 printers. For other
|
|
printers, substitute the <tt/-sDEVICE/ argument to the
|
|
<tt/gs/ (Ghostscript) command. (Type <tt/gs -h/ to get a
|
|
list of devices the current installation of Ghostscript
|
|
supports.)
|
|
<code>
|
|
#!/bin/sh
|
|
#
|
|
# ifhp - Print Ghostscript-simulated PostScript on a DesJet 500
|
|
# Installed in /usr/local/libexec/hpif
|
|
|
|
#
|
|
# Treat LF as CR+LF:
|
|
#
|
|
printf "\033&ero;k2G" || exit 2
|
|
|
|
#
|
|
# Read first two characters of the file
|
|
#
|
|
read first_line
|
|
first_two_chars=`expr "$first_line" : '\(..\)'`
|
|
|
|
if [ "$first_two_chars" = "%!" ]; then
|
|
#
|
|
# It's PostScript; use Ghostscript to scan-convert and print it
|
|
#
|
|
/usr/local/bin/gs -dSAFER -dNOPAUSE -q -sDEVICE=djet500 -sOutputFile=- - \
|
|
&ero;&ero; exit 0
|
|
|
|
else
|
|
#
|
|
# Plain text or HP/PCL, so just print it directly; print a form
|
|
# at the end to eject the last page.
|
|
#
|
|
echo $first_line &ero;&ero; cat &ero;&ero; printf "\f" &ero;&ero; exit 2
|
|
fi
|
|
|
|
exit 2
|
|
</code>
|
|
Finally, you need to notify LPD of the filter via the
|
|
<tt/if/ capability:
|
|
<tscreen><verb>
|
|
:if=/usr/local/libexec/hpif:
|
|
</verb></tscreen>
|
|
That's it. You can type <tt/lpr plain.text/ and <tt/lpr
|
|
whatever.ps/ and both should print successfully.
|
|
|
|
|
|
<sect2><heading>Conversion Filters<label
|
|
id="printing:advanced:convfilters"></heading>
|
|
|
|
<p> After completing the simple setup described in <ref
|
|
name="Simple Printer Setup" id="printing:simple">, the
|
|
first thing you'll probably want to do is install
|
|
conversion filters for your favorite file formats
|
|
(besides plain ASCII text).
|
|
|
|
<sect3><heading>Why Install Conversion Filters?</heading>
|
|
|
|
<p> 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:
|
|
<tscreen><verb>
|
|
dvips seaweed-analysis.dvi
|
|
lpr seaweed-analysis.ps
|
|
</verb></tscreen>
|
|
By installing a conversion filter for DVI files, we can
|
|
skip the hand conversion step each time by having LPD do
|
|
it for us. Now, each time we get a DVI file, we're just
|
|
one step away from printing it:
|
|
<tscreen><verb>
|
|
lpr -d seaweed-analysis.dvi
|
|
</verb></tscreen>
|
|
We got LPD to do the DVI file conversion for us by
|
|
specifying the <tt/-d/ option. Section <ref
|
|
id="printing:lpr:options:format" name="Formatting and
|
|
Conversion Options"> lists the conversion options.
|
|
|
|
For each of the conversion options you want a printer to
|
|
support, install a <em/conversion filter/ and specify
|
|
its pathname in <tt>/etc/printcap</tt>. A conversion
|
|
filter is like the text filter for the simple printer
|
|
setup (see section <ref id="printing:textfilter"
|
|
name="Installing the Text Filter">) except that instead
|
|
of printing plain text, the filter converts the file
|
|
into a format the printer can understand.
|
|
|
|
<sect3><heading>Which Conversions Filters Should I Install?
|
|
</heading>
|
|
|
|
<p> 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
|
|
<tt>/etc/printcap</tt> file, and how to invoke them with
|
|
the <tt/lpr/ command:
|
|
<code>
|
|
/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
|
|
</code>
|
|
|
|
In our example, using <tt/lpr -d/ means the printer
|
|
needs a <tt/df/ capability in its entry in
|
|
<tt>/etc/printcap</tt>.
|
|
|
|
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 <tt/gf/
|
|
capability and then educate your users that <tt/lpr -g/
|
|
mean ``print Printerleaf files.''
|
|
|
|
<sect3><heading>Installing Conversion Filters</heading>
|
|
|
|
<p> Since conversion filters are programs you install
|
|
outside of the base FreeBSD installation, they should
|
|
probably go under <tt>/usr/local</tt>. The directory
|
|
<tt>/usr/local/libexec</tt> 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 <tt>/etc/printcap</tt>.
|
|
|
|
In our example, we'll add the DVI conversion filter to
|
|
the entry for the printer named <tt/bamboo/. Here's the
|
|
example <tt>/etc/printcap</tt> file again, with the new
|
|
<tt/df/ capability for the printer <tt/bamboo/
|
|
<code>
|
|
#
|
|
# /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:
|
|
</code>
|
|
The DVI filter is a shell script named
|
|
<tt>/usr/local/libexec/psdf</tt>. Here's that script:
|
|
<code>
|
|
#!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 "$@"
|
|
</code>
|
|
This script runs <tt/dvips/ in filter mode (the <tt/-f/
|
|
argument) on standard input, which is the job to print.
|
|
It then starts the PostScript printer filter <tt/lprps/
|
|
(see section <ref id="printing:advanced:if-conversion"
|
|
name="Accomodating Plain Text Jobs on PostScript
|
|
Printers">) with the arguments LPD passed to this script.
|
|
<tt/lprps/ will use those arguments to account for the
|
|
pages printed.
|
|
|
|
<sect3><heading>More Conversion Filter Examples</heading>
|
|
|
|
<p> 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:
|
|
<code>
|
|
#!/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
|
|
</code>
|
|
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 <tt>/etc/printcap</tt> file with an entry for
|
|
a printer using the above filter:
|
|
<code>
|
|
#
|
|
# /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:
|
|
</code>
|
|
|
|
The following script is a conversion filter for troff
|
|
data from the groff typesetting system for the
|
|
PostScript printer named <tt/bamboo/:
|
|
<code>
|
|
#!/bin/sh
|
|
#
|
|
# pstf - Convert groff's troff data into PS, then print.
|
|
# Installed in /usr/local/libexec/pstf
|
|
#
|
|
exec grops | /usr/local/libexec/lprps "$@"
|
|
</code>
|
|
The above script makes use of <tt/lprps/ again to handle
|
|
the communication with the printer. If the printer were
|
|
on a parallel port, we'd use this script instead:
|
|
<code>
|
|
#!/bin/sh
|
|
#
|
|
# pstf - Convert groff's troff data into PS, then print.
|
|
# Installed in /usr/local/libexec/pstf
|
|
#
|
|
exec grops
|
|
</code>
|
|
That's it. Here's the entry we need to add to
|
|
<tt>/etc/printcap</tt> to enable the filter:
|
|
<tscreen><verb>
|
|
:tf=/usr/local/libexec/pstf:
|
|
</verb></tscreen>
|
|
|
|
Here's an example that might make old hands at FORTRAN
|
|
blush. It's a FORTRAN-text filter for any printer that
|
|
can directly print plain text. We'll install it for the
|
|
printer <tt/teak/:
|
|
<code>
|
|
#!/bin/sh
|
|
#
|
|
# hprf - FORTRAN text filter for LaserJet 3si:
|
|
# Installed in /usr/local/libexec/hprf
|
|
#
|
|
|
|
printf "\033&ero;k2G" &ero;&ero; fpr &ero;&ero; printf "\f" &ero;&ero; exit 0
|
|
exit 2
|
|
</code>
|
|
And we'll add this line to the <tt>/etc/printcap</tt>
|
|
for the printer <tt/teak/ to enable this filter:
|
|
<tscreen><verb>
|
|
:rf=/usr/local/libexec/hprf:
|
|
</verb></tscreen>
|
|
|
|
Here's one final, somewhat complex example. We'll add a
|
|
DVI filter to the LaserJet printer <tt/teak/ introduced
|
|
earlier. First, the easy part: updating
|
|
<tt>/etc/printcap</tt> with the location of the DVI
|
|
filter:
|
|
<tscreen><verb>
|
|
:df=/usr/local/libexec/hpdf:
|
|
</verb></tscreen>
|
|
|
|
Now, for the hard part: making the filter. For that, we
|
|
need a DVI-to-LaserJet/PCL conversion program. The
|
|
FreeBSD ports collection (see <ref id="ports" name="The
|
|
Ports Collection">) has one: <tt/dvi2xx/ is the name of
|
|
the package. Installing this package gives us the
|
|
program we need, <tt/dvilj2p/, which converts DVI into
|
|
LaserJet IIp, LaserJet III, and LaserJet 2000 compatible
|
|
codes.
|
|
|
|
<tt/dvilj2p/ makes the filter <tt/hpdf/ quite complex
|
|
since <tt/dvilj2p/ can't read from standard input. It
|
|
wants to work with a filename. What's worse, the
|
|
filename has to end in <tt/.dvi/ so using
|
|
<tt>/dev/fd/0</tt> for standard input is problematic.
|
|
We can get around that problem by linking (symbolically)
|
|
a temporary file name (one that ends in <tt/.dvi/) to
|
|
<tt>/dev/fd/0</tt>, thereby forcing <tt/dvilj2p/ to read
|
|
from standard input.
|
|
|
|
The only other fly in the ointment is the fact that we
|
|
can't use /tmp for the temporary link. Symbolic links
|
|
are owned by user and group <tt/bin/. The filter runs
|
|
as user <tt/daemon/. And the <tt>/tmp</tt> directory
|
|
has the sticky bit set. The filter can create the link,
|
|
but it won't be able clean up when done and remove it
|
|
since the link will belong to a different user.
|
|
|
|
Instead, the filter will make the symbolic link in the
|
|
current working directory, which is the spooling
|
|
directory (specified by the <tt/sd/ capability in
|
|
<tt>/etc/printcap</tt>). This is a perfect place for
|
|
filters to do their work, especially since there's
|
|
(sometimes) more free disk space in the spooling directory
|
|
than under <tt>/tmp</tt>.
|
|
|
|
Here, finally, is the filter:
|
|
<code>
|
|
#!/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
|
|
</code>
|
|
|
|
<sect3><heading>Automated Conversion: An Alternative To Conversion Filters
|
|
<label id="printing:advanced:autoconv"></heading>
|
|
|
|
<p> All these conversion filters accomplish a lot for your
|
|
printing environment, but at the cost forcing the user
|
|
to specify (on the <tt/lpr/ command line) which one to
|
|
use. If your users aren't particularly computer
|
|
literate, having to specify a filter option will become
|
|
annoying. What's worse, though, is that an incorrectly
|
|
specified filter option may run a filter on the wrong
|
|
type of file and cause your printer to spew out hundreds
|
|
of sheets of paper.
|
|
|
|
Rather than install conversion filters at all, you might
|
|
want to try having the text filter (since it's the
|
|
default filter) detect the type of file it's asked to
|
|
print and then automatically run the right conversion
|
|
filter. Tools such as <tt/file/ can be of help here.
|
|
Of course, it'll be hard to determine the differences
|
|
between <em/some/ file types---and, of course, you can
|
|
still provide conversion filters just for them.
|
|
|
|
The FreeBSD ports collection has a text filter that
|
|
performs automatic conversion called <tt/apsfilter/. It
|
|
can detect plain text, PostScript, and DVI files, run
|
|
the proper conversions, and print.
|
|
|
|
<sect2><heading>Output Filters<label
|
|
id="printing:advanced:of"></heading>
|
|
|
|
<p> 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
|
|
<itemize>
|
|
<item>LPD starts an output filter once for the entire
|
|
job instead of once for each file in the job.
|
|
|
|
<item>LPD doesn't make any provision to identify the
|
|
start or the end of files within the job for the
|
|
output filter.
|
|
|
|
<item>LPD doesn't pass the user's login or host to
|
|
the filter, so it's not intended to do accounting. In
|
|
fact, it gets only two arguments:
|
|
<tscreen>
|
|
<tt>-w<it/width/ -l<it/length/</tt>
|
|
</tscreen>
|
|
where <it/width/ is from the <tt/pw/ capability and
|
|
<it/length/ is from the <tt/pl/ capability for the
|
|
printer in question.
|
|
</itemize>
|
|
|
|
Don't be seduced by an output filter's simplicity. If
|
|
you'd like each file in a job to start on a different page
|
|
an output filter <em/won't work/. Use a text filter (also
|
|
known as an input filter); see section <ref
|
|
id="printing:textfilter" name="Installing the Text
|
|
Filter">. Furthermore, an output filter is actually
|
|
<em/more complex/ in that it has to examine the byte
|
|
stream being sent to it for special flag characters and
|
|
must send signals to itself on behalf of LPD.
|
|
|
|
However, an output filter is <em/necessary/ if you want
|
|
header pages and need to send escape sequences or other
|
|
initialization strings to be able to print the header
|
|
page. (But it's also <em/futile/ if you want to charge
|
|
header pages to the requesting user's account, since LPD
|
|
doesn't give any user or host information to the output
|
|
filter.)
|
|
|
|
On a single printer, LPD allows both an output filter and
|
|
text or other filters. In such cases, LPD will start the
|
|
output filter to print the header page (see section <ref
|
|
id="printing:advanced:header-pages" name="Header Pages">)
|
|
only. LPD then expects the output filter to <em/stop
|
|
itself/ by sending two bytes to the filter: ASCII 031
|
|
followed by ASCII 001. When an output filter sees these
|
|
two bytes (031, 001), it should stop by sending SIGSTOP to
|
|
itself. When LPD's done running other filters, it'll
|
|
restart the output filter by sending SIGCONT to it.
|
|
|
|
If there's an output filter but <em/no/ text filter and
|
|
LPD is working on a plain text job, LPD uses the output
|
|
filter to do the job. As stated before, the output filter
|
|
will print each file of the job in sequence with no
|
|
intervening form feeds or other paper advancement, and
|
|
this is probably <em/not/ what you want. In almost all
|
|
cases, you need a text filter.
|
|
|
|
The program <tt/lpf/, whch we introduced earlier as a text
|
|
filter, can also run as an output filter. If you need a
|
|
quick-and-dirty output filter but don't want to write the
|
|
byte detection and signal sending code, try <tt/lpf/. You
|
|
can also wrap <tt/lpf/ in a shell script to handle any
|
|
intialization codes the printer might require.
|
|
|
|
<sect2><heading><tt/lpf/: a Text Filter<label
|
|
id="printing:advanced:lpf"></heading>
|
|
|
|
<p> The program <tt>/usr/libexec/lpr/lpf</tt> that comes
|
|
with FreeBSD binary distribution is a text filter (input
|
|
filter) that can indent output (job submitted with <tt/lpr
|
|
-i/), allow literal characters to pass (job submitted with
|
|
<tt/lpr -l/), adjust the printing position for backspaces
|
|
and tabs in the job, and account for pages printed. It
|
|
can also act like an output filter.
|
|
|
|
<tt/lpf/ is suitable for many printing environments. And
|
|
although it has no capability to send initialization
|
|
sequences to a printer, it's easy to write a shell script
|
|
to do the needed initialization and then execute <tt/lpf/.
|
|
|
|
In order for <tt/lpf/ to do page accounting correctly, it
|
|
needs correct values filled in for the <tt/pw/ and <tt/pl/
|
|
capabilities in the <tt>/etc/printcap</tt> 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 <ref
|
|
id="printing:advanced:acct" name="Accounting for Printer
|
|
Usage">.
|
|
|
|
<sect1><heading>Header Pages<label
|
|
id="printing:advanced:header-pages"></heading>
|
|
|
|
<p> If you've got <em/lots/ of users, all of them using
|
|
various printers, then you probably want to consider
|
|
<em/header pages/ as a necessary evil.
|
|
|
|
Header pages, also known as <em/banner/ or <em/burst pages/
|
|
identify to whom jobs belong after they're printed. They're
|
|
usually printed in large, bold letters, perhaps with
|
|
decorative borders, so that in a stack of printouts they
|
|
stand out from the real documents that comprise users' jobs.
|
|
They enable users to locate their jobs quickly. The obvious
|
|
drawback to a header page is that it's yet one more sheet
|
|
that has to be printed for every job, their ephemeral
|
|
usefulness lasting not more than a few minutes, ultimately
|
|
finding themselves in a recycling bin or rubbish heap.
|
|
(Note that header pages go with each job, not each file in a
|
|
job, so the paper waste might not be that bad.)
|
|
|
|
The LPD system can provide header pages automatically for
|
|
your printouts <em/if/ your printer can directly print plain
|
|
text. If you've got a PostScript printer, you'll need an
|
|
external program to generate the header page; see <ref
|
|
id="printing:advanced:header-pages:ps" name="Header Pages on
|
|
PostScript Printers">.
|
|
|
|
<sect2><heading>Enabling Header Pages<label
|
|
id="printing:advanced:header-pages:enabling"></heading>
|
|
|
|
<p> In the <ref id="printing:simple" name="Simple Printer
|
|
Setup">, we turned off header pages by specifying
|
|
<tt/sh/ (meaning ``suppress header'') in the
|
|
<tt>/etc/printcap</tt> file. To enable header pages for
|
|
a printer, just remove the <tt/sh/ capability.
|
|
|
|
Sounds too easy, right?
|
|
|
|
You're right. You <em/might/ have to provide an output
|
|
filter to send initialization strings to the printer.
|
|
Here's an example output filter for Hewlett Packard
|
|
PCL-compatible printers:
|
|
<code>
|
|
#!/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
|
|
</code>
|
|
Specify the path to the output filter in the <tt/of/
|
|
capability. See <ref id="printing:advanced:of"
|
|
name="Output Filters"> for more information.
|
|
|
|
Here's an example <tt>/etc/printcap</tt> file for the printer
|
|
<tt/teak/ that we introduced earlier; we enabled header
|
|
pages and added the above output filter:
|
|
<code>
|
|
#
|
|
# /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:
|
|
</code>
|
|
Now, when users print jobs to <tt/teak/, they get a header
|
|
page with each job. If users want to spend time searching
|
|
for their printouts, they can suppress header pages by
|
|
submitting the job with <tt/lpr -h/; see <ref
|
|
id="printing:lpr:options:misc" name="Header Page Options">
|
|
for more <tt/lpr/ options.
|
|
|
|
<tt/Note:/ LPD prints a form feed character after the
|
|
header page. If your printer uses a different character
|
|
or sequence of characters to eject a page, specify them
|
|
with the <tt/ff/ capability in <tt>/etc/printcap</tt>.
|
|
|
|
<sect2><heading>Controlling Header Pages<label
|
|
id="printing:advanced:header-pages:controlling"></heading>
|
|
|
|
<p> By enabling header pages, LPD will produce a <em/long
|
|
header/, a full page of large letters identifying the
|
|
user, host, and job. Here's an example (kelly printed
|
|
the job named outline from host rose):
|
|
<tscreen><verb>
|
|
k ll ll
|
|
k l l
|
|
k l l
|
|
k k eeee l l y y
|
|
k k e e l l y y
|
|
k k eeeeee l l y y
|
|
kk k e l l y y
|
|
k k e e l l y yy
|
|
k k eeee lll lll yyy y
|
|
y
|
|
y y
|
|
yyyy
|
|
|
|
|
|
ll
|
|
t l i
|
|
t l
|
|
oooo u u ttttt l ii n nnn eeee
|
|
o o u u t l i nn n e e
|
|
o o u u t l i n n eeeeee
|
|
o o u u t l i n n e
|
|
o o u uu t t l i n n e e
|
|
oooo uuu u tt lll iii n n eeee
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
r rrr oooo ssss eeee
|
|
rr r o o s s e e
|
|
r o o ss eeeeee
|
|
r o o ss e
|
|
r o o s s e e
|
|
r oooo ssss eeee
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Job: outline
|
|
Date: Sun Sep 17 11:04:58 1995
|
|
</verb></tscreen>
|
|
LPD appends a form feed after this text so the job starts
|
|
on a new page (unless you've got <tt/sf/ (suppress form
|
|
feeds) in the destination printer's entry in
|
|
<tt>/etc/printcap</tt>).
|
|
|
|
If you prefer, LPD can make a <em/short header/; specify
|
|
<tt/sb/ (short banner) in the <tt>/etc/printcap</tt> file.
|
|
The header page will look like this:
|
|
<tscreen><verb>
|
|
rose:kelly Job: outline Date: Sun Sep 17 11:07:51 1995
|
|
</verb></tscreen>
|
|
Also by default, LPD prints the header page first, then
|
|
the job. To reverse that, specify <tt/hl/ (header last)
|
|
in <tt>/etc/printcap</tt>.
|
|
|
|
<sect2><heading>Accounting for Header Pages<label
|
|
id="printing:advanced:header-pages:accounting"></heading>
|
|
|
|
<p> Using LPD's built-in header pages enforces a particular
|
|
paradigm when it comes to printer accounting: header pages
|
|
must be <em/free of charge/.
|
|
|
|
Why?
|
|
|
|
Because the output filter is the only external program
|
|
that will have control when the header page is printed
|
|
that could do accounting, and it isn't provided with any
|
|
<em/user or host/ information or an accounting file, so it
|
|
has no idea whom to charge for printer use. It's also not
|
|
enough to just ``add one page'' to the text filter or any
|
|
of the conversion filters (which do have user and host
|
|
information) since users can suppress header pages with
|
|
<tt/lpr -h/. They could still be charged for header pages
|
|
they didn't print. Basically, <tt/lpr -h/ will be the
|
|
preferred option of environmentally-minded users, but you
|
|
can't offer any incentive to use it.
|
|
|
|
It's <em/still not enough/ to have each of the filters
|
|
generate their own header pages (thereby being able to
|
|
charge for them). If users wanted the option of
|
|
suppressing the header pages with <tt/lpr -h/, they will
|
|
still get them and be charged for them since LPD does not
|
|
pass any knowledge of the <tt/-h/ option to any of the
|
|
filters.
|
|
|
|
So, what are your options?
|
|
|
|
You can
|
|
<itemize>
|
|
<item>Accept LPD's paradigm and make header pages free.
|
|
|
|
<item>Install an alternative to LPD, such as LPDng or
|
|
PLP. Section <ref name="Alternatives to the Standard
|
|
Spooler" id="printing:lpd-alternatives"> tells more
|
|
about other spooling software you can substitute for
|
|
LPD.
|
|
|
|
<item>Write a <em/smart/ output filter. Normally, an
|
|
output filter isn't meant to do anything more than
|
|
initialize a printer or do some simple character
|
|
conversion. It's suited for header pages and plain
|
|
text jobs (when there's no text (input) filter).
|
|
|
|
But, if there is a text filter for the plain text
|
|
jobs, then LPD will start the output filter only for
|
|
the header pages. And the output filter can parse the
|
|
header page text that LPD generates to determine what
|
|
user and host to charge for the header page. The only
|
|
other problem with this method is that the output
|
|
filter still doesn't know what accounting file to use
|
|
(it's not passed the name of the file from the <tt/af/
|
|
capability), but if you have a well-known accounting
|
|
file, you can hard-code that into the output filter.
|
|
|
|
To facilitate the parsing step, use the <tt/sh/ (short
|
|
header) capability in <tt>/etc/printcap</tt>.
|
|
|
|
Then again, all that might be too much trouble, and
|
|
users will certainly appreciate the more generous
|
|
system administrator who makes header pages free.
|
|
</itemize>
|
|
|
|
<sect2><heading>Header Pages on PostScript Printers<label
|
|
id="printing:advanced:header-pages:ps"></heading>
|
|
|
|
<p> 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 <tt/lpr -h/.
|
|
|
|
Let's explore this method. The following script takes
|
|
three arguments (user login name, host name, and job name)
|
|
and makes a simple PostScript header page:
|
|
<code>
|
|
#!/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` <user> <host> <job>" 1>&ero;2
|
|
exit 1
|
|
fi
|
|
|
|
#
|
|
# Save these, mostly for readability in the PostScript, below.
|
|
#
|
|
user=$1
|
|
host=$2
|
|
job=$3
|
|
date=`date`
|
|
|
|
#
|
|
# Send the PostScript code to stdout.
|
|
#
|
|
exec cat <<EOF
|
|
%!PS
|
|
|
|
%
|
|
% Make sure we don't interfere with user's job that will follow
|
|
%
|
|
save
|
|
|
|
%
|
|
% Make a thick, unpleasant border around the edge of the paper.
|
|
%
|
|
$border $border moveto
|
|
$page_width $border 2 mul sub 0 rlineto
|
|
0 $page_height $border 2 mul sub rlineto
|
|
currentscreen 3 -1 roll pop 100 3 1 roll setscreen
|
|
$border 2 mul $page_width sub 0 rlineto closepath
|
|
0.8 setgray 10 setlinewidth stroke 0 setgray
|
|
|
|
%
|
|
% Display user's login name, nice and large and prominent
|
|
%
|
|
/Helvetica-Bold findfont 64 scalefont setfont
|
|
$page_width ($user) stringwidth pop sub 2 div $page_height 200 sub moveto
|
|
($user) show
|
|
|
|
%
|
|
% Now show the boring particulars
|
|
%
|
|
/Helvetica findfont 14 scalefont setfont
|
|
/y 200 def
|
|
[ (Job:) (Host:) (Date:) ] {
|
|
200 y moveto show /y y 18 sub def
|
|
} forall
|
|
|
|
/Helvetica-Bold findfont 14 scalefont setfont
|
|
/y 200 def
|
|
[ ($job) ($host) ($date) ] {
|
|
270 y moveto show /y y 18 sub def
|
|
} forall
|
|
|
|
%
|
|
% That's it
|
|
%
|
|
restore
|
|
showpage
|
|
EOF
|
|
</code>
|
|
Now, each of the conversion filters and the text filter
|
|
can call this script to first generate the header page,
|
|
and then print the user's job. Here's the DVI conversion
|
|
filter from earlier in this document, modified to make a
|
|
header page:
|
|
<code>
|
|
#!/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
|
|
</code>
|
|
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 <ref id="printing:advanced:filters" name="How
|
|
Filters Work">).
|
|
|
|
As we've mentioned before, the above scheme, though fairly
|
|
simple, disables the ``suppress header page'' option (the
|
|
<tt/-h/ option) to <tt/lpr/. If users wanted to save a
|
|
tree (or a few pennies, if you charge for header pages),
|
|
they wouldn't be able to do so, since every filter's going
|
|
to print a header page with every job.
|
|
|
|
To allow users to shut off header pages on a per-job
|
|
basis, you'll need to use the trick introduced in section
|
|
<ref id="printing:advanced:header-pages:accounting"
|
|
name="Accounting for Header Pages">: write an output
|
|
filter that parses the LPD-generated header page and
|
|
produces a PostScript version. If the user submits the
|
|
job with <tt/lpr -h/, then LPD won't generate a header
|
|
page, and neither will your output filter. Otherwise,
|
|
your output filter will read the text from LPD and send
|
|
the appropriate header page PostScript code to the
|
|
printer.
|
|
|
|
If you've got a PostScript printer on a serial line, you
|
|
can make use of <tt/lprps/, which comes with an output
|
|
filter, <tt/psof/, which does the above. Note that
|
|
<tt/psof/ doesn't charge for header pages.
|
|
|
|
<sect1><heading>Networked Printing<label
|
|
id="printing:advanced:network-printers"></heading>
|
|
|
|
<p> FreeBSD supports networked printing: sending jobs to
|
|
remote printers. Networked printing generally refers to two
|
|
different things:
|
|
<itemize>
|
|
<item>Accessing a printer attached to a remote host. You
|
|
install a printer that has a conventional serial or
|
|
parallel interface on one host. Then, you set up LPD to
|
|
enable access to the printer from other hosts on the
|
|
network. Section <ref id="printing:advanced:network:rm"
|
|
name="Printers Installed on Remote Hosts"> tells how to
|
|
do this.
|
|
|
|
<item>Accessing a printer attached directly to a network.
|
|
The printer has a network interface in addition (or in
|
|
place of) a more conventional serial or parallel
|
|
interface. Such a printer might work as follows:
|
|
|
|
<itemize>
|
|
<item>It might understand the LPD protocol and can
|
|
even queue jobs from remote hosts. In this case, it
|
|
acts just like a regular host running LPD. Follow
|
|
the same procedure in section <ref
|
|
id="printing:advanced:network:rm" name="Printers
|
|
Installed on Remote Hosts"> to set up such a
|
|
printer.
|
|
|
|
<item>It might support a data stream network
|
|
connection. In this case, you ``attach'' the
|
|
printer to one host on the network by making that
|
|
host responsible for spooling jobs and sending them
|
|
to the printer. Section <ref
|
|
id="printing:advanced:network:net-if" name="Printers
|
|
with Networked Data Stream Interfaces"> gives some
|
|
suggestions on installing such printers.
|
|
</itemize>
|
|
</itemize>
|
|
|
|
<sect2><heading>Printers Installed on Remote Hosts<label
|
|
id="printing:advanced:network:rm"></heading>
|
|
|
|
<p> 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 <em/printer host/, using the
|
|
simple printer setup described in <ref
|
|
id="printing:simple" name="Simple Printer Setup">. Do any
|
|
advanced setup in <ref id="printing:advanced"
|
|
name="Advanced Printer Setup"> 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 <em/printer host/ in the
|
|
discussion below is the printer itself, and the
|
|
<em/printer name/ is the name you configured for the
|
|
printer. See the documentation that accompanied your
|
|
printer and/or printer-network interface.
|
|
|
|
Then, on the other hosts you want to have access to the
|
|
printer, make an entry in their <tt>/etc/printcap</tt>
|
|
files with the following:
|
|
<enum>
|
|
<item>Name the entry anything you want. For
|
|
simplicity, though, you probably want to use the same
|
|
name and aliases as on the printer host.
|
|
|
|
<item>Leave the <tt/lp/ capability blank, explicitly
|
|
(<tt/:lp=:/).
|
|
|
|
<item>Make a spooling directory and specify its
|
|
location in the <tt/sd/ capability. LPD will store
|
|
jobs here before they get sent to the printer host.
|
|
|
|
<item>Place the name of the printer host in the <tt/rm/
|
|
capability.
|
|
|
|
<item>Place the printer name on the <em/printer host/ in
|
|
the <tt/rp/ capability.
|
|
</enum>
|
|
That's it. You don't need to list conversion filters,
|
|
page dimensions, or anything else in the
|
|
<tt>/etc/printcap</tt> file.
|
|
|
|
Here's an example. The host rose has two printers,
|
|
<tt/bamboo/ and <tt/rattan/. We'll enable users on the
|
|
host orchid to print to those printers. Here's the
|
|
<tt>/etc/printcap</tt> file for orchid (back from section
|
|
<ref id="printing:advanced:header-pages:enabling"
|
|
name="Enabling Header Pages">). It already had the entry
|
|
for the printer <tt/teak/; we've added entries for the two
|
|
printers on the host rose:
|
|
<code>
|
|
#
|
|
# /etc/printcap for host orchid - added (remote) printers on rose
|
|
#
|
|
|
|
#
|
|
# teak is local; it's connected directly to orchid:
|
|
#
|
|
teak|hp|laserjet|Hewlett Packard LaserJet 3Si:\
|
|
:lp=/dev/lpt0:sd=/var/spool/lpd/teak:mx#0:\
|
|
:if=/usr/local/libexec/ifhp:\
|
|
:vf=/usr/local/libexec/vfhp:\
|
|
:of=/usr/local/libexec/ofhp:
|
|
|
|
#
|
|
# rattan is connected to rose; send jobs for rattan to rose:
|
|
#
|
|
rattan|line|diablo|lp|Diablo 630 Line Printer:\
|
|
:lp=:rm=rose:rp=rattan:sd=/var/spool/lpd/rattan:
|
|
|
|
#
|
|
# bamboo is connected to rose as well:
|
|
#
|
|
bamboo|ps|PS|S|panasonic|Panasonic KX-P4455 PostScript v51.4:\
|
|
:lp=:rm=rose:rp=bamboo:sd=/var/spool/lpd/bamboo:
|
|
</code>
|
|
Then, we just need to make spooling directories on orchid:
|
|
<tscreen><verb>
|
|
mkdir -p /var/spool/lpd/rattan /var/spool/lpd/bamboo
|
|
chmod 770 /var/spool/lpd/rattan /var/spool/lpd/bamboo
|
|
chown daemon.daemon /var/spool/lpd/rattan /var/spool/lpd/bamboo
|
|
</verb></tscreen>
|
|
|
|
Now, users on orchid can print to <tt/rattan/ and
|
|
<tt/bamboo/. If, for example, a user on orchid typed
|
|
<tscreen><verb>
|
|
lpr -P bamboo -d sushi-review.dvi
|
|
</verb></tscreen>
|
|
the LPD system on orchid would copy the job to the
|
|
spooling directory <tt>/var/spool/lpd/bamboo</tt> and note
|
|
that it was a DVI job. As soon as the host rose has room
|
|
in its <tt/bamboo/ spooling directory, the two
|
|
LPDs would transfer the file to rose. The file would wait
|
|
in rose's queue until it was finally printed. It would be
|
|
converted from DVI to PostScript (since bamboo is a
|
|
PostScript printer) on rose.
|
|
|
|
<sect2><heading>Printers with Networked Data Stream Interfaces<label
|
|
id="printing:advanced:network:net-if"></heading>
|
|
|
|
<p> 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 <ref name="Printers
|
|
Installed on Remote Hosts" id="printing:advanced:network:rm">.
|
|
|
|
The format of the <tt>/etc/printcap</tt> 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
|
|
<tt/netprint/ takes all data on standard input and sends
|
|
it to a network-attached printer. We specify the hostname
|
|
of the printer as the first argument and the port number
|
|
to which to connect as the second argument to
|
|
<tt/netprint/. Note that this supports one-way
|
|
communication only (FreeBSD to printer); many network
|
|
printers support two-way communication, and you might want
|
|
to take advantage of that (to get printer status, perform
|
|
accounting, etc.).
|
|
<code>
|
|
#!/usr/bin/perl
|
|
#
|
|
# netprint - Text filter for printer attached to network
|
|
# Installed in /usr/local/libexec/netprint
|
|
#
|
|
|
|
$#ARGV eq 1 || die "Usage: $0 <printer-hostname> <port-number>";
|
|
|
|
$printer_host = $ARGV[0];
|
|
$printer_port = $ARGV[1];
|
|
|
|
require 'sys/socket.ph';
|
|
|
|
($ignore, $ignore, $protocol) = getprotobyname('tcp');
|
|
($ignore, $ignore, $ignore, $ignore, $address)
|
|
= gethostbyname($printer_host);
|
|
|
|
$sockaddr = pack('S n a4 x8', &ero;AF_INET, $printer_port, $address);
|
|
|
|
socket(PRINTER, &ero;PF_INET, &ero;SOCK_STREAM, $protocol)
|
|
|| die "Can't create TCP/IP stream socket: $!";
|
|
connect(PRINTER, $sockaddr) || die "Can't contact $printer_host: $!";
|
|
while (<STDIN>) { print PRINTER; }
|
|
exit 0;
|
|
</code>
|
|
We can then use this script in various filters. Suppose
|
|
we had a Diablo 750-N line printer connected to the
|
|
network. The printer accepts data to print on port number
|
|
5100. The host name of the printer is scrivener. Here's
|
|
the text filter for the printer:
|
|
<code>
|
|
#!/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
|
|
</code>
|
|
|
|
|
|
<sect1><heading>Restricting Printer Usage<label
|
|
id="printing:advanced:restricting"></heading>
|
|
|
|
<p> 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.
|
|
|
|
<sect2><heading>Restricting Multiple Copies<label
|
|
id="printing:advanced:restricting:copies"></heading>
|
|
|
|
<p> The LPD system makes it easy for users to print multiple
|
|
copies of a file. Users can print jobs with <tt/lpr -#5/
|
|
(for example) and get five copies of each file in the job.
|
|
Whether this is a good thing is up to you.
|
|
|
|
If you feel multiple copies cause unnecessary wear and
|
|
tear on your printers, you can disable the <tt/-#/ option
|
|
to <tt/lpr/ by adding the <tt/sc/ capability to the
|
|
<tt>/etc/printcap</tt> file. When users submit jobs
|
|
with the <tt/-#/ option, they'll see
|
|
<tscreen><verb>
|
|
lpr: multiple copies are not allowed
|
|
</verb></tscreen>
|
|
|
|
Note that if you've set up access to a printer remotely
|
|
(see section <ref name="Printers Installed on Remote
|
|
Hosts" id="printing:advanced:network:rm">), you need the
|
|
<tt/sc/ capability on the remote <tt>/etc/printcap</tt>
|
|
files as well, or else users will still be able to submit
|
|
multiple-copy jobs by using another host.
|
|
|
|
Here's an example. This is the <tt>/etc/printcap</tt>
|
|
file for the host rose. The printer <tt/rattan/ is quite
|
|
hearty, so we'll allow multiple copies, but the laser
|
|
printer <tt/bamboo/'s a bit more delicate, so we'll
|
|
disable multiple copies by adding the <tt/sc/ capability:
|
|
<code>
|
|
#
|
|
# /etc/printcap for host rose - restrict multiple copies on 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:\
|
|
:lp=/dev/ttyd5:fs#0x82000e1:xs#0x820:rw:\
|
|
:if=/usr/local/libexec/psif:\
|
|
:df=/usr/local/libexec/psdf:
|
|
</code>
|
|
Now, we also need to add the <tt/sc/ capability on the
|
|
host orchid's <tt>/etc/printcap</tt> (and while we're at
|
|
it, let's disable multiple copies for the printer
|
|
<tt/teak/):
|
|
<code>
|
|
#
|
|
# /etc/printcap for host orchid - no multiple copies for local
|
|
# printer teak or remote printer bamboo
|
|
|
|
teak|hp|laserjet|Hewlett Packard LaserJet 3Si:\
|
|
:lp=/dev/lpt0:sd=/var/spool/lpd/teak:mx#0:sc:\
|
|
:if=/usr/local/libexec/ifhp:\
|
|
:vf=/usr/local/libexec/vfhp:\
|
|
:of=/usr/local/libexec/ofhp:
|
|
|
|
rattan|line|diablo|lp|Diablo 630 Line Printer:\
|
|
:lp=:rm=rose:rp=rattan:sd=/var/spool/lpd/rattan:
|
|
|
|
bamboo|ps|PS|S|panasonic|Panasonic KX-P4455 PostScript v51.4:\
|
|
:lp=:rm=rose:rp=bamboo:sd=/var/spool/lpd/bamboo:sc:
|
|
</code>
|
|
By using the <tt/sc/ capability, we prevent the use of
|
|
<tt/lpr -#/, but that still doesn't prevent users from
|
|
running <tt/lpr/ multiple times, or from submitting the
|
|
same file mutliple times in one job like this:
|
|
<tscreen><verb>
|
|
lpr forsale.sign forsale.sign forsale.sign forsale.sign forsale.sign
|
|
</verb></tscreen>
|
|
There are many ways to prevent this abuse (including
|
|
ignoring it) which you are free to explore.
|
|
|
|
<sect2><heading>Restricting Access To Printers<label
|
|
id="printing:advanced:restricting:access"></heading>
|
|
|
|
<p> You can control who can print to what printers by using
|
|
the UNIX group mechanism and the <tt/rg/ capability in
|
|
<tt>/etc/printcap</tt>. Just place the users you want to
|
|
have access to a printer in a certain group, and then name
|
|
that group in the <tt/rg/ capability.
|
|
|
|
Users outside the group (including root) will be greeted
|
|
with
|
|
<tscreen><verb>
|
|
lpr: Not a member of the restricted group
|
|
</verb></tscreen>
|
|
if they try to print to the controlled printer.
|
|
|
|
As with the <tt/sc/ (suppress multiple copies) capability,
|
|
you need to specify <tt/rg/ on remote hosts that also have
|
|
access to your printers, if you feel it's appropriate (see
|
|
section <ref name="Printers Installed on Remote Hosts"
|
|
id="printing:advanced:network:rm">).
|
|
|
|
For example, we'll let anyone access the printer
|
|
<tt/rattan/, but only those in group <tt/artists/ can use
|
|
<tt/bamboo/. Here's the familiar <tt>/etc/printcap</tt>
|
|
for host rose:
|
|
<code>
|
|
#
|
|
# /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:
|
|
</code>
|
|
Let's leave the other example <tt>/etc/printcap</tt> file
|
|
(for the host orchid) alone. Of course, anyone on orchid
|
|
can print to <tt/bamboo/. It might be the case that we
|
|
only allow certain logins on orchid anyway, and want them
|
|
to have access to the printer. Or not.
|
|
|
|
<em/Note:/ there can be only one restricted group per
|
|
printer.
|
|
|
|
<sect2><heading>Controlling Sizes of Jobs Submitted<label
|
|
id="printing:advanced:restricting:sizes"></heading>
|
|
|
|
<p> 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 <tt/mx/ capability. The units are in
|
|
BUFSIZ blocks, which are 1024 bytes. If you put a zero
|
|
for this capability, there'll be no limit on file size.
|
|
Note that the limit applies to <em/files/ in a job, and
|
|
<em/not/ the total job size.
|
|
|
|
LPD won't refuse a file that's larger than the limit you
|
|
place on a printer. Instead, it'll queue as much of the
|
|
file up to the limit, which will then get printed. The
|
|
rest will be discarded. Whether this is correct behavior
|
|
is up for debate.
|
|
|
|
Let's add limits to our example printers <tt/rattan/ and
|
|
<tt/bamboo/. Since those artists' PostScript files tend
|
|
to be large, we'll limit them to five megabytes. We'll
|
|
put no limit on the plain text line printer:
|
|
<code>
|
|
#
|
|
# /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:
|
|
</code>
|
|
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
|
|
<tt/mx/ capability in the remote <tt>/etc/printcap</tt>
|
|
files as well. See section <ref name="Printers Installed
|
|
on Remote Hosts" id="printing:advanced:network:rm"> for
|
|
more information on remote printing.
|
|
|
|
There's another specialized way to limit job sizes from
|
|
remote printers; see section <ref
|
|
id="printing:advanced:restricting:remote"
|
|
name="Restricting Jobs from Remote Printers">.
|
|
|
|
<sect2><heading>Restricting Jobs from Remote Printers<label
|
|
id="printing:advanced:restricting:remote"></heading>
|
|
|
|
<p> The LPD spooling system provides several ways to restrict
|
|
print jobs submitted from remote hosts:
|
|
|
|
<descrip>
|
|
<tag/Host restrictions/
|
|
|
|
You can control from which remote hosts a local LPD
|
|
accepts requests with the files
|
|
<tt>/etc/hosts.equiv</tt> and <tt>/etc/hosts.lpd</tt>.
|
|
LPD checks to see if an incoming request is from a
|
|
host listed in either one of these files. If not, LPD
|
|
refuses the request.
|
|
|
|
The format of these files is simple: one host name per
|
|
line. Note that the file <tt>/etc/hosts.equiv</tt> is
|
|
also used by the ruserok(3) protocol, and affects
|
|
programs like <tt/rsh/ and <tt/rcp/, so be careful.
|
|
|
|
For example, here's the <tt>/etc/hosts.lpd</tt> file
|
|
on the host rose:
|
|
<code>
|
|
orchid
|
|
violet
|
|
madrigal.fishbaum.de
|
|
</code>
|
|
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.
|
|
|
|
<tag/Size restrictions/
|
|
|
|
You can control how much free space there needs to
|
|
remain on the filesystem where a spooling directory
|
|
resides. Make a file called <tt/minfree/ in the
|
|
spooling directory for the local printer. Insert in
|
|
that file a number representing how many disk blocks
|
|
(512 bytes) of free space there has to be for a remote
|
|
job to be accepted.
|
|
|
|
This lets you insure that remote users won't fill your
|
|
filesystem. You can also use it to give a certain
|
|
priority to local users: they'll be able to queue jobs
|
|
long after the free disk space has fallen below the
|
|
amount specified in the <tt/minfree/ file.
|
|
|
|
For example, let's add a <tt/minfree/ file for the
|
|
printer <tt/bamboo/. We examine
|
|
<tt>/etc/printcap</tt> to find the spooling directory
|
|
for this printer; here's <tt/bamboo/'s entry:
|
|
<tscreen><verb>
|
|
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:mx#5000:\
|
|
:if=/usr/local/libexec/psif:\
|
|
:df=/usr/local/libexec/psdf:
|
|
</verb></tscreen>
|
|
The spooling directory is the given in the <tt/sd/
|
|
capability. We'll make three megabytes (which is 6144
|
|
disk blocks) the amount of free disk space that must
|
|
exist on the filesystem for LPD to accept remote jobs:
|
|
<tscreen><verb>
|
|
echo 6144 > /var/spool/lpd/bamboo/minfree
|
|
</verb></tscreen>
|
|
<tag/User restrictions/
|
|
|
|
You can control which remote users can print to local
|
|
printers by specifying the <tt/rs/ capability in
|
|
<tt>/etc/printcap</tt>. When <tt/rs/ appears in the
|
|
entry for a locally-attached printer, LPD will accept
|
|
jobs from remote hosts <em/if/ the user submitting the
|
|
job also has an account of the same login name on the
|
|
local host. Otherwise, LPD refuses the job.
|
|
|
|
This capability is particularly useful in an
|
|
environment where there are (for example) different
|
|
departments sharing a network, and some users
|
|
transcend departmental boundaries. By giving them
|
|
accounts on your systems, they can use your printers
|
|
from their own departmental systems. If you'd rather
|
|
allow them to use <em/only/ your printers and not your
|
|
compute resources, you can give them ``token''
|
|
accounts, with no home directory and a useless shell
|
|
like <tt>/usr/bin/false</tt>.
|
|
</descrip>
|
|
|
|
<sect1><heading>Accounting for Printer Usage<label
|
|
id="printing:advanced:acct"></heading>
|
|
|
|
<p> 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 <em/your/ requirements in charging for printer
|
|
usage.
|
|
|
|
To implement accounting, you have to modify a printer's text
|
|
filter (to charge for plain text jobs) and the conversion
|
|
filters (to charge for other file formats), to count pages
|
|
or query the printer for pages printed. You can't get away
|
|
with using the simple output filter, since it cannot do
|
|
accounting. See section <ref name="Filters"
|
|
id="printing:advanced:filter-intro">.
|
|
|
|
Generally, there are two ways to do accounting:
|
|
<itemize>
|
|
<item><em/Periodic accounting/ is the more common way,
|
|
possibly because it's easier. Whenever someone prints a
|
|
job, the filter logs the user, host, and number of pages
|
|
to an accounting file. Every month, semester, year, or
|
|
whatever time period you prefer, you collect the
|
|
accounting files for the various printers, tally up the
|
|
pages printed by users, and charge for usage. Then you
|
|
truncate all the logging files, starting with a clean
|
|
slate for the next period.
|
|
|
|
<item><em/Timely accounting/ is less common, probably
|
|
because it's more difficult. This method has the
|
|
filters charge users for printouts as soon as they use
|
|
the printers. Like disk quotas, the accounting is
|
|
immediate. You can prevent users from printing when
|
|
their account goes in the red, and might provide a way
|
|
for users to check and adjust their ``print quotas.''
|
|
But this method requires some database code to track
|
|
users and their quotas.
|
|
</itemize>
|
|
|
|
The LPD spooling system supports both methods easily: since
|
|
you have to provide the filters (well, most of the time),
|
|
you also have to provide the accounting code. But there is
|
|
a bright side: you have enormous flexibility in your
|
|
accounting methods. For example, you choose whether to use
|
|
periodic or timely accounting. You choose what information
|
|
to log: user names, host names, job types, pages printed,
|
|
square footage of paper used, how long the job took to
|
|
print, and so forth. And you do so by modifying the filters
|
|
to save this information.
|
|
|
|
<sect2><heading>Quick and Dirty Printer Accounting</heading>
|
|
|
|
<p> FreeBSD comes with two programs that can get you set up
|
|
with simple periodic accounting right away. They are the
|
|
text filter <tt/lpf/, described in section <ref
|
|
id="printing:advanced:lpf" name="lpf: a Text Filter">, and
|
|
<tt/pac/, a program to gather and total entries from
|
|
printer accounting files.
|
|
|
|
As mentioned in the section on filters (<ref
|
|
id="printing:advanced:filters" name="Filters">), 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 <tt/af/ capability in
|
|
<tt>/etc/printcap</tt>, and if not specified as an
|
|
absolute path, is relative to the spooling directory.
|
|
|
|
LPD starts <tt/lpf/ with page width and length arguments
|
|
(from the <tt/pw/ and <tt/pl/ capabilities). <tt/lpf/
|
|
uses these arguments to determine how much paper will be
|
|
used. After sending the file to the printer, it then
|
|
writes an accounting entry in the accounting file. The
|
|
entries look like this:
|
|
<tscreen><verb>
|
|
2.00 rose:andy
|
|
3.00 rose:kelly
|
|
3.00 orchid:mary
|
|
5.00 orchid:mary
|
|
2.00 orchid:zhang
|
|
</verb></tscreen>
|
|
You should use a separate accounting file for each
|
|
printer, as <tt/lpf/ has no file locking logic built into
|
|
it, and two <tt/lpf/s might corrupt each other's entries
|
|
if they were to write to the same file at the same time.
|
|
A easy way to insure a separate accounting file for each
|
|
printer is to use <tt/af=acct/ in <tt>/etc/printcap</tt>.
|
|
Then, each accounting file will be in the spooling directory
|
|
for a printer, in a file named <tt/acct/.
|
|
|
|
When you're ready to charge users for printouts, run the
|
|
<tt/pac/ program. Just change to the spooling directory
|
|
for the printer you want to collect on and type <tt/pac/.
|
|
You'll get a dollar-centric summary like the following:
|
|
<code>
|
|
Login pages/feet runs price
|
|
orchid:kelly 5.00 1 $ 0.10
|
|
orchid:mary 31.00 3 $ 0.62
|
|
orchid:zhang 9.00 1 $ 0.18
|
|
rose:andy 2.00 1 $ 0.04
|
|
rose:kelly 177.00 104 $ 3.54
|
|
rose:mary 87.00 32 $ 1.74
|
|
rose:root 26.00 12 $ 0.52
|
|
|
|
total 337.00 154 $ 6.74
|
|
</code>
|
|
These are the arguments <tt/pac/ expects:
|
|
<descrip>
|
|
<tag/<tt/-P<it/printer///
|
|
|
|
Which <it/printer/ to summarize. This option works
|
|
only if there's an absolute path in the <tt/af/
|
|
capability in <tt>/etc/printcap</tt>.
|
|
|
|
<tag/<tt/-c//
|
|
|
|
Sort the output by cost instead of alphabetically by
|
|
user name.
|
|
|
|
<tag/<tt/-m//
|
|
|
|
Ignore host name in the accounting files. With this
|
|
option, user smith on host alpha is the same user
|
|
smith on host gamma. Without, they're different users.
|
|
|
|
<tag/<tt/-p<it/price///
|
|
|
|
Compute charges with <it/price/ dollars per page or
|
|
per foot instead of the price from the <tt/pc/
|
|
capabilty in <tt>/etc/printcap</tt>, or two cents (the
|
|
default). You can specify <it/price/ as a floating
|
|
point number.
|
|
|
|
<tag/<tt/-r//
|
|
|
|
Reverse the sort order.
|
|
|
|
<tag/<tt/-s//
|
|
|
|
Make an accounting summary file and truncate the
|
|
accounting file.
|
|
|
|
<tag/<tt/<it/names...///
|
|
|
|
Print accounting information for the given user
|
|
<it/names/ only.
|
|
</descrip>
|
|
|
|
In the default summary that <tt/pac/ produces, you see the
|
|
number of pages printed by each user from various hosts.
|
|
If, at your site, host doesn't matter (because users can
|
|
use any host), run <tt/pac -m/, to produce the following
|
|
summary:
|
|
<code>
|
|
Login pages/feet runs price
|
|
andy 2.00 1 $ 0.04
|
|
kelly 182.00 105 $ 3.64
|
|
mary 118.00 35 $ 2.36
|
|
root 26.00 12 $ 0.52
|
|
zhang 9.00 1 $ 0.18
|
|
|
|
total 337.00 154 $ 6.74
|
|
</code>
|
|
To compute the dollar amount due, <tt/pac/ uses the
|
|
<tt/pc/ capability in the <tt>/etc/printcap</tt> file
|
|
(default of 200, or 2 cents per page). Specify, in
|
|
hundreths of cents, the price per page or per foot you
|
|
want to charge for printouts in this capability. You can
|
|
override this value when you run <tt/pac/ with the <tt/-p/
|
|
option. The units for the <tt/-p/ option are in dollars,
|
|
though, not hundreths of cents. For example,
|
|
<tscreen><verb>
|
|
pac -p1.50
|
|
</verb></tscreen>
|
|
makes each page cost one dollar and fifty cents. You can
|
|
really rake in the profits by using this option.
|
|
|
|
Finally, running <tt/pac -s/ will save the summary
|
|
information in a summary accounting file, which is named
|
|
the same as the printer's accounting file, but with
|
|
<tt/_sum/ appended to the name. It then truncates the
|
|
accounting file. When you run <tt/pac/ again, it rereads
|
|
the summary file to get starting totals, then adds
|
|
information from the regular accounting file.
|
|
|
|
|
|
<sect2><heading>How Can You Count Pages Printed?</heading>
|
|
|
|
<p> 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 <tt/lpf/ (introduced in <ref
|
|
id="printing:advanced:lpf" name="lpf: a 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 <tt/lpf/'s source
|
|
code.
|
|
|
|
How do you handle other file formats, though?
|
|
|
|
Well, for DVI-to-LaserJet or DVI-to-PostScript conversion,
|
|
you can have your filter parse the diagnostic output of
|
|
<tt/dvilj/ or <tt/dvips/ and look to see how many pages
|
|
were converted. You might be able to do similar things
|
|
with other file formats and conversion programs.
|
|
|
|
But these methods suffer from the fact that the printer
|
|
may not actually print all those pages. For example, it
|
|
could jam, run out of toner, or explode---and the user
|
|
would still get charged.
|
|
|
|
So, what can you do?
|
|
|
|
There is only one <em/sure/ way to do <em/accurate/
|
|
accounting. Get a printer that can tell you how much
|
|
paper it uses, and attach it via a serial line or a
|
|
network connection. Nearly all PostScript printers
|
|
support this notion. Other makes and models do as well
|
|
(networked Imagen laser printers, for example). Modify
|
|
the filters for these printers to get the page usage after
|
|
they print each job and have them log accounting
|
|
information based on that value <em/only/. There's no
|
|
line counting nor error-prone file examination required.
|
|
|
|
Of course, you can always be generous and make all
|
|
printouts free.
|
|
|
|
<sect><heading>Alternatives to the Standard Spooler<label
|
|
id="printing:lpd-alternatives"></heading>
|
|
|
|
<p> 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 <em/two/ alternatives---and
|
|
they're almost identical to each other! They are:
|
|
<descrip>
|
|
<tag/PLP, the Portable Line Printer Spooler System/
|
|
|
|
PLP was based on software developed by Patrick Powell and
|
|
then maintained by an Internet-wide group of developers.
|
|
The main site for the software is at <htmlurl
|
|
url="ftp://ftp.iona.ie/pub/plp"
|
|
name="ftp://ftp.iona.ie/pub/plp">. There's also a <htmlurl
|
|
url="http://www.iona.ie:8000/www/hyplan/jmason/plp.html"
|
|
name="web page">.
|
|
|
|
It's quite similar to the BSD LPD spooler, but boasts a
|
|
host of features, including:
|
|
<itemize>
|
|
<item>Better network support, including built-in support
|
|
for networked printers, NIS-maintained printcaps, and
|
|
NFS-mounted spooling directories
|
|
|
|
<item>Sophisticated queue management, allowing multiple
|
|
printers on a queue, transfer of jobs between queues,
|
|
and queue redirection
|
|
|
|
<item>Remote printer control functions
|
|
|
|
<item>Prioritization of jobs
|
|
|
|
<item>Expansive security and access options
|
|
</itemize>
|
|
|
|
<tag/LPRng/
|
|
|
|
LPRng, which purportedly means ``LPR: the Next
|
|
Generation'' is a complete rewrite of PLP. Patrick Powell
|
|
and Justin Mason (the principal maintainer of PLP)
|
|
collaborated to make LPRng. The main site for LPRng is
|
|
<htmlurl url="ftp://dickory.sdsu.edu/pub/LPRng"
|
|
name="ftp://dickory.sdsu.edu/pub/LPRng">.
|
|
</descrip>
|
|
|
|
|
|
<sect><heading>Acknowledgments</heading>
|
|
|
|
<p> I'd like to thank the following people who've assisted in
|
|
the development of this document:
|
|
|
|
<descrip>
|
|
<tag/Daniel Eischen <tt/<deischen@iworks.interworks.org>//
|
|
|
|
For providing a plethora of HP filter programs for perusal.
|
|
|
|
<tag/Jake Hamby <tt/<jehamby@lightside.com>//
|
|
|
|
For the Ghostscript-to-HP filter.
|
|
|
|
<tag/My wife, Mary Kelly <tt/<urquhart@argyre.colorado.edu>//
|
|
|
|
For allowing me to spend more time with FreeBSD than with her.
|
|
|
|
</descrip>
|