summaryrefslogtreecommitdiff
path: root/en/handbook/printing/chapter.sgml
diff options
context:
space:
mode:
authorNik Clayton <nik@FreeBSD.org>1998-11-03 23:17:06 +0000
committerNik Clayton <nik@FreeBSD.org>1998-11-03 23:17:06 +0000
commit2207769022c0b726ecdd97003a494c796dfb022b (patch)
tree2f26f2909f28edb06c950ac6fbbb830cf0db746c /en/handbook/printing/chapter.sgml
parent05dc329be3f5fae2b8a8dc537730f3ea884900b0 (diff)
Notes
Diffstat (limited to 'en/handbook/printing/chapter.sgml')
-rw-r--r--en/handbook/printing/chapter.sgml4938
1 files changed, 4938 insertions, 0 deletions
diff --git a/en/handbook/printing/chapter.sgml b/en/handbook/printing/chapter.sgml
new file mode 100644
index 0000000000..3619fa1649
--- /dev/null
+++ b/en/handbook/printing/chapter.sgml
@@ -0,0 +1,4938 @@
+ <chapter id="printing">
+ <title>Printing</title>
+
+ <para><emphasis>Contributed by &a.kelly;<!-- <br> -->30 September
+ 1995</emphasis></para>
+
+ <para>In order to use printers with FreeBSD, you will need to set them
+ up to work with the Berkeley line printer spooling system, also known
+ as the LPD spooling system. It is the standard printer control system
+ in FreeBSD. This section introduces the LPD spooling system, often
+ simply called LPD.</para>
+
+ <para>If you are already familiar with LPD or another printer spooling
+ system, you may wish to skip to section <xref
+ linkend="printing-intro-setup" remap="Setting up the spooling
+ system">.</para>
+
+
+ <sect1 id="printing-intro-spooler">
+ <title>What the Spooler Does</title>
+
+ <para>LPD controls everything about a host's printers. It is
+ responsible for a number of things:</para>
+
+
+ <itemizedlist>
+
+ <listitem>
+ <para>It controls access to attached printers and printers
+ attached to other hosts on the network.</para>
+ </listitem>
+
+ <listitem>
+ <para>It enables users to submit files to be printed; these
+ submissions are known as <emphasis>jobs</emphasis>.</para>
+ </listitem>
+
+ <listitem>
+ <para>It prevents multiple users from accessing a printer at the
+ same time by maintaining a <emphasis>queue</emphasis> for each
+ printer.</para>
+ </listitem>
+
+ <listitem>
+ <para>It can print <emphasis>header pages</emphasis> (also known
+ as <emphasis>banner</emphasis> or <emphasis>burst</emphasis>
+ pages) so users can easily find jobs they have printed in a
+ stack of printouts.</para>
+ </listitem>
+
+ <listitem>
+ <para>It takes care of communications parameters for printers
+ connected on serial ports.</para>
+ </listitem>
+
+ <listitem>
+ <para>It can send jobs over the network to another LPD spooler
+ on another host.</para>
+ </listitem>
+
+ <listitem>
+ <para>It can run special filters to format jobs to be printed
+ for various printer languages or printer capabilities.</para>
+ </listitem>
+
+ <listitem>
+ <para>It can account for printer usage.</para>
+ </listitem>
+
+ </itemizedlist>
+
+
+ <para>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.</para>
+
+ </sect1>
+
+ <sect1 id="printing-intro-why">
+ <title>Why You Should Use the Spooler</title>
+
+ <para>If you are the sole user of your system, you may be wondering
+ why you should bother with the spooler when you do not need access
+ control, header pages, or printer accounting. While it is possible
+ to enable direct access to a printer, you should use the spooler
+ anyway since</para>
+
+
+ <itemizedlist>
+
+ <listitem>
+ <para>LPD prints jobs in the background; you do not have to wait
+ for data to be copied to the printer.</para>
+ </listitem>
+
+ <listitem>
+ <para>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 will not have to do these steps manually.</para>
+ </listitem>
+
+ <listitem>
+ <para>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 will more easily
+ support other software you may later add or already
+ have.</para>
+ </listitem>
+
+ </itemizedlist>
+
+
+ </sect1>
+
+ <sect1 id="printing-intro-setup">
+ <title>Setting Up the Spooling System</title>
+
+ <para>To use printers with the LPD spooling system, you will need to
+ set up both your printer hardware and the LPD software. This
+ document describes two levels of setup:</para>
+
+
+ <itemizedlist>
+
+ <listitem>
+ <para>See section <xref linkend="printing-simple" remap="Simple
+ Printer Setup"> to learn how to connect a printer, tell LPD
+ how to communicate with it, and print plain text files to the
+ printer.</para>
+ </listitem>
+
+ <listitem>
+ <para>See section <xref linkend="printing-advanced"
+ remap="Advanced Printer Setup"> 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.</para>
+ </listitem>
+
+ </itemizedlist>
+
+
+ </sect1>
+
+ <sect1 id="printing-simple">
+ <title>Simple Printer Setup</title>
+
+ <para>This section tells how to configure printer hardware and the
+ LPD software to use the printer. It teaches the basics:</para>
+
+
+ <itemizedlist>
+
+ <listitem>
+ <para>Section <xref linkend="printing-hardware" remap="Hardware
+ Setup"> gives some hints on connecting the printer to a port
+ on your computer.</para>
+ </listitem>
+
+ <listitem>
+ <para>Section <xref linkend="printing-software" remap="Software
+ Setup"> shows how to setup the LPD spooler configuration
+ file <filename>/etc/printcap</filename>.</para>
+ </listitem>
+
+ </itemizedlist>
+
+
+ <para>If you are setting up a printer that uses a network protocol to
+ accept data to print instead of a serial or parallel interface, see
+ <xref linkend="printing-advanced-network-net-if" remap="Printers
+ With Networked Data Stream Interaces">.</para>
+
+ <para>Although this section is called &ldquo;Simple Printer Setup,&rdquo; it is
+ 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.</para>
+
+
+ <sect2 id="printing-hardware">
+ <title>Hardware Setup</title>
+
+ <para>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.</para>
+
+ <para>If you have already connected your printer and have
+ successfully printed with it under another operating system, you
+ can probably skip to section <xref linkend="printing-software"
+ remap="Software Setup">.</para>
+
+
+ <sect3 id="printing-ports">
+ <title>Ports and Cables</title>
+
+ <para>Nearly all printers you can get for a PC today support one
+ or both of the following interfaces:</para>
+
+
+ <itemizedlist>
+
+ <listitem>
+ <para><emphasis>Serial</emphasis> 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.</para>
+ </listitem>
+
+ <listitem>
+ <para><emphasis>Parallel</emphasis> 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.</para>
+
+ <para>Parallel interfaces are sometimes known as
+ &ldquo;Centronics&rdquo; interfaces, named after the connector type
+ on the printer.</para>
+ </listitem>
+
+ </itemizedlist>
+
+
+ <para>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 does not support two-way parallel
+ communication yet.</para>
+
+ <para>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 need not 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 has 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.</para>
+
+ <para>So, which interface should you use?</para>
+
+
+ <itemizedlist>
+
+ <listitem>
+ <para>If you need two-way communication, use a serial port.
+ FreeBSD does not yet support two-way communication over a
+ parallel port.</para>
+ </listitem>
+
+ <listitem>
+ <para>If you do not need two-way communication and can pick
+ parallel or serial, prefer the parallel interface. It
+ keeps a serial port free for other peripherals&mdash;such as a
+ terminal or a modem&mdash;and is faster most of the time. It
+ is also easier to configure.</para>
+ </listitem>
+
+ <listitem>
+ <para>Finally, use whatever works.</para>
+ </listitem>
+
+ </itemizedlist>
+
+
+ </sect3>
+
+ <sect3 id="printing-parallel">
+ <title>Parallel Ports</title>
+
+ <para>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.</para>
+
+ <para>Remember which parallel port you used on the computer. The
+ first parallel port is <filename>/dev/lpt0</filename> to FreeBSD; the second is
+ <filename>/dev/lpt1</filename>, and so on.</para>
+
+ </sect3>
+
+ <sect3 id="printing-serial">
+ <title>Serial Ports</title>
+
+ <para>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.</para>
+
+ <para>If you are unsure what the &ldquo;proper serial cable&rdquo; is, you
+ may wish to try one of the following alternatives:</para>
+ <itemizedlist>
+
+ <listitem>
+ <para>A <emphasis>modem</emphasis> 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 &ldquo;DTE-to-DCE&rdquo;
+ cable.</para>
+ </listitem>
+
+ <listitem>
+ <para>A <emphasis>null-modem</emphasis> 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
+ &ldquo;DTE-to-DTE&rdquo; cable.</para>
+ </listitem>
+
+ <listitem>
+ <para>A <emphasis>serial printer</emphasis> cable, required
+ for some unusual printers, is like the null modem cable,
+ but sends some signals to their counterparts instead of
+ being internally shorted.</para>
+ </listitem>
+
+ </itemizedlist>
+
+ <para>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
+ <emphasis>baud rate</emphasis>) 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
+ &ldquo;in-band&rdquo; or &ldquo;software&rdquo;)
+ flow control. Remember these settings for the software
+ configuration that follows.</para>
+
+ </sect3>
+ </sect2>
+
+ <sect2 id="printing-software">
+ <title>Software Setup</title>
+
+ <para>This section describes the software setup necessary to print
+ with the LPD spooling system in FreeBSD.</para>
+
+ <para>Here is an outline of the steps involved:</para>
+
+ <procedure>
+
+ <step>
+ <para>Configure your kernel, if necessary, for the port you
+ are using for the printer; section <xref
+ linkend="printing-kernel" remap="Kernel Configuration">
+ tells you what you need to do.</para>
+ </step>
+
+ <step>
+ <para>Set the communications mode for the parallel port, if
+ you are using a parallel port; section <xref
+ linkend="printing-parallel-port-mode" remap="Setting the
+ Communication Mode for the Parallel Port"> gives details.</para>
+ </step>
+
+ <step>
+ <para>Test if the operating system can send data to the
+ printer. Section <xref linkend="printing-testing"
+ remap="Checking Printer Communications"> gives some
+ suggestions on how to do this.</para>
+ </step>
+
+ <step>
+ <para>Set up LPD for the printer by modifying the file
+ <filename>/etc/printcap</filename>. Section <xref
+ linkend="printing-printcap" remap="The /etc/printcap
+ File"> shows you how.</para>
+ </step>
+
+ </procedure>
+
+ <sect3 id="printing-kernel">
+ <title>Kernel Configuration</title>
+
+ <para>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 is not already configured for one.</para>
+
+ <para>To find out if the kernel you are currently using supports a
+ serial interface, type:</para>
+
+ <informalexample>
+ <screen>&prompt.root; <userinput>dmesg | grep sio<replaceable>N</replaceable></userinput></screen>
+ </informalexample>
+
+ <para>Where <replaceable>N</replaceable> is the
+ number of the serial port, starting from zero. If you see
+ output similar to the following:</para>
+
+ <informalexample>
+ <screen>sio2 at 0x3e8-0x3ef irq 5 on isa
+sio2: type 16550A</screen>
+ </informalexample>
+
+ <para>then the kernel supports the port.</para>
+
+ <para>To find out if the kernel supports a parallel interface,
+ type:</para>
+
+ <informalexample>
+ <screen>&prompt.root; <userinput>dmesg | grep lpt<replaceable>N</replaceable></userinput></screen>
+ </informalexample>
+
+ <para>Where <replaceable>N</replaceable> is the
+ number of the parallel port, starting from zero. If you see
+ output similar to the following
+
+ <informalexample>
+ <screen>lpt0 at 0x378-0x37f on isa</screen>
+ </informalexample> then the kernel supports the port.</para>
+
+ <para>You might have to reconfigure your kernel in order for the
+ operating system to recognize and use the parallel or serial
+ port you are using for the printer.</para>
+
+ <para>To add support for a serial port, see the section on kernel
+ configuration. To add support for a parallel port, see that
+ section <emphasis>and</emphasis> the section that
+ follows.</para>
+
+
+ <sect4 id="printing-dev-ports">
+ <title>Adding <filename>/dev</filename> Entries for the Ports</title>
+
+ <para>Even though the kernel may support communication along a
+ serial or parallel port, you will still need a software
+ interface through which programs running on the system can
+ send and receive data. That is what entries in the
+ <filename>/dev</filename> directory are for.</para>
+
+ <para><emphasis>To add a <filename>/dev</filename>
+ entry for a port:</emphasis></para>
+
+ <procedure>
+
+ <step>
+ <para>Become root with the <citerefentry>
+ <refentrytitle>su</refentrytitle></citerefentry>
+ command. Enter the root password when prompted.</para>
+ </step>
+
+ <step>
+ <para>Change to the <filename>/dev</filename> directory:</para>
+
+ <informalexample>
+ <screen>&prompt.root; cd /dev</screen>
+ </informalexample>
+ </step>
+
+ <step>
+ <para>Type:</para>
+
+ <informalexample>
+ <screen>&prompt.root; <userinput>./MAKEDEV <replaceable>port</replaceable></userinput></screen>
+ </informalexample>
+
+ <para>Where <replaceable>port</replaceable> is the device entry for the
+ port you want to make. Use <literal>lpt0</literal> for the first parallel port,
+ <literal>lpt1</literal> for the second, and
+ so on; use <literal>ttyd0</literal> for the
+ first serial port, <literal>ttyd1</literal>
+ for the second, and so on.</para>
+ </step>
+
+ <step>
+ <para>Type:</para>
+
+ <informalexample>
+ <screen>&prompt.root; <userinput>ls -l <replaceable>port</replaceable></userinput></screen>
+ </informalexample>
+
+ <para>to make sure the device entry got
+ created.</para>
+ </step>
+
+ </procedure>
+
+ </sect4>
+
+ <sect4 id="printing-parallel-port-mode">
+ <title>Setting the Communication Mode for the Parallel Port</title>
+
+ <para>When you are using the parallel interface, you can choose
+ whether FreeBSD should use interrupt-driven or polled
+ communication with the printer.</para>
+
+
+ <itemizedlist>
+
+ <listitem>
+ <para>The <emphasis>interrupt-driven</emphasis> method is
+ the default with the GENERIC kernel. With this method,
+ the operating system uses an IRQ line to determine when
+ the printer is ready for data.</para>
+ </listitem>
+
+ <listitem>
+ <para>The <emphasis>polled</emphasis> method directs the
+ operating system to repeatedly ask the printer if it is
+ ready for more data. When it responds ready, the kernel
+ sends more data.</para>
+ </listitem>
+
+ </itemizedlist>
+
+
+ <para>The interrupt-driven method is somewhat faster but uses up
+ a precious IRQ line. You should use whichever one
+ works.</para>
+
+ <para>You can set the communications mode in two ways: by
+ configuring the kernel or by using the <citerefentry>
+ <refentrytitle>lptcontrol</refentrytitle></citerefentry> program.</para>
+
+ <para><emphasis>To set the communications mode by
+ configuring the kernel:</emphasis></para>
+
+ <procedure>
+
+ <step>
+ <para>Edit your kernel configuration file. Look for or
+ add an <literal>lpt0</literal> entry. If you
+ are setting up the second parallel port, use <literal>lpt1</literal> instead. Use <literal>lpt2</literal> for the third port, and so
+ on.</para>
+ <itemizedlist>
+
+ <listitem>
+ <para>If you want interrupt-driven mode, add the
+ <literal>irq</literal> specifier:</para>
+
+ <programlisting>
+device lpt0 at isa? port? tty irq <replaceable>N</replaceable> vector lptintr</programlisting>
+
+ <para>Where <replaceable>N</replaceable> is the IRQ number for your
+ computer's parallel port.</para>
+ </listitem>
+
+ <listitem>
+ <para>If you want polled mode, do not add the
+ <literal>irq</literal> specifier:</para>
+
+ <programlisting>
+device lpt0 at isa? port? tty vector lptintr</programlisting>
+ </listitem>
+
+ </itemizedlist>
+
+ </step>
+
+ <step>
+ <para>Save the file. Then configure, build, and install
+ the kernel, then reboot. See <xref
+ linkend="kernelconfig" remap="kernel configuration">
+ for more details.</para>
+ </step>
+
+ </procedure>
+
+ <para><emphasis>To set the communications mode
+ with</emphasis> <citerefentry>
+ <refentrytitle>lptcontrol</refentrytitle></citerefentry>:</para>
+
+ <procedure>
+
+ <step>
+ <para>Type:</para>
+
+ <informalexample>
+ <screen>&prompt.root; <userinput>lptcontrol -i -u <replaceable>N</replaceable></userinput></screen>
+ </informalexample>
+
+ <para>to set interrupt-driven mode for
+ <literal>lpt<replaceable>N</replaceable></literal>.</para>
+ </step>
+
+ <step>
+ <para>Type:</para>
+
+ <informalexample>
+ <screen>&prompt.root; <userinput>lptcontrol -p -u <replaceable>N</replaceable></userinput></screen>
+ </informalexample>
+
+ <para>to set polled-mode for <literal>lpt<replaceable>N</replaceable></literal>.</para>
+ </step>
+
+ </procedure>
+
+ <para>You could put these commands in your
+ <filename>/etc/rc.local</filename> file to set the mode each
+ time your system boots. See <citerefentry><refentrytitle>lptcontrol</refentrytitle><manvolnum>8</manvolnum></citerefentry> for more information.</para>
+
+ </sect4>
+
+ <sect4 id="printing-testing">
+ <title>Checking Printer Communications</title>
+
+ <para>Before proceeding to configure the spooling system, you
+ should make sure the operating system can successfully send
+ data to your printer. It is a lot easier to debug printer
+ communication and the spooling system separately.</para>
+
+ <para>To test the printer, we will send some text to it. For
+ printers that can immediately print characters sent to them,
+ the program <citerefentry>
+ <refentrytitle>lptest</refentrytitle></citerefentry> is perfect: it generates all 96 printable ASCII characters in 96 lines.</para>
+
+ <para>For a PostScript (or other language-based) printer, we
+ will need a more sophisticated test. A small PostScript
+ program, such as the following, will suffice:</para>
+
+ <programlisting>
+%!PS
+100 100 moveto 300 300 lineto stroke
+310 310 moveto /Helvetica findfont 12 scalefont setfont
+(Is this thing working?) show
+showpage</programlisting>
+
+
+ <note>
+ <para>When this document refers to a printer language, I am
+ 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 is the
+ kind of printer language for which we must make special
+ accommodations.</para>
+ </note>
+
+ <sect5 id="printing-checking-parallel">
+ <title>Checking a Parallel Printer</title>
+
+ <para>This section tells you how to check if FreeBSD can
+ communicate with a printer connected to a parallel
+ port.</para>
+
+ <para><emphasis>To test a printer on a parallel
+ port:</emphasis></para>
+
+ <procedure>
+
+ <step>
+ <para>Become root with <citerefentry>
+ <refentrytitle>su</refentrytitle></citerefentry>.</para>
+ </step>
+
+ <step>
+ <para>Send data to the printer.</para>
+ <itemizedlist>
+
+ <listitem>
+ <para>If the printer can print plain text, then
+ use <citerefentry>
+ <refentrytitle>lptest</refentrytitle></citerefentry>. Type:</para>
+
+ <informalexample>
+ <screen>&prompt.root; <userinput>lptest &gt; /dev/lpt<replaceable>N</replaceable></userinput></screen>
+ </informalexample>
+
+ <para>Where <replaceable>N</replaceable> is the number of the
+ parallel port, starting from zero.</para>
+ </listitem>
+
+ <listitem>
+ <para>If the printer understands PostScript or
+ other printer language, then send a small
+ program to the printer. Type:</para>
+
+ <informalexample>
+ <screen>&prompt.root; <userinput>cat &gt; /dev/lpt<replaceable>N</replaceable></userinput></screen>
+ </informalexample>
+
+ <para>Then, line by line, type the
+ program <emphasis>carefully</emphasis> as you
+ cannot edit a line once you have pressed RETURN
+ or ENTER. When you have finished entering the
+ program, press CONTROL+D, or whatever your end
+ of file key is.</para>
+
+ <para>Alternatively, you can put the program in a
+ file and type:</para>
+
+ <informalexample>
+ <screen>&prompt.root; <userinput>cat <replaceable>file</replaceable> &gt; /dev/lpt<replaceable>N</replaceable></userinput></screen>
+ </informalexample>
+
+ <para>Where <replaceable>file</replaceable> is the name of the
+ file containing the program you want to send to
+ the printer.</para>
+ </listitem>
+
+ </itemizedlist>
+
+ </step>
+
+ </procedure>
+
+ <para>You should see something print. Do not worry if the
+ text does not look right; we will fix such things
+ later.</para>
+
+ </sect5>
+
+ <sect5 id="printing-checking-serial">
+ <title>Checking a Serial Printer</title>
+
+ <para>This section tells you how to check if FreeBSD can
+ communicate with a printer on a serial port.</para>
+
+ <para><emphasis>To test a printer on a serial
+ port:</emphasis></para>
+
+ <procedure>
+
+ <step>
+ <para>Become root with <citerefentry>
+ <refentrytitle>su</refentrytitle></citerefentry>.</para>
+ </step>
+
+ <step>
+ <para>Edit the file <filename>/etc/remote</filename>.
+ Add the following entry:</para>
+
+ <programlisting>
+printer:dv=/dev/<replaceable>port</replaceable>:br#<replaceable>bps-rate</replaceable>:pa=<replaceable>parity</replaceable></programlisting>
+
+ <para>Where <replaceable>port</replaceable> is the device entry for the
+ serial port (<literal>ttyd0</literal>,
+ <literal>ttyd1</literal>, etc.), <replaceable>bps-rate</replaceable> is the bits-per-second
+ rate at which the printer communicates, and
+ <replaceable>parity</replaceable> is the parity required by
+ the printer (either <literal>even</literal>, <literal>odd</literal>, <literal>none</literal>, or <literal>zero</literal>).</para>
+
+ <para>Here is a sample entry for a printer connected via
+ a serial line to the third serial port at 19200 bps
+ with no parity:</para>
+
+ <programlisting>
+printer:dv=/dev/ttyd2:br#19200:pa=none</programlisting>
+ </step>
+
+ <step>
+ <para>Connect to the printer with <citerefentry>
+ <refentrytitle>tip</refentrytitle></citerefentry>. Type:</para>
+ <informalexample>
+ <screen>&prompt.root; <userinput>tip printer</userinput></screen>
+ </informalexample>
+
+ <para>If this step does not work, edit
+ the file <filename>/etc/remote</filename> again and
+ try using
+ <filename>/dev/cuaa<replaceable>N</replaceable></filename> instead of <filename>/dev/ttyd<replaceable>N</replaceable></filename>.</para>
+ </step>
+
+ <step>
+ <para>Send data to the printer.</para>
+ <itemizedlist>
+
+ <listitem>
+ <para>If the printer can print plain text, then
+ use <citerefentry>
+ <refentrytitle>lptest</refentrytitle></citerefentry>. Type:</para>
+
+ <informalexample>
+ <screen><prompt>~</prompt><userinput>$lptest</userinput></screen>
+ </informalexample>
+ </listitem>
+
+ <listitem>
+ <para>If the printer understands PostScript or
+ other printer language, then send a small
+ program to the printer. Type the program, line
+ by line, <emphasis>very carefully</emphasis> 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.</para>
+
+ <para>Alternatively, you can put the program in a
+ file and type:</para>
+
+ <informalexample>
+ <screen><prompt>~</prompt><userinput>&gt;<replaceable>file</replaceable></userinput></screen>
+ </informalexample>
+
+ <para>Where <replaceable>file</replaceable> is the name of the
+ file containing the program. After
+ <citerefentry>
+ <refentrytitle>tip</refentrytitle></citerefentry> sends the file, press any required end-of-file key.</para>
+ </listitem>
+
+ </itemizedlist>
+
+ </step>
+
+ </procedure>
+
+ <para>You should see something print. Do not worry if the
+ text does not look right; we will fix that later.</para>
+
+ </sect5>
+ </sect4>
+ </sect3>
+
+ <sect3 id="printing-printcap">
+ <title>Enabling the Spooler: The
+ <filename>/etc/printcap</filename> File</title>
+
+ <para>At this point, your printer should be hooked up, your
+ kernel configured to communicate with it (if necessary), and you
+ have been able to send some simple data to the printer. Now, we
+ are ready to configure LPD to control access to your
+ printer.</para>
+
+ <para>You configure LPD by editing the file
+ <filename>/etc/printcap</filename>. The LPD spooling system
+ reads this file each time the spooler is used, so updates to the
+ file take immediate effect.</para>
+
+ <para>The format of the <citerefentry>
+ <refentrytitle>printcap</refentrytitle></citerefentry> file is straightforward. Use your favorite text editor to make changes to <filename>/etc/printcap</filename>. The format is identical to other capability files like <filename>/usr/share/misc/termcap</filename> and <filename>/etc/remote</filename>. For complete information about the format, see the <citerefentry><refentrytitle>cgetent</refentrytitle><manvolnum>3</manvolnum></citerefentry>.</para>
+
+ <para>The simple spooler configuration consists of the following
+ steps:</para>
+
+ <procedure>
+
+ <step>
+ <para>Pick a name (and a few convenient aliases) for the
+ printer, and put them in the
+ <filename>/etc/printcap</filename> file; see <xref
+ linkend="printing-naming" remap="Naming the Printer">.</para>
+ </step>
+
+ <step>
+ <para>Turn off header pages (which are on by default) by
+ inserting the <literal>sh</literal> capability;
+ see <xref linkend="printing-no-header-pages"
+ remap="Suppressing Header Pages">.</para>
+ </step>
+
+ <step>
+ <para>Make a spooling directory, and specify its location
+ with the <literal>sd</literal> capability; see
+ <xref linkend="printing-spooldir"
+ remap="Making the Spooling Directory">.</para>
+ </step>
+
+ <step>
+ <para>Set the <filename>/dev</filename> entry to use for the
+ printer, and note it in <filename>/etc/printcap</filename>
+ with the <literal>lp</literal> capability; see
+ <xref
+ linkend="printing-device" remap="Identifying the Printer
+ Device">. Also, if the printer is on a serial port, set
+ up the communication parameters with the
+ <literal>fs</literal>, <literal>fc</literal>,
+ <literal>xs</literal>, and <literal>xc</literal> capabilities; see <xref
+ linkend="printing-commparam" remap="Configuring Spooler
+ Communications Parameters">.</para>
+ </step>
+
+ <step>
+ <para>Install a plain text input filter; see <xref
+ linkend="printing-textfilter" remap="Installing the Text
+ Filter"></para>
+ </step>
+
+ <step>
+ <para>Test the setup by printing something with the
+ <citerefentry>
+ <refentrytitle>lpr</refentrytitle></citerefentry>
+ command; see <xref linkend="printing-trying" remap="Trying
+ It Out"> and <xref linkend="printing-troubleshooting"
+ remap="Troubleshooting">.</para>
+ </step>
+
+ </procedure>
+
+ <note>
+ <para>Language-based printers, such as PostScript printers,
+ cannot directly print plain text. The simple setup outlined
+ above and described in the following sections assumes that if
+ you are installing such a printer you will print only files
+ that the printer can understand.</para>
+ </note>
+
+ <para>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 are installing such a printer and want to be able to
+ print jobs in the printer language <emphasis>and</emphasis>
+ print plain text jobs, you are 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 <xref
+ linkend="printing-advanced-if-conversion" remap="Accommodating
+ Plain Text Jobs on PostScript Printers"> tells how to do
+ this.</para>
+
+
+ <sect4 id="printing-naming">
+ <title>Naming the Printer</title>
+
+ <para>The first (easy) step is to pick a name for your printer.
+ It really does not matter whether you choose functional or
+ whimsical names since you can also provide a number aliases
+ for the printer.</para>
+
+ <para>At least one of the printers specified in the
+ <filename>/etc/printcap</filename> should have the alias
+ <literal>lp</literal>. This is the default
+ printer's name. If users do not have the <envar>PRINTER</envar> environment
+ variable nor specify a printer name on the command line of any
+ of the LPD commands, then <literal>lp</literal>
+ will be the default printer they get to use.</para>
+
+ <para>Also, it is common practice to make the last alias for a
+ printer be a full description of the printer, including make
+ and model.</para>
+
+ <para>Once you have picked a name and some common aliases, put
+ them in the <filename>/etc/printcap</filename> 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.</para>
+
+ <para>In the following example, we start with a skeletal
+ <filename>/etc/printcap</filename> that defines two printers
+ (a Diablo 630 line printer and a Panasonic KX-P4455 PostScript
+ laser printer):</para>
+
+ <programlisting>
+#
+# /etc/printcap for host rose
+#
+rattan|line|diablo|lp|Diablo 630 Line Printer:
+
+bamboo|ps|PS|S|panasonic|Panasonic KX-P4455 PostScript v51.4:</programlisting>
+
+ <para>In this example, the first printer is named
+ <literal>rattan</literal> and has as aliases
+ <literal>line</literal>, <literal>diablo</literal>,
+ <literal>lp</literal>, and <literal>Diablo 630
+ Line Printer</literal>. Since it has the alias <literal>lp</literal>, it is also the default printer. The
+ second is named <literal>bamboo</literal>, and has
+ as aliases <literal>ps</literal>,
+ <literal>PS</literal>, <literal>S</literal>,
+ <literal>panasonic</literal>, and <literal>Panasonic KX-P4455 PostScript
+ v51.4</literal>.</para>
+
+ </sect4>
+
+ <sect4 id="printing-no-header-pages">
+ <title>Suppressing Header Pages</title>
+
+ <para>The LPD spooling system will by default print a
+ <emphasis>header page</emphasis> 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 will suppress
+ header pages.</para>
+
+ <para>To suppress header pages, add the <literal>sh</literal> capability to the entry for the
+ printer in <filename>/etc/printcap</filename>. Here is the
+ example <filename>/etc/printcap</filename> with <literal>sh</literal> added:</para>
+
+ <programlisting>
+#
+# /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:</programlisting>
+
+ <para>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.</para>
+
+ </sect4>
+
+ <sect4 id="printing-spooldir">
+ <title>Making the Spooling Directory</title>
+
+ <para>The next step in the simple spooler setup is to make a
+ <emphasis>spooling directory</emphasis>, a directory where
+ print jobs reside until they are printed, and where a number
+ of other spooler support files live.</para>
+
+ <para>Because of the variable nature of spooling directories, it
+ is customary to put these directories under
+ <filename>/var/spool</filename>. It is not necessary to
+ backup the contents of spooling directories, either.
+ Recreating them is as simple as running <citerefentry>
+ <refentrytitle>mkdir</refentrytitle></citerefentry>.</para>
+
+ <para>It is also customary to make the directory with a name
+ that is identical to the name of the printer, as shown below:</para>
+
+ <informalexample>
+ <screen>&prompt.root; <userinput>mkdir /var/spool/<replaceable>printer-name</replaceable></userinput></screen>
+ </informalexample>
+
+ <para>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 will do this for our two example printers
+ <literal>rattan</literal> and <literal>bamboo</literal>:</para>
+
+ <informalexample>
+ <screen>&prompt.root; <userinput>mkdir /var/spool/lpd</userinput>
+&prompt.root; <userinput>mkdir /var/spool/lpd/rattan</userinput>
+&prompt.root; <userinput>mkdir /var/spool/lpd/bamboo</userinput></screen>
+ </informalexample>
+
+ <note>
+ <para>If you are concerned about the privacy of jobs that
+ users print, you might want to protect the spooling
+ directory so it is 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 will do this for our example printers:</para>
+
+
+ <informalexample>
+ <screen>&prompt.root; <userinput>chown daemon.daemon /var/spool/lpd/rattan</userinput>
+&prompt.root; <userinput>chown daemon.daemon /var/spool/lpd/bamboo</userinput>
+&prompt.root; <userinput>chmod 770 /var/spool/lpd/rattan</userinput>
+&prompt.root; <userinput>chmod 770 /var/spool/lpd/bamboo</userinput></screen>
+ </informalexample>
+ </note>
+
+ <para>Finally, you need to tell LPD about these directories
+ using the <filename>/etc/printcap</filename> file. You
+ specify the pathname of the spooling directory with the
+ <literal>sd</literal> capability:</para>
+
+ <programlisting>
+#
+# /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:</programlisting>
+
+ <para>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.</para>
+
+ <para>If you do not specify a spooling directory with <literal>sd</literal>, the spooling system will use
+ <filename>/var/spool/lpd</filename> as a default.</para>
+
+ </sect4>
+
+ <sect4 id="printing-device">
+ <title>Identifying the Printer Device</title>
+
+ <para>In section <xref linkend="printing-dev-ports"
+ remap="Adding /dev Entries for the Ports">, we identified
+ which entry in the <filename>/dev</filename> 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).</para>
+
+ <para>List the <filename>/dev</filename> entry pathname in the
+ <filename>/etc/printcap</filename> file using the <literal>lp</literal> capability.</para>
+
+ <para>In our running example, let us assume that <hostid>rattan</hostid> is on the first parallel port,
+ and <hostid>bamboo</hostid> is on a sixth serial
+ port; here are the additions to
+ <filename>/etc/printcap</filename>:</para>
+
+ <programlisting>
+#
+# /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:</programlisting>
+
+ <para>If you do not specify the <literal>lp</literal>
+ capability for a printer in your
+ <filename>/etc/printcap</filename> file, LPD uses
+ <filename>/dev/lp</filename> as a default.
+ <filename>/dev/lp</filename> currently does not exist in
+ FreeBSD.</para>
+
+ <para>If the printer you are installing is connected to a
+ parallel port, skip to the section <xref
+ linkend="printing-textfilter" remap="Installing the
+ Text Filter">. Otherwise, be sure to follow the
+ instructions in the next section.</para>
+
+ </sect4>
+
+ <sect4 id="printing-commparam">
+ <title>Configuring Spooler Communication Parameters</title>
+
+ <para>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:</para>
+
+ <itemizedlist>
+
+ <listitem>
+ <para>It lets you try different communication parameters
+ by simply editing the <filename>/etc/printcap</filename>
+ file; you do not have to recompile the filter program.</para>
+ </listitem>
+
+ <listitem>
+ <para>It enables the spooling system to use the same
+ filter program for multiple printers which may have
+ different serial communication settings.</para>
+ </listitem>
+
+ </itemizedlist>
+
+
+ <para>The following <filename>/etc/printcap</filename>
+ capabilities control serial communication parameters of the
+ device listed in the <literal>lp</literal>
+ capability:</para>
+
+ <variablelist>
+ <varlistentry><term><literal>br#<replaceable>bps-rate</replaceable></literal></term>
+ <listitem>
+ <para>Sets the communications speed of the device to
+ <replaceable>bps-rate</replaceable>, where
+ <replaceable>bps-rate</replaceable> can be 50, 75,
+ 110, 134, 150, 200, 300, 600, 1200, 1800, 2400, 4800,
+ 9600, 19200, or 38400 bits-per-second.</para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry><term><literal>fc#<replaceable>clear-bits</replaceable></literal></term>
+
+ <listitem>
+ <para>Clears the flag bits
+ <replaceable>clear-bits</replaceable> in the
+ <replaceable>sgttyb</replaceable> structure after opening
+ the device.</para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry><term><literal>fs#<replaceable>set-bits</replaceable></literal></term>
+
+ <listitem>
+ <para>Sets the flag bits
+ <replaceable>set-bits</replaceable> in the
+ <replaceable>sgttyb</replaceable> structure.</para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry><term><literal>xc#<replaceable>clear-bits</replaceable></literal></term>
+
+ <listitem>
+ <para>Clears local mode bits <replaceable>clear-bits</replaceable> after opening the
+ device.</para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry><term><literal>xs#<replaceable>set-bits</replaceable></literal></term>
+
+ <listitem>
+ <para>Sets local mode bits <replaceable>set-bits</replaceable>.</para>
+
+ </listitem>
+ </varlistentry>
+ </variablelist>
+
+ <para>For more information on the bits for the
+ <literal>fc</literal>, <literal>fs</literal>, <literal>xc</literal>,
+ and <literal>xs</literal> capabilities, see the
+ file
+ <filename>/usr/include/sys/ioctl_compat.h</filename>.</para>
+
+ <para>When LPD opens the device specified by the <literal>lp</literal> capability, it reads the flag bits in
+ the <literal>sgttyb</literal> structure; it clears
+ any bits in the <literal>fc</literal> capability,
+ then sets bits in the <literal>fs</literal>
+ capability, then applies the resultant setting. It does the
+ same for the local mode bits as well.</para>
+
+ <para>Let us add to our example printer on the sixth serial
+ port. We will set the bps rate to 38400. For the flag bits,
+ we will set the TANDEM, ANYP, LITOUT, FLUSHO, and PASS8 flags.
+ For the local mode bits, we will set the LITOUT and PASS8
+ flags:</para>
+
+ <programlisting>
+bamboo|ps|PS|S|panasonic|Panasonic KX-P4455 PostScript v51.4:\
+ :sh:sd=/var/spool/lpd/bamboo:\
+ :lp=/dev/ttyd5:fs#0x82000c1:xs#0x820:</programlisting>
+
+ </sect4>
+
+ <sect4 id="printing-textfilter">
+ <title>Installing the Text Filter</title>
+
+ <para>We are now ready to tell LPD what text filter to use to
+ send jobs to the printer. A <emphasis>text filter</emphasis>,
+ also known as an <emphasis>input filter</emphasis>, 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 <literal>lp</literal> capability. The filter is expected
+ to read the job from standard input, perform 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 <xref
+ linkend="printing-advanced-filters"
+ remap="Filters">.</para>
+
+ <para>For our simple printer setup, the text filter can be a
+ small shell script that just executes
+ <command>/bin/cat</command> to send the job to the printer.
+ FreeBSD comes with another filter called <filename>lpf</filename> 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 <command>lpf</command> is described in detail in section
+ <xref linkend="printing-advanced-lpf" remap="lpf: a
+ Text Filter">.</para>
+
+ <para>First, let us make the shell script
+ <filename>/usr/local/libexec/if-simple</filename> be a simple
+ text filter. Put the following text into that file with your
+ favorite text editor:</para>
+
+ <programlisting>
+#!/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 &amp;&amp; exit 0
+exit 2</programlisting>
+ <para>Make the file executable:</para>
+
+ <informalexample>
+ <screen>&prompt.root; <userinput>chmod 555 /usr/local/libexec/if-simple</userinput></screen>
+ </informalexample>
+
+ <para>And then tell LPD to use it by specifying it with the
+ <literal>if</literal> capability in
+ <filename>/etc/printcap</filename>. We will add it to the two
+ printers we have so far in the example
+ <filename>/etc/printcap</filename>:</para>
+
+ <programlisting>
+#
+# /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:</programlisting>
+
+ </sect4>
+
+ <sect4 id="printing-trying">
+ <title>Trying It Out</title>
+
+ <para>You have reached the end of the simple LPD setup.
+ Unfortunately, congratulations are not quite yet in order,
+ since we still have 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 <citerefentry>
+ <refentrytitle>lpr</refentrytitle></citerefentry>,
+ which submits a job for printing.</para>
+
+ <para>You can combine <citerefentry>
+ <refentrytitle>lpr</refentrytitle></citerefentry>
+ with the <citerefentry>
+ <refentrytitle>lptest</refentrytitle></citerefentry> program, introduced in section <xref linkend="printing-testing"
+ remap="Checking Printer Communications"> to generate some
+ test text.</para>
+
+ <para><emphasis>To test the simple LPD
+ setup:</emphasis></para>
+
+ <para>Type:</para>
+
+ <informalexample>
+ <screen>&prompt.root; <userinput>lptest 20 5 | lpr -P<replaceable>printer-name</replaceable></userinput></screen>
+ </informalexample>
+
+ <para>Where <replaceable>printer-name</replaceable> is a the name of a printer
+ (or an alias) specified in <filename>/etc/printcap</filename>.
+ To test the default printer, type <citerefentry>
+ <refentrytitle>lpr</refentrytitle></citerefentry>
+ without any <option>-P</option> argument. Again, if you are
+ testing a printer that expects PostScript, send a PostScript
+ program in that language instead of using <citerefentry>
+ <refentrytitle>lptest</refentrytitle></citerefentry>. You
+ can do so by putting the program in a file and typing <command>lpr <replaceable>file</replaceable></command>.</para>
+
+ <para>For a PostScript printer, you should get the results of
+ the program. If you are using <citerefentry>
+ <refentrytitle>lptest</refentrytitle></citerefentry>, then your results should look like the following:</para>
+
+ <programlisting>
+!"#$%&amp;'()*+,-./01234
+"#$%&amp;'()*+,-./012345
+#$%&amp;'()*+,-./0123456
+$%&amp;'()*+,-./01234567
+%&amp;'()*+,-./012345678</programlisting>
+
+ <para>To further test the printer, try downloading larger
+ programs (for language-based printers) or running <citerefentry>
+ <refentrytitle>lptest</refentrytitle></citerefentry> with different arguments. For example, <command>lptest 80 60</command> will produce 60 lines of 80 characters each.</para>
+
+ <para>If the printer did not work, see the next section, <xref
+ linkend="printing-troubleshooting"
+ remap="Troubleshooting">.</para>
+
+ </sect4>
+
+ <sect4 id="printing-troubleshooting">
+ <title>Troubleshooting</title>
+
+ <para>After performing the simple test with <citerefentry>
+ <refentrytitle>lptest</refentrytitle></citerefentry>, you
+ might have gotten one of the following results instead of the
+ correct printout:</para>
+
+ <variablelist>
+ <varlistentry><term>It worked, after awhile; or, it did not
+ eject a full sheet.</term>
+ <listitem>
+ <para>The printer printed the above, but it sat for
+ awhile and did nothing. In fact, you might have
+ needed to press a PRINT REMAINING or FORM FEED button
+ on the printer to get any results to appear.</para>
+
+ <para>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
+ is also useful to make sure each print job ends on a
+ full sheet, so the next job does not start somewhere
+ on the middle of the last page of the previous
+ job.</para>
+
+ <para>The following replacement for the shell script
+ <filename>/usr/local/libexec/if-simple</filename>
+ prints a form feed after it sends the job to the
+ printer:</para>
+
+ <programlisting>
+#!/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 &amp;&amp; printf "\f" &amp;&amp; exit 0
+exit 2</programlisting>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry><term>It produced the &ldquo;staircase
+ effect.&rdquo;</term>
+
+ <listitem>
+ <para>You got the following on paper:</para>
+
+ <programlisting>
+!"#$%&amp;'()*+,-./01234
+ "#$%&amp;'()*+,-./012345
+ #$%&amp;'()*+,-./0123456</programlisting>
+ <para>You have become another victim of
+ the <emphasis>staircase effect</emphasis>, 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 <emphasis>and</emphasis> ASCII code 13
+ (the carriage return or CR). Many printers use the
+ MS-DOS convention for representing new-lines.</para>
+
+ <para>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 is what the
+ carriage return is for: to move the location of the
+ next character to print to the left edge of the
+ paper.</para>
+
+
+ <para>Here is what FreeBSD wants your printer to
+ do:</para>
+
+ <informaltable>
+ <tgroup cols="2">
+ <tbody>
+ <row>
+ <entry>Printer received CR</entry>
+ <entry>Printer prints CR</entry>
+ </row>
+
+ <row>
+ <entry>Printer received LF</entry>
+ <entry>Printer prints CR + LF</entry>
+ </row>
+ </tbody>
+ </tgroup>
+ </informaltable>
+
+ <para>Here are some ways to achieve this:</para>
+ <itemizedlist>
+
+ <listitem>
+ <para>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.</para>
+
+ <note>
+ <para>If you boot your system into other
+ operating systems besides FreeBSD, you may
+ have to <emphasis>reconfigure</emphasis> 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.</para>
+ </note>
+ </listitem>
+
+ <listitem>
+ <para>Have FreeBSD's serial line driver
+ automatically convert LF to CR+LF. Of course,
+ this works with printers on serial ports
+ <emphasis>only</emphasis>. To enable this
+ feature, set the CRMOD bit in <literal>fs</literal> capability in the
+ <filename>/etc/printcap</filename> file for the
+ printer.</para>
+ </listitem>
+
+ <listitem>
+ <para>Send an <emphasis>escape code</emphasis> 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.</para>
+
+ <para>Here is 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.</para>
+
+ <programlisting>
+#!/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&amp;k2G" &amp;&amp; cat &amp;&amp; printf "\f" &amp;&amp; exit 0
+exit 2</programlisting>
+
+ <para>Here is an example
+ <filename>/etc/printcap</filename> from a host
+ called orchid. It has a single printer attached
+ to its first parallel port, a Hewlett Packard
+ LaserJet 3Si named <hostid>teak</hostid>. It is using the
+ above script as its text filter:</para>
+
+ <programlisting>
+#
+# /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:</programlisting>
+ </listitem>
+
+ </itemizedlist>
+
+ </listitem>
+ </varlistentry>
+
+ <varlistentry><term>It overprinted each line.</term>
+
+ <listitem>
+ <para>The printer never advanced a line. All of the
+ lines of text were printed on top of each other on one
+ line.</para>
+
+ <para>This problem is the &ldquo;opposite&rdquo; 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.</para>
+
+ <para>Use the printer's configuration switches or
+ control panel to enforce the following interpretation
+ of LF and CR characters:</para>
+
+ <informaltable>
+ <tgroup cols="2">
+ <thead>
+ <row>
+ <entry>Printer receives</entry>
+ <entry>Printer prints</entry>
+ </row>
+ </thead>
+
+ <tbody>
+ <row>
+ <entry>CR</entry>
+ <entry>CR</entry>
+ </row>
+
+ <row>
+ <entry>LF</entry>
+ <entry>CR + LF</entry>
+ </row>
+ </tbody>
+ </tgroup>
+ </informaltable>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry><term>The printer lost characters.</term>
+
+ <listitem>
+ <para>While printing, the printer did not print a few
+ characters in each line. The problem might have
+ gotten worse as the printer ran, losing more and more
+ characters.</para>
+
+ <para>The problem is that the printer cannot keep up
+ with the speed at which the computer sends data over a
+ serial line. (This problem should not occur with
+ printers on parallel ports.) There are two ways to
+ overcome the problem:</para>
+ <itemizedlist>
+
+ <listitem>
+ <para>If the printer supports XON/XOFF flow
+ control, have FreeBSD use it by specifying the
+ TANDEM bit in the <literal>fs</literal> capability.</para>
+ </listitem>
+
+ <listitem>
+ <para>If the printer supports carrier flow
+ control, specify the MDMBUF bit in the <literal>fs</literal> capability. Make sure
+ the cable connecting the printer to the computer
+ is correctly wired for carrier flow control.</para>
+ </listitem>
+
+ <listitem>
+ <para>If the printer does not support any flow
+ control, use some combination of the NLDELAY,
+ TBDELAY, CRDELAY, VTDELAY, and BSDELAY bits in
+ the <literal>fs</literal> capability
+ to add appropriate delays to the stream of data
+ sent to the printer.</para>
+ </listitem>
+
+ </itemizedlist>
+
+ </listitem>
+ </varlistentry>
+
+ <varlistentry><term>It printed garbage.</term>
+
+ <listitem>
+ <para>The printer printed what appeared to be random
+ garbage, but not the desired text.</para>
+
+ <para>This is usually another symptom of incorrect
+ communications parameters with a serial printer.
+ Double-check the bps rate in the <literal>br</literal> capability, and the parity
+ bits in the <literal>fs</literal> and
+ <literal>fc</literal> capabilities; make
+ sure the printer is using the same settings as
+ specified in the <filename>/etc/printcap</filename>
+ file.</para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry><term>Nothing happened.</term>
+
+ <listitem>
+ <para>If nothing happened, the problem is probably
+ within FreeBSD and not the hardware. Add the log file
+ (<literal>lf</literal>) capability to the
+ entry for the printer you are debugging in the
+ <filename>/etc/printcap</filename> file. For example,
+ here is the entry for <literal>rattan</literal>, with
+ the <literal>lf</literal> capability:</para>
+
+ <programlisting>
+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</programlisting>
+ <para>Then, try printing again. Check
+ the log file (in our example,
+ <filename>/var/log/rattan.log</filename>) to see any
+ error messages that might appear. Based on the
+ messages you see, try to correct the problem.</para>
+
+ <para>If you do not specify a <literal>lf</literal> capability, LPD uses
+ <filename>/dev/console</filename> as a default.</para>
+
+ </listitem>
+ </varlistentry>
+ </variablelist>
+
+ </sect4>
+ </sect3>
+ </sect2>
+ </sect1>
+
+ <sect1 id="printing-using">
+ <title>Using Printers</title>
+
+ <para>This section tells you how to use printers you have setup with
+ FreeBSD. Here is an overview of the user-level commands:</para>
+
+ <variablelist>
+ <varlistentry><term><citerefentry>
+ <refentrytitle>lpr</refentrytitle></citerefentry></term>
+ <listitem>
+ <para>Print jobs</para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry><term><citerefentry>
+ <refentrytitle>lpq</refentrytitle></citerefentry></term>
+
+ <listitem>
+ <para>Check printer queues</para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry><term><citerefentry>
+ <refentrytitle>lprm</refentrytitle></citerefentry></term>
+
+ <listitem>
+ <para>Remove jobs from a printer's queue</para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+
+ <para>There is also an administrative command, <citerefentry>
+ <refentrytitle>lpc</refentrytitle></citerefentry>,
+ described in the section <xref linkend="printing-lpc"
+ remap="Administrating the
+ LPD Spooler">, used to control printers and their queues.</para>
+
+ <para>All three of the commands <citerefentry>
+ <refentrytitle>lpr</refentrytitle></citerefentry>, <citerefentry>
+ <refentrytitle>lprm</refentrytitle></citerefentry>, and
+ <citerefentry>
+ <refentrytitle>lpq</refentrytitle></citerefentry>
+ accept an option <option>-P <replaceable>printer-name</replaceable></option> to specify on which
+ printer/queue to operate, as listed in the
+ <filename>/etc/printcap</filename> file. This enables you to
+ submit, remove, and check on jobs for various printers. If you do
+ not use the <option>-P</option> option, then these commands use the
+ printer specified in the <envar>PRINTER</envar> environment variable. Finally, if
+ you do not have a <envar>PRINTER</envar> environment variable, these commands
+ default to the printer named <literal>lp</literal>.</para>
+
+ <para>Hereafter, the terminology <emphasis>default printer</emphasis>
+ means the printer named in the <envar>PRINTER</envar> environment variable, or the
+ printer named <literal>lp</literal> when there is no
+ <envar>PRINTER</envar> environment variable.</para>
+
+
+ <sect2 id="printing-lpr">
+ <title>Printing Jobs</title>
+
+ <para>To print files, type:</para>
+
+ <informalexample>
+ <screen>&prompt.user; <userinput>lpr <replaceable>filename</replaceable> <replaceable>...</replaceable></userinput></screen>
+ </informalexample>
+
+ <para>This prints each of the listed files to the
+ default printer. If you list no files, <citerefentry>
+ <refentrytitle>lpr</refentrytitle></citerefentry> reads
+ data to print from standard input. For example, this command
+ prints some important system files:</para>
+
+ <informalexample>
+ <screen>&prompt.user; <userinput>lpr /etc/host.conf /etc/hosts.equiv</userinput></screen>
+ </informalexample>
+
+ <para>To select a specific printer, type:</para>
+
+ <informalexample>
+ <screen>&prompt.user; <userinput>lpr -P <replaceable>printer-name</replaceable> <replaceable>filename</replaceable> <replaceable>...</replaceable></userinput></screen>
+ </informalexample>
+
+ <para>This example prints a long listing of the
+ current directory to the printer named <literal>rattan</literal>:</para>
+
+ <informalexample>
+ <screen>&prompt.user; <userinput>ls -l | lpr -P rattan</userinput></screen>
+ </informalexample>
+
+ <para>Because no files were listed for the
+ <citerefentry>
+ <refentrytitle>lpr</refentrytitle></citerefentry>
+ command, <command>lpr</command> read the data to print
+ from standard input, which was the output of the <command>ls
+ -l</command> command.</para>
+
+ <para>The <citerefentry>
+ <refentrytitle>lpr</refentrytitle></citerefentry> 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 <xref
+ linkend="printing-lpr-options"
+ remap="Printing Options">.</para>
+
+ </sect2>
+
+ <sect2 id="printing-lpq">
+ <title>Checking Jobs</title>
+
+ <para>When you print with <citerefentry>
+ <refentrytitle>lpr</refentrytitle></citerefentry>, the
+ data you wish to print is put together in a package called a
+ &ldquo;print job&rdquo;, 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.</para>
+
+ <para>To display the queue for the default printer, type
+ <citerefentry>
+ <refentrytitle>lpq</refentrytitle></citerefentry>. For a
+ specific printer, use the <option>-P</option> option. For
+ example, the command
+
+ <informalexample>
+ <screen>&prompt.user; <userinput>lpq -P bamboo</userinput></screen>
+ </informalexample> shows the queue for the printer named <hostid>bamboo</hostid>. Here is an example of the output of
+ the <command>lpq</command> command:</para>
+
+ <informalexample>
+ <screen>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</screen>
+ </informalexample>
+
+ <para>This shows three jobs in the queue for
+ <literal>bamboo</literal>. The first job, submitted by
+ user kelly, got assigned &ldquo;job number&rdquo; 9. Every
+ job for a printer gets a unique job number. Most of the time you
+ can ignore the job number, but you will need it if you want to
+ cancel the job; see section
+ <xref linkend="printing-lprm" remap="Removing Jobs"> for
+ details.</para>
+
+ <para>Job number nine consists of two files; multiple files given on
+ the <citerefentry>
+ <refentrytitle>lpr</refentrytitle></citerefentry> command
+ line are treated as part of a single job. It is the currently
+ active job (note the word <literal>active</literal>
+ under the &ldquo;Rank&rdquo; column), which means the printer should be
+ currently printing that job. The second job consists of data
+ passed as the standard input to the</para>
+
+ <para><citerefentry>
+ <refentrytitle>lpr</refentrytitle></citerefentry>
+ command. The third job came from user mary; it is a much larger
+ job. The pathname of the files she's trying to print is too long
+ to fit, so the <citerefentry>
+ <refentrytitle>lpq</refentrytitle></citerefentry> command
+ just shows three dots.</para>
+
+ <para>The very first line of the output from <citerefentry>
+ <refentrytitle>lpq</refentrytitle></citerefentry> is also
+ useful: it tells what the printer is currently doing (or at least
+ what LPD thinks the printer is doing).</para>
+
+ <para>The <citerefentry>
+ <refentrytitle>lpq</refentrytitle></citerefentry> command
+ also support a <option>-l</option> option to generate a detailed
+ long listing. Here is an example of <command>lpq -l</command>:</para>
+
+ <informalexample>
+ <screen>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</screen>
+ </informalexample>
+
+ </sect2>
+
+ <sect2 id="printing-lprm">
+ <title>Removing Jobs</title>
+
+ <para>If you change your mind about printing a job, you can remove
+ the job from the queue with the <citerefentry>
+ <refentrytitle>lprm</refentrytitle></citerefentry>
+ command. Often, you can even use <citerefentry>
+ <refentrytitle>lprm</refentrytitle></citerefentry> to
+ remove an active job, but some or all of the job might still get
+ printed.</para>
+
+ <para>To remove a job from the default printer, first use
+ <citerefentry>
+ <refentrytitle>lpq</refentrytitle></citerefentry> to find
+ the job number. Then type:</para>
+
+ <informalexample>
+ <screen>&prompt.user; <userinput>lprm <replaceable>job-number</replaceable></userinput></screen>
+ </informalexample>
+
+ <para>To remove the job from a specific printer, add
+ the <option>-P</option> option. The following command removes job
+ number 10 from the queue for the printer
+ <hostid>bamboo</hostid>:</para>
+
+ <informalexample>
+ <screen>&prompt.user; <userinput>lprm -P bamboo 10</userinput></screen>
+ </informalexample>
+
+ <para>The <citerefentry>
+ <refentrytitle>lprm</refentrytitle></citerefentry>
+ command has a few shortcuts:</para>
+
+ <variablelist>
+ <varlistentry><term>lprm -</term>
+ <listitem>
+ <para>Removes all jobs (for the default printer) belonging
+ to you.</para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry><term>lprm <replaceable>user</replaceable></term>
+
+ <listitem>
+ <para>Removes all jobs (for the default printer) belonging
+ to <replaceable>user</replaceable>. The superuser can
+ remove other users' jobs; you can remove only your own
+ jobs.</para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry><term>lprm</term>
+
+ <listitem>
+ <para>With no job number, user name, or
+ <option>-</option> appearing on the command line,
+ <citerefentry>
+ <refentrytitle>lprm</refentrytitle></citerefentry> removes the currently active job on the default printer, if it belongs to you. The superuser can remove any active job.</para>
+
+ </listitem>
+ </varlistentry>
+ </variablelist>
+
+ <para>Just use the <option>-P</option> 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 <literal>rattan</literal>:</para>
+
+ <informalexample>
+ <screen>&prompt.user; <userinput>lprm -P rattan -</userinput></screen>
+ </informalexample>
+
+ <note>
+ <para>If you are working in a networked
+ environment, <citerefentry>
+ <refentrytitle>lprm</refentrytitle></citerefentry>
+ 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:</para>
+
+ <informalexample>
+ <screen>&prompt.user; <userinput>lpr -P rattan myfile</userinput>
+&prompt.user; <userinput>rlogin orchid</userinput>
+&prompt.user; <userinput>lpq -P rattan</userinput>
+Rank Owner Job Files Total Size
+active seeyan 12 ... 49123 bytes
+2nd kelly 13 myfile 12 bytes
+&prompt.user; <userinput>lprm -P rattan 13</userinput>
+rose: Permission denied
+&prompt.user; <userinput>logout</userinput>
+&prompt.user; <userinput>lprm -P rattan 13</userinput>
+dfA013rose dequeued
+cfA013rose dequeued
+ </screen>
+ </informalexample>
+ </note>
+ </sect2>
+
+ <sect2 id="printing-lpr-options">
+ <title>Beyond Plain Text: Printing Options</title>
+
+ <para>The <citerefentry>
+ <refentrytitle>lpr</refentrytitle></citerefentry> 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.</para>
+
+
+ <sect3 id="printing-lpr-options-format">
+ <title>Formatting and Conversion Options</title>
+
+ <para>The following <citerefentry>
+ <refentrytitle>lpr</refentrytitle></citerefentry>
+ options control formatting of the files in the job. Use these
+ options if the job does not contain plain text or if you want
+ plain text formatted through the <citerefentry>
+ <refentrytitle>pr</refentrytitle></citerefentry>
+ utility.</para>
+
+ <para>For example, the following command prints a DVI file (from
+ the TeX typesetting system) named
+ <filename>fish-report.dvi</filename> to the printer named
+ <literal>bamboo</literal>:</para>
+ <informalexample>
+ <screen>&prompt.user; <userinput>lpr -P bamboo -d fish-report.dvi</userinput></screen>
+ </informalexample>
+
+ <para>These options apply to every file in the job,
+ so you cannot 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.</para>
+
+ <note>
+ <para>All of these options except <option>-p</option> and
+ <option>-T</option> require conversion filters installed for
+ the destination printer. For example, the <option>-d</option>
+ option requires the DVI conversion filter. Section <xref
+ linkend="printing-advanced-convfilters" remap="Conversion
+ Filters"> gives details.</para>
+ </note>
+
+
+ <variablelist>
+ <varlistentry><term><option>-c</option></term>
+ <listitem>
+ <para>Print cifplot files.</para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry><term><option>-d</option></term>
+
+ <listitem>
+ <para>Print DVI files.</para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry><term><option>-f</option></term>
+
+ <listitem>
+ <para>Print FORTRAN text files.</para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry><term><option>-g</option></term>
+
+ <listitem>
+ <para>Print plot data.</para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry><term><option>-i
+ <replaceable>number</replaceable></option></term>
+
+ <listitem>
+ <para>Indent the output by <replaceable>number</replaceable> columns; if you omit
+ <replaceable>number</replaceable>, indent by 8
+ columns. This option works only with certain conversion
+ filters.</para>
+
+ <note>
+ <para>Do not put any space between the
+ <option>-i</option> and the number.</para>
+ </note>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry><term><option>-l</option></term>
+
+ <listitem>
+ <para>Print literal text data, including control
+ characters.</para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry><term><option>-n</option></term>
+
+ <listitem>
+ <para>Print ditroff (device independent troff)
+ data.</para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry><term>-p</term>
+
+ <listitem>
+ <para>Format plain text with <citerefentry>
+ <refentrytitle>pr</refentrytitle></citerefentry>
+ before printing. See <citerefentry><refentrytitle>pr</refentrytitle><manvolnum>1</manvolnum></citerefentry> for more information.</para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry><term><option>-T
+ <replaceable>title</replaceable></option></term>
+
+ <listitem>
+ <para>Use <replaceable>title</replaceable> on the
+ <citerefentry>
+ <refentrytitle>pr</refentrytitle></citerefentry>
+ header instead of the file name. This option has effect
+ only when used with the <option>-p</option>
+ option.</para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry><term><option>-t</option></term>
+
+ <listitem>
+ <para>Print troff data.</para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry><term><option>-v</option></term>
+
+ <listitem>
+ <para>Print raster data.</para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+
+
+ <para>Here is an example: this command prints a nicely formatted
+ version of the <citerefentry>
+ <refentrytitle>ls</refentrytitle></citerefentry> manual
+ page on the default printer:</para>
+
+ <informalexample>
+ <screen>&prompt.user; <userinput>zcat /usr/share/man/man1/ls.1.gz | troff -t -man | lpr -t</userinput></screen>
+ </informalexample>
+
+ <para>The <citerefentry>
+ <refentrytitle>zcat</refentrytitle></citerefentry>
+ command uncompresses the source of the</para>
+
+ <para><citerefentry>
+ <refentrytitle>ls</refentrytitle></citerefentry> manual
+ page and passes it to the <citerefentry>
+ <refentrytitle>troff</refentrytitle></citerefentry>
+ command, which formats that source and makes GNU troff output
+ and passes it to <citerefentry>
+ <refentrytitle>lpr</refentrytitle></citerefentry>,
+ which submits the job to the LPD spooler. Because we used the
+ <option>-t</option> option to</para>
+
+ <para><citerefentry>
+ <refentrytitle>lpr</refentrytitle></citerefentry>, the
+ spooler will convert the GNU troff output into a format the
+ default printer can understand when it prints the job.</para>
+
+ </sect3>
+
+ <sect3 id="printing-lpr-options-job-handling">
+ <title>Job Handling Options</title>
+
+ <para>The following options to <citerefentry>
+ <refentrytitle>lpr</refentrytitle></citerefentry> tell
+ LPD to handle the job specially:</para>
+
+
+ <variablelist>
+ <varlistentry><term>-# <replaceable>copies</replaceable></term>
+ <listitem>
+ <para>Produce a number of <replaceable>copies</replaceable> 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 <xref
+ linkend="printing-advanced-restricting-copies"
+ remap="Restricting Multiple Copies">.</para>
+
+ <para>This example prints three copies of
+ <filename>parser.c</filename> followed by three copies
+ of <filename>parser.h</filename> to the default
+ printer:</para>
+
+ <informalexample>
+ <screen>&prompt.user; <userinput>lpr -#3 parser.c parser.h</userinput></screen>
+ </informalexample>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry><term>-m</term>
+
+ <listitem>
+ <para>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.</para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry><term>-s</term>
+
+ <listitem>
+ <para>Do not copy the files to the spooling directory, but
+ make symbolic links to them instead.</para>
+
+ <para>If you are 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 will not have to copy each
+ and every byte of your job to the spooling
+ directory.</para>
+
+ <para>There is a drawback, though: since LPD will refer to
+ the original files directly, you cannot modify or remove
+ them until they have been printed.</para>
+
+ <note>
+ <para>If you are printing to a remote printer, LPD will
+ eventually have to copy files from the local host to
+ the remote host, so the <option>-s</option> option
+ will save space only on the local spooling directory,
+ not the remote. It is still useful, though.</para>
+ </note>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry><term>-r</term>
+
+ <listitem>
+ <para>Remove the files in the job after copying them to
+ the spooling directory, or after printing them with the
+ <option>-s</option> option. Be careful with this
+ option!</para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+
+
+ </sect3>
+
+ <sect3 id="printing-lpr-options-misc">
+ <title>Header Page Options</title>
+
+ <para>These options to <citerefentry>
+ <refentrytitle>lpr</refentrytitle></citerefentry>
+ 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 <xref
+ linkend="printing-advanced-header-pages" remap="Header Pages">
+ for information about setting up header pages.</para>
+
+
+ <variablelist>
+ <varlistentry><term>-C <replaceable>text</replaceable></term>
+ <listitem>
+ <para>Replace the hostname on the header page with
+ <replaceable>text</replaceable>. The hostname is
+ normally the name of the host from which the job was
+ submitted.</para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry><term>-J <replaceable>text</replaceable></term>
+
+ <listitem>
+ <para>Replace the job name on the header page with
+ <replaceable>text</replaceable>. The job name is
+ normally the name of the first file of the job, or
+ <filename>stdin</filename> if you are printing standard input.</para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry><term>-h</term>
+
+ <listitem>
+ <para>Do not print any header page.</para>
+
+ <note>
+ <para>At some sites, this option may have no effect due
+ to the way header pages are generated. See <xref
+ linkend="printing-advanced-header-pages" remap="Header
+ Pages"> for details.</para>
+ </note>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+
+
+ </sect3>
+ </sect2>
+
+ <sect2 id="printing-lpc">
+ <title>Administrating Printers</title>
+
+ <para>As an administrator for your printers, you have had to
+ install, set up, and test them. Using the <citerefentry>
+ <refentrytitle>lpc</refentrytitle></citerefentry>
+ command, you can interact with your printers in yet more ways.
+ With <citerefentry>
+ <refentrytitle>lpc</refentrytitle></citerefentry>, you
+ can</para>
+
+
+ <itemizedlist>
+
+ <listitem>
+ <para>Start and stop the printers</para>
+ </listitem>
+
+ <listitem>
+ <para>Enable and disable their queues</para>
+ </listitem>
+
+ <listitem>
+ <para>Rearrange the order of the jobs in each queue.</para>
+ </listitem>
+
+ </itemizedlist>
+
+
+ <para>First, a note about terminology: if a printer is
+ <emphasis>stopped</emphasis>, it will not print anything in its
+ queue. Users can still submit jobs, which will wait in the queue
+ until the printer is <emphasis>started</emphasis> or the queue is
+ cleared.</para>
+
+ <para>If a queue is <emphasis>disabled</emphasis>, no user (except
+ root) can submit jobs for the printer. An
+ <emphasis>enabled</emphasis> queue allows jobs to be submitted. A
+ printer can be <emphasis>started</emphasis> for a disabled queue,
+ in which case it will continue to print jobs in the queue until
+ the queue is empty.</para>
+
+ <para>In general, you have to have root privileges to use the <citerefentry>
+ <refentrytitle>lpc</refentrytitle></citerefentry>
+ command. Ordinary users can use the <citerefentry>
+ <refentrytitle>lpc</refentrytitle></citerefentry> command
+ to get printer status and to restart a hung printer only.</para>
+
+ <para>Here is a summary of the <citerefentry>
+ <refentrytitle>lpc</refentrytitle></citerefentry>
+ commands. Most of the commands takes a <replaceable>printer-name</replaceable> argument to tell on which
+ printer to operate. You can use <literal>all</literal>
+ for the <replaceable>printer-name</replaceable> to mean all
+ printers listed in <filename>/etc/printcap</filename>.</para>
+
+
+ <variablelist>
+ <varlistentry><term><command>abort
+ <replaceable>printer-name</replaceable></command></term>
+ <listitem>
+ <para>Cancel the current job and stop the printer. Users
+ can still submit jobs if the queue's enabled.</para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry><term><command>clean
+ <replaceable>printer-name</replaceable></command></term>
+
+ <listitem>
+ <para>Remove old files from the printer's spooling
+ directory. Occasionally, the files that make up a job are
+ not properly removed by LPD, particularly if there have
+ been errors during printing or a lot of administrative
+ activity. This command finds files that do not belong in
+ the spooling directory and removes them.</para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry><term><command>disable
+ <replaceable>printer-name</replaceable></command></term>
+
+ <listitem>
+ <para>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.</para>
+
+ <para>This command is useful while you are testing a new
+ printer or filter installation: disable the queue and
+ submit jobs as root. Other users will not be able to
+ submit jobs until you complete your testing and re-enable
+ the queue with the <command>enable</command>
+ command.</para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry><term><command>down
+ <replaceable>printer-name</replaceable>
+ <replaceable>message</replaceable></command></term>
+
+ <listitem>
+ <para>Take a printer down. Equivalent to
+ <command>disable</command> followed by
+ <command>stop</command>. The <replaceable>message</replaceable> appears as the printer's
+ status whenever a user checks the printer's queue with
+ <citerefentry>
+ <refentrytitle>lpq</refentrytitle></citerefentry>
+ or status with <command>lpc
+ status</command>.</para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry><term><command>enable
+ <replaceable>printer-name</replaceable></command></term>
+
+ <listitem>
+ <para>Enable the queue for a printer. Users can submit jobs
+ but the printer will not print anything until it is
+ started.</para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry><term><command>help
+ <replaceable>command-name</replaceable></command></term>
+
+ <listitem>
+ <para>Print help on the command
+ <replaceable>command-name</replaceable>. With no
+ <replaceable>command-name</replaceable>, print a summary of the
+ commands available.</para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry><term><command>restart
+ <replaceable>printer-name</replaceable></command></term>
+
+ <listitem>
+ <para>Start the printer. Ordinary users can use this
+ command if some extraordinary circumstance hangs LPD, but
+ they cannot start a printer stopped with either the
+ <command>stop</command> or <command>down</command> commands. The <command>restart</command> command is equivalent to
+ <command>abort</command> followed by <command>start</command>.</para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry><term><command>start
+ <replaceable>printer-name</replaceable></command></term>
+
+ <listitem>
+ <para>Start the printer. The printer will print jobs in its
+ queue.</para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry><term><command>stop
+ <replaceable>printer-name</replaceable></command></term>
+
+ <listitem>
+ <para>Stop the printer. The printer will finish the current
+ job and will not print anything else in its queue. Even
+ though the printer is stopped, users can still submit jobs
+ to an enabled queue.</para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry><term><command>topq
+ <replaceable>printer-name</replaceable>
+ <replaceable>job-or-username</replaceable></command></term>
+
+ <listitem>
+ <para>Rearrange the queue for <replaceable>printer-name</replaceable> by placing the jobs
+ with the listed <replaceable>job</replaceable> numbers
+ or the jobs belonging to <replaceable>username</replaceable> at the top of the queue.
+ For this command, you cannot use <literal>all</literal> as
+ the <replaceable>printer-name</replaceable>.</para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry><term><command>up
+ <replaceable>printer-name</replaceable></command></term>
+
+ <listitem>
+ <para>Bring a printer up; the opposite of the <command>down</command> command. Equivalent to
+ <command>start</command> followed by <command>enable</command>.</para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+
+
+ <para><citerefentry>
+ <refentrytitle>lpc</refentrytitle></citerefentry> accepts
+ the above commands on the command line. If you do not enter any
+ commands, <citerefentry>
+ <refentrytitle>lpc</refentrytitle></citerefentry> enters
+ an interactive mode, where you can enter commands until you type
+ <command>exit</command>, <command>quit</command>, or end-of-file.</para>
+
+ </sect2>
+ </sect1>
+
+ <sect1 id="printing-advanced">
+ <title>Advanced Printer Setup</title>
+
+ <para>This section describes filters for printing specially formatted
+ files, header pages, printing across networks, and restricting and
+ accounting for printer usage.</para>
+
+
+ <sect2 id="printing-advanced-filter-intro">
+ <title>Filters</title>
+
+ <para>Although LPD handles network protocols, queuing, access
+ control, and other aspects of printing, most of the
+ <emphasis>real</emphasis> work happens in the
+ <emphasis>filters</emphasis>. 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&mdash;an extremely simple one that
+ should work with most printers (section <xref
+ linkend="printing-textfilter" remap="Installing the
+ Text Filter">).</para>
+
+ <para>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 <emphasis>you</emphasis> have to provide filters
+ yourself. The good news is that many are generally available;
+ when they are not, they are usually easy to write.</para>
+
+ <para>Also, FreeBSD comes with one,
+ <filename>/usr/libexec/lpr/lpf</filename>, that works with many
+ printers that can print plain text. (It handles backspacing and
+ tabs in the file, and does accounting, but that is about all it
+ does.) There are also several filters and filter components in
+ the FreeBSD ports collection.</para>
+
+ <para>Here is what you will find in this section:</para>
+
+
+ <itemizedlist>
+
+ <listitem>
+ <para>Section <xref linkend="printing-advanced-filters"
+ remap="How Filters 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 is happening &ldquo;under
+ the hood&rdquo; 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.</para>
+ </listitem>
+
+ <listitem>
+ <para>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 cannot directly print
+ plain text. Section <xref
+ linkend="printing-advanced-if-conversion"
+ remap="Accommodating 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.</para>
+ </listitem>
+
+ <listitem>
+ <para>PostScript is a popular output format for many programs.
+ Even some people (myself included) write PostScript code
+ directly. But PostScript printers are expensive. Section
+ <xref linkend="printing-advanced-ps"
+ remap="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
+ <emphasis>non-PostScript</emphasis> printer. I recommend
+ reading this section if you do not have a PostScript
+ printer.</para>
+ </listitem>
+
+ <listitem>
+ <para>Section <xref linkend="printing-advanced-convfilters"
+ remap="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
+ <command>lpr -t</command> to print troff data, or
+ <command>lpr -d</command> to print TeX DVI data, or
+ <command>lpr -v</command> to print raster image data, and so
+ forth. I recommend reading this section.</para>
+ </listitem>
+
+ <listitem>
+ <para>Section <xref linkend="printing-advanced-of"
+ remap="Output Filters"> tells all about a not often used
+ feature of LPD: output filters. Unless you are printing
+ header pages (see <xref
+ linkend="printing-advanced-header-pages"
+ remap="Header Pages">), you can probably skip that section
+ altogether.</para>
+ </listitem>
+
+ <listitem>
+ <para>Section <xref linkend="printing-advanced-lpf"
+ remap="lpf: a Text Filter"> describes <command>lpf</command>, 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 <command>lpf</command>.</para>
+ </listitem>
+
+ </itemizedlist>
+
+
+ <sect3 id="printing-advanced-filters">
+ <title>How Filters Work</title>
+
+ <para>As mentioned before, a filter is an executable program
+ started by LPD to handle the device-dependent part of
+ communicating with the printer.</para>
+
+ <para>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 <literal>lf</literal> capability in
+ <filename>/etc/printcap</filename>, or
+ <filename>/dev/console</filename> by default).</para>
+
+ <para>Which filter LPD starts and the filter's arguments depend on
+ what is listed in the <filename>/etc/printcap</filename> file
+ and what arguments the user specified for the job on the</para>
+
+ <para><citerefentry>
+ <refentrytitle>lpr</refentrytitle></citerefentry>
+ command line. For example, if the user typed <command>lpr
+ -t</command>, LPD would start the troff filter, listed in the
+ <literal>tf</literal> capability for the destination
+ printer. If the user wanted to print plain text, it would start
+ the <literal>if</literal> filter (this is mostly
+ true:
+ see <xref linkend="printing-advanced-of" remap="Output Filters">
+ for details).</para>
+
+ <para>There are three kinds of filters you can specify in
+ <filename>/etc/printcap</filename>:</para>
+
+ <itemizedlist>
+
+ <listitem>
+ <para>The <emphasis>text filter</emphasis>, confusingly
+ called the <emphasis>input filter</emphasis> 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 is the text
+ filter's job to make sure backspaces, tabs, or other
+ special characters do not confuse the printer. If you are
+ 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:
+
+ <cmdsynopsis>
+ <command>filter-name</command>
+ <arg>-c</arg>
+ <arg choice="plain">-w<replaceable>width</replaceable></arg>
+ <arg choice="plain">-l<replaceable>length</replaceable></arg>
+ <arg choice="plain">-i<replaceable>indent</replaceable></arg>
+ <arg choice="plain">-n <replaceable>login</replaceable></arg>
+ <arg choice="plain">-h <replaceable>host</replaceable></arg>
+ <arg choice="plain"><replaceable>acct-file</replaceable></arg>
+ </cmdsynopsis> where
+
+ <variablelist>
+ <varlistentry><term><option>-c</option></term>
+ <listitem>
+ <para>appears if the job's submitted with
+ <command>lpr -l</command></para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry><term><replaceable>width</replaceable></term>
+
+ <listitem>
+ <para>is the value from the <literal>pw</literal> (page width) capability
+ specified in <filename>/etc/printcap</filename>,
+ default 132</para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry><term><replaceable>length</replaceable></term>
+
+ <listitem>
+ <para>is the value from the <literal>pl</literal> (page length) capability,
+ default 66</para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry><term><replaceable>indent</replaceable></term>
+
+ <listitem>
+ <para>is the amount of the indentation from
+ <command>lpr -i</command>, default 0</para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry><term><replaceable>login</replaceable></term>
+
+ <listitem>
+ <para>is the account name of the user printing the
+ file</para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry><term><replaceable>host</replaceable></term>
+
+ <listitem>
+ <para>is the host name from which the job was
+ submitted</para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry><term><replaceable>acct-file</replaceable></term>
+
+ <listitem>
+ <para>is the name of the accounting file from the
+ <literal>af</literal>
+ capability.</para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+
+ </para>
+ </listitem>
+
+ <listitem>
+ <para>A <emphasis>conversion filter</emphasis> converts a
+ specific file format into one the printer can render onto
+ paper. For example, ditroff typesetting data cannot 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
+ <xref linkend="printing-advanced-convfilters"
+ remap="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:
+
+ <cmdsynopsis>
+ <command>filter-name</command>
+ <arg
+ choice="plain">-x<replaceable>pixel-width</replaceable></arg>
+ <arg choice="plain">-y<replaceable>pixel-height</replaceable></arg>
+ <arg choice="plain">-n <replaceable>login</replaceable></arg>
+ <arg choice="plain">-h <replaceable>host</replaceable></arg>
+ <arg choice="plain"><replaceable>acct-file</replaceable></arg>
+ </cmdsynopsis> where <replaceable>pixel-width</replaceable> is the value from the
+ <literal>px</literal> capability (default 0)
+ and <replaceable>pixel-height</replaceable> is the
+ value from the <literal>py</literal> capability
+ (default 0).</para>
+ </listitem>
+
+ <listitem>
+ <para>The <emphasis>output filter</emphasis> is used only if
+ there is no text filter, or if header pages are enabled.
+ In my experience, output filters are rarely used. Section
+ <xref linkend="printing-advanced-of" remap="Output
+ Filters"> describe them. There are only two arguments
+ to an output filter:
+
+ <cmdsynopsis>
+ <command>filter-name</command>
+ <arg choice="plain">-w<replaceable>width</replaceable></arg>
+
+ <arg choice="plain">-l<replaceable>length</replaceable></arg>
+ </cmdsynopsis> which are identical to the text filters
+ <option>-w</option> and <option>-l</option>
+ arguments.</para>
+ </listitem>
+
+ </itemizedlist>
+
+ <para>Filters should also <emphasis>exit</emphasis> with the
+ following exit status:</para>
+
+ <variablelist>
+ <varlistentry><term>exit 0</term>
+ <listitem>
+ <para>If the filter printed the file successfully.</para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry><term>exit 1</term>
+
+ <listitem>
+ <para>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.</para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry><term>exit 2</term>
+
+ <listitem>
+ <para>If the filter failed to print the file and does not
+ want LPD to try again. LPD will throw out the
+ file.</para>
+
+ </listitem>
+ </varlistentry>
+ </variablelist>
+
+ <para>The text filter that comes with the FreeBSD release,
+ <filename>/usr/libexec/lpr/lpf</filename>, 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.</para>
+
+ <para>If you are shopping for filters, see if they are
+ 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.</para>
+
+ </sect3>
+
+ <sect3 id="printing-advanced-if-conversion">
+ <title>Accommodating Plain Text Jobs on PostScript Printers</title>
+
+ <para>If you are 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 do not need to worry about this section at all.</para>
+
+ <para>But, if you would like to send both PostScript and plain
+ text jobs to the printer, then you are 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 <literal>%!</literal> (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 are not the first
+ two characters in the file, then the filter will convert the
+ text into PostScript and print the result.</para>
+
+ <para>How do we do this?</para>
+
+ <para>If you have got a serial printer, a great way to do it is to
+ install <command>lprps</command>. <command>lprps</command> 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 <errorname>toner low</errorname> or <errorname>paper jam</errorname>). But
+ more importantly, it includes a program called <command>psif</command> which detects whether the incoming
+ job is plain text and calls <command>textps</command>
+ (another program that comes with <command>lprps</command>) to convert it to PostScript. It
+ then uses <command>lprps</command> to send the job to
+ the printer.</para>
+
+ <para><command>lprps</command> is part of the FreeBSD
+ ports collection (see <xref linkend="ports" remap="The Ports
+ Collection">). You
+ can fetch, build and install it yourself, of course. After
+ installing <command>lprps</command>, just specify the
+ pathname to the <command>psif</command> program that
+ is part of <command>lprps</command>. If you
+ installed <command>lprps</command> from the ports
+ collection, use the following in the serial PostScript printer's
+ entry in <filename>/etc/printcap</filename>:</para>
+
+ <programlisting>
+:if=/usr/local/libexec/psif:</programlisting>
+
+ <para>You should also specify the <literal>rw</literal> capability; that tells LPD to open the
+ printer in read-write mode.</para>
+
+ <para>If you have a parallel PostScript printer (and therefore
+ cannot use two-way communication with the printer, which
+ <command>lprps</command> needs), you can use the
+ following shell script as the text filter:</para>
+
+ <programlisting>
+#!/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 &amp;&amp; cat &amp;&amp; printf "\004" &amp;&amp; exit 0
+ exit 2
+else
+ #
+ # Plain text, convert it, then print it.
+ #
+ ( echo $first_line; cat ) | /usr/local/bin/textps &amp;&amp; printf "\004" &amp;&amp; exit 0
+ exit 2
+fi</programlisting>
+
+ <para>In the above script, <command>textps</command> 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 <xref linkend="ports" remap="The Ports
+ Collection">) includes a full featured text-to-PostScript
+ program called <citerefentry>
+ <refentrytitle>a2ps</refentrytitle></citerefentry> that you might want to investigate.</para>
+
+ </sect3>
+
+ <sect3 id="printing-advanced-ps">
+ <title>Simulating PostScript on Non-PostScript Printers</title>
+
+ <para>PostScript is the <emphasis>de facto</emphasis>
+ standard for high quality typesetting and printing. PostScript
+ is, however, an <emphasis>expensive</emphasis> standard.
+ Thankfully, Alladin Enterprises has a free PostScript work-alike
+ called <application>Ghostscript</application> 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.</para>
+
+ <para>Ghostscript should be in the FreeBSD ports collection, if
+ you would like to install it from there. You can fetch, build,
+ and install it quite easily yourself, as well.</para>
+
+ <para>To simulate PostScript, we have the text filter detect if it
+ is printing a PostScript file. If it is 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.</para>
+
+ <para>Here is an example: the following script is a text filter
+ for Hewlett Packard DeskJet 500 printers. For other printers,
+ substitute the <option>-sDEVICE</option> argument to the</para>
+
+ <para><citerefentry>
+ <refentrytitle>gs</refentrytitle></citerefentry> (Ghostscript) command. (Type <command>gs -h</command> to get a list of devices the current installation of Ghostscript supports.)</para>
+
+ <programlisting>
+#!/bin/sh
+#
+# ifhp - Print Ghostscript-simulated PostScript on a DeskJet 500
+# Installed in /usr/local/libexec/hpif
+
+#
+# Treat LF as CR+LF:
+#
+printf "\033&amp;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 is PostScript; use Ghostscript to scan-convert and print it
+ #
+ /usr/local/bin/gs -dSAFER -dNOPAUSE -q -sDEVICE=djet500 -sOutputFile=- - \
+ &amp;&amp; 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 &amp;&amp; cat &amp;&amp; printf "\f" &amp;&amp; exit 0
+fi
+
+exit 2</programlisting>
+
+ <para>Finally, you need to notify LPD of the filter
+ via the <literal>if</literal> capability:</para>
+
+ <programlisting>
+:if=/usr/local/libexec/hpif:</programlisting>
+
+ <para>That is it. You can type <command>lpr plain.text</command> and <filename>lpr
+ whatever.ps</filename> and both should print
+ successfully.</para>
+
+ </sect3>
+
+ <sect3 id="printing-advanced-convfilters">
+ <title>Conversion Filters</title>
+
+ <para>After completing the simple setup described in <xref
+ linkend="printing-simple" remap="Simple Printer Setup">, the
+ first thing you will probably want to do is install conversion
+ filters for your favorite file formats (besides plain ASCII
+ text).</para>
+
+
+ <sect4>
+ <title>Why Install Conversion Filters?</title>
+
+ <para>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 cannot print it
+ directly until we convert the DVI file into PostScript. The
+ command sequence goes like this:</para>
+
+ <informalexample>
+ <screen>&prompt.user; <userinput>dvips seaweed-analysis.dvi</userinput>
+&prompt.user; <userinput>lpr seaweed-analysis.ps</userinput></screen>
+ </informalexample>
+
+ <para>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
+ are just one step away from printing it:</para>
+
+ <informalexample>
+ <screen>&prompt.user; <userinput>lpr -d seaweed-analysis.dvi</userinput></screen>
+ </informalexample>
+
+ <para>We got LPD to do the DVI file conversion
+ for us by specifying the <option>-d</option> option. Section
+ <xref
+ linkend="printing-lpr-options-format" remap="Formatting and
+ Conversion Options"> lists the conversion options.</para>
+
+ <para>For each of the conversion options you want a printer to
+ support, install a <emphasis>conversion filter</emphasis> and
+ specify its pathname in <filename>/etc/printcap</filename>. A
+ conversion filter is like the text filter for the simple
+ printer setup (see section <xref linkend="printing-textfilter"
+ remap="Installing the Text Filter">) except that instead of
+ printing plain text, the filter converts the file into a
+ format the printer can understand.</para>
+
+ </sect4>
+
+ <sect4>
+ <title>Which Conversions Filters Should I Install?</title>
+
+ <para>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 have got plenty of troff to print
+ out, then you probably want a troff filter.</para>
+
+ <para>The following table summarizes the filters that LPD works
+ with, their capability entries for the
+ <filename>/etc/printcap</filename> file, and how to invoke
+ them with the <command>lpr</command> command:</para>
+
+ <informaltable frame="none">
+ <tgroup cols="3">
+ <thead>
+ <row>
+ <entry>File type</entry>
+ <entry><filename>/etc/printcap</filename>
+ capability</entry>
+ <entry><command>lpr</command> option</entry>
+ </row>
+ </thead>
+ <tbody>
+ <row>
+ <entry>cifplot</entry>
+ <entry><literal>cf</literal></entry>
+ <entry><option>-c</option></entry>
+ </row>
+
+ <row>
+ <entry>DVI</entry>
+ <entry><literal>df</literal></entry>
+ <entry><option>-d</option></entry>
+ </row>
+
+ <row>
+ <entry>plot</entry>
+ <entry><literal>gf</literal></entry>
+ <entry><option>-g</option></entry>
+ </row>
+
+ <row>
+ <entry>ditroff</entry>
+ <entry><literal>nf</literal></entry>
+ <entry><option>-n</option></entry>
+ </row>
+
+ <row>
+ <entry>FORTRAN text</entry>
+ <entry><literal>rf</literal></entry>
+ <entry><option>-f</option></entry>
+ </row>
+
+ <row>
+ <entry>troff</entry>
+ <entry><literal>rf</literal></entry>
+ <entry><option>-f</option></entry>
+ </row>
+
+ <row>
+ <entry>raster</entry>
+ <entry><literal>vf</literal></entry>
+ <entry><option>-v</option></entry>
+ </row>
+
+ <row>
+ <entry>plain text</entry>
+ <entry><literal>if</literal></entry>
+ <entry>none, <option>-p</option>, or <option>-l</option></entry>
+ </row>
+ </tbody>
+ </tgroup>
+ </informaltable>
+
+ <para>In our example, using <command>lpr -d</command> means the
+ printer needs a <literal>df</literal> capability in
+ its entry in <filename>/etc/printcap</filename>.</para>
+
+ <para>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
+ would 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 <literal>gf</literal> capability and then
+ educate your users that <command>lpr -g</command> mean &ldquo;print
+ Printerleaf files.&rdquo;</para>
+
+ </sect4>
+
+ <sect4>
+ <title>Installing Conversion Filters</title>
+
+ <para>Since conversion filters are programs you install outside
+ of the base FreeBSD installation, they should probably go
+ under <filename>/usr/local</filename>. The directory
+ <filename>/usr/local/libexec</filename> is a popular location,
+ since they are specialized programs that only LPD will run;
+ regular users should not ever need to run them.</para>
+
+ <para>To enable a conversion filter, specify its pathname under
+ the appropriate capability for the destination printer in
+ <filename>/etc/printcap</filename>.</para>
+
+ <para>In our example, we will add the DVI conversion filter to
+ the entry for the printer named <literal>bamboo</literal>. Here is the example
+ <filename>/etc/printcap</filename> file again, with the new
+ <literal>df</literal> capability for the printer
+ <literal>bamboo</literal>.</para>
+
+ <programlisting>
+#
+# /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:</programlisting>
+
+ <para>The DVI filter is a shell script named
+ <filename>/usr/local/libexec/psdf</filename>. Here is that
+ script:</para>
+
+ <programlisting>
+#!bin/sh
+#
+# psdf - 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 "$@"</programlisting>
+
+ <para>This script runs <citerefentry>
+ <refentrytitle>dvips</refentrytitle></citerefentry> in filter mode (the <option>-f</option> argument) on standard input, which is the job to print. It then starts the PostScript printer filter <command>lprps</command> (see section <xref linkend="printing-advanced-if-conversion"
+ remap="Accommodating Plain Text Jobs on PostScript
+ Printers">) with the arguments LPD passed to this script.
+ <command>lprps</command> will use those arguments
+ to account for the pages printed.</para>
+
+ </sect4>
+
+ <sect4>
+ <title>More Conversion Filter Examples</title>
+
+ <para>Since there is 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.</para>
+
+ <para>This example script is a raster (well, GIF file, actually)
+ conversion filter for a Hewlett Packard LaserJet III-Si
+ printer:</para>
+
+ <programlisting>
+#!/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 \
+ &amp;&amp; exit 0 \
+ || exit 2</programlisting>
+
+ <para>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.</para>
+
+ <para>Here is the <filename>/etc/printcap</filename> file with
+ an entry for a printer using the above filter:</para>
+
+ <programlisting>
+#
+# /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:</programlisting>
+
+ <para>The following script is a conversion filter for troff data
+ from the groff typesetting system for the PostScript printer
+ named <literal>bamboo</literal>:</para>
+
+ <programlisting>
+#!/bin/sh
+#
+# pstf - Convert groff's troff data into PS, then print.
+# Installed in /usr/local/libexec/pstf
+#
+exec grops | /usr/local/libexec/lprps "$@"</programlisting>
+
+ <para>The above script makes use of <command>lprps</command> again to handle the communication
+ with the printer. If the printer were on a parallel port, we
+ would use this script instead:</para>
+
+ <programlisting>
+#!/bin/sh
+#
+# pstf - Convert groff's troff data into PS, then print.
+# Installed in /usr/local/libexec/pstf
+#
+exec grops</programlisting>
+
+ <para>That is it. Here is the entry we need to
+ add to <filename>/etc/printcap</filename> to enable the
+ filter:</para>
+
+ <programlisting>
+:tf=/usr/local/libexec/pstf:</programlisting>
+
+ <para>Here is an example that might make old hands at FORTRAN
+ blush. It is a FORTRAN-text filter for any printer that can
+ directly print plain text. We will install it for the printer
+ <literal>teak</literal>:</para>
+
+ <programlisting>
+#!/bin/sh
+#
+# hprf - FORTRAN text filter for LaserJet 3si:
+# Installed in /usr/local/libexec/hprf
+#
+
+printf "\033&amp;k2G" &amp;&amp; fpr &amp;&amp; printf "\f" &amp;&amp; exit 0
+exit 2</programlisting>
+
+ <para>And we will add this line to the
+ <filename>/etc/printcap</filename> for the printer
+ <literal>teak</literal> to enable this filter:</para>
+
+ <programlisting>
+:rf=/usr/local/libexec/hprf:</programlisting>
+
+ <para>Here is one final, somewhat complex example. We will add
+ a DVI filter to the LaserJet printer <literal>teak</literal> introduced earlier. First, the
+ easy part: updating <filename>/etc/printcap</filename> with
+ the location of the DVI filter:</para>
+
+ <programlisting>
+:df=/usr/local/libexec/hpdf:</programlisting>
+
+ <para>Now, for the hard part: making the filter. For that, we
+ need a DVI-to-LaserJet/PCL conversion program. The FreeBSD
+ ports collection (see <xref linkend="ports" remap="The
+ Ports Collection">) has one: <citerefentry>
+ <refentrytitle>dvi2xx</refentrytitle></citerefentry> is the
+ name of the package. Installing this package gives us the
+ program we need, <citerefentry>
+ <refentrytitle>dvilj2p</refentrytitle></citerefentry>, which converts DVI into LaserJet IIp, LaserJet III, and LaserJet 2000 compatible codes.</para>
+
+ <para><citerefentry>
+ <refentrytitle>dvilj2p</refentrytitle></citerefentry> makes
+ the filter <command>hpdf</command> quite complex since
+ <citerefentry>
+ <refentrytitle>dvilj2p</refentrytitle></citerefentry> cannot
+ read from standard input. It wants to work with a filename.
+ What is worse, the filename has to end in
+ <filename>.dvi</filename> so using
+ <filename>/dev/fd/0</filename> for standard input is
+ problematic. We can get around that problem by linking
+ (symbolically) a temporary file name (one that ends in
+ <filename>.dvi</filename>) to <filename>/dev/fd/0</filename>,
+ thereby forcing <citerefentry>
+ <refentrytitle>dvilj2p</refentrytitle></citerefentry> to read from standard input.</para>
+
+ <para>The only other fly in the ointment is the fact that we
+ cannot use <filename>/tmp</filename> for the temporary link.
+ Symbolic links are owned by user and group
+ <username>bin</username>. The filter runs as user <username>daemon</username>. And the
+ <filename>/tmp</filename> directory has the sticky bit set.
+ The filter can create the link, but it will not be able clean
+ up when done and remove it since the link will belong to a
+ different user.</para>
+
+ <para>Instead, the filter will make the symbolic link in the
+ current working directory, which is the spooling directory
+ (specified by the <literal>sd</literal> capability
+ in <filename>/etc/printcap</filename>). This is a perfect
+ place for filters to do their work, especially since there is
+ (sometimes) more free disk space in the spooling directory
+ than under <filename>/tmp</filename>.</para>
+
+ <para>Here, finally, is the filter:</para>
+
+ <programlisting>
+#!/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 do not try to reprint the
+# job.
+#
+fatal() {
+ echo "$@" 1&gt;&amp;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 are 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&amp;k2G" || fatal "Cannot initialize printer"
+
+#
+# Convert and print. Return value from dvilj2p does not seem to be
+# reliable, so we ignore it.
+#
+dvilj2p -M1 -q -e- dfhp$$.dvi
+
+#
+# Clean up and exit
+#
+cleanup
+exit 0</programlisting>
+
+ </sect4>
+
+ <sect4 id="printing-advanced-autoconv">
+ <title>Automated Conversion: An Alternative To Conversion
+ Filters</title>
+
+ <para>All these conversion filters accomplish a lot for your
+ printing environment, but at the cost forcing the user to
+ specify (on the <citerefentry>
+ <refentrytitle>lpr</refentrytitle></citerefentry>
+ command line) which one to use. If your users are not
+ particularly computer literate, having to specify a filter
+ option will become annoying. What is 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.</para>
+
+ <para>Rather than install conversion filters at all, you might
+ want to try having the text filter (since it is the default
+ filter) detect the type of file it has been asked to print and
+ then automatically run the right conversion filter. Tools
+ such as <command>file</command> can be of help
+ here. Of course, it will be hard to determine the differences
+ between <emphasis>some</emphasis> file types&mdash;and, of course,
+ you can still provide conversion filters just for them.</para>
+
+ <para>The FreeBSD ports collection has a text filter that
+ performs automatic conversion called <citerefentry>
+ <refentrytitle>apsfilter</refentrytitle></citerefentry>. It can detect plain text, PostScript, and DVI files, run the proper conversions, and print.</para>
+
+ </sect4>
+ </sect3>
+
+ <sect3 id="printing-advanced-of">
+ <title>Output Filters</title>
+
+ <para>The LPD spooling system supports one other type of filter
+ that we have 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 are using an
+ output filter but no text filter, then:</para>
+ <itemizedlist>
+
+ <listitem>
+ <para>LPD starts an output filter once for the entire job
+ instead of once for each file in the job.</para>
+ </listitem>
+
+ <listitem>
+ <para>LPD does not make any provision to identify the start
+ or the end of files within the job for the output filter.</para>
+ </listitem>
+
+ <listitem>
+ <para>LPD does not pass the user's login or host to the
+ filter, so it is not intended to do accounting. In fact,
+ it gets only two arguments:</para>
+
+ <cmdsynopsis>
+ <command>filter-name</command>
+ <arg choice="plain">-w<replaceable>width</replaceable></arg>
+ <arg choice="plain">-l<replaceable>length</replaceable></arg>
+ </cmdsynopsis>
+
+ <para>Where <replaceable>width</replaceable> is
+ from the <literal>pw</literal> capability and
+ <replaceable>length</replaceable> is from the <literal>pl</literal> capability for the printer in
+ question.</para>
+ </listitem>
+
+ </itemizedlist>
+
+
+ <para>Do not be seduced by an output filter's simplicity. If you
+ would like each file in a job to start on a different page an
+ output filter <emphasis>will not work</emphasis>. Use a text
+ filter (also known as an input filter); see section <xref
+ linkend="printing-textfilter" remap="Installing the Text
+ Filter">. Furthermore, an output filter is actually
+ <emphasis>more complex</emphasis> 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.</para>
+
+ <para>However, an output filter is <emphasis>necessary</emphasis>
+ 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 is also <emphasis>futile</emphasis> if you want
+ to charge header pages to the requesting user's account, since
+ LPD does not give any user or host information to the output
+ filter.)</para>
+
+ <para>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 <xref
+ linkend="printing-advanced-header-pages" remap="Header
+ Pages">) only. LPD then expects the output filter to
+ <emphasis>stop itself</emphasis> 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
+ will restart the output filter by sending SIGCONT to it.</para>
+
+ <para>If there is an output filter but <emphasis>no</emphasis>
+ 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 <emphasis>not</emphasis> what you want. In almost all
+ cases, you need a text filter.</para>
+
+ <para>The program <command>lpf</command>, which we
+ introduced earlier as a text filter, can also run as an output
+ filter. If you need a quick-and-dirty output filter but do not
+ want to write the byte detection and signal sending code, try
+ <command>lpf</command>. You can also wrap <command>lpf</command> in a shell script to handle any
+ initialization codes the printer might require.</para>
+
+ </sect3>
+
+ <sect3 id="printing-advanced-lpf">
+ <title><command>lpf</command>: a Text Filter</title>
+
+ <para>The program <filename>/usr/libexec/lpr/lpf</filename> that
+ comes with FreeBSD binary distribution is a text filter (input
+ filter) that can indent output (job submitted with <command>lpr -i</command>), allow literal characters to pass
+ (job submitted with <command>lpr -l</command>), adjust the
+ printing position for backspaces and tabs in the job, and
+ account for pages printed. It can also act like an output
+ filter.</para>
+
+ <para><command>lpf</command> is suitable for many
+ printing environments. And although it has no capability to
+ send initialization sequences to a printer, it is easy to write
+ a shell script to do the needed initialization and then execute
+ <command>lpf</command>.</para>
+
+ <para>In order for <command>lpf</command> to do page
+ accounting correctly, it needs correct values filled in for the
+ <literal>pw</literal> and <literal>pl</literal> capabilities in the
+ <filename>/etc/printcap</filename> 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 <xref
+ linkend="printing-advanced-acct" remap="Accounting for Printer
+ Usage">.</para>
+
+ </sect3>
+ </sect2>
+
+ <sect2 id="printing-advanced-header-pages">
+ <title>Header Pages</title>
+
+ <para>If you have <emphasis>lots</emphasis> of users, all of them
+ using various printers, then you probably want to consider
+ <emphasis>header pages</emphasis> as a necessary evil.</para>
+
+ <para>Header pages, also known as <emphasis>banner</emphasis> or
+ <emphasis>burst pages</emphasis> identify to whom jobs belong
+ after they are printed. They are 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 is 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.)</para>
+
+ <para>The LPD system can provide header pages automatically for your
+ printouts <emphasis>if</emphasis> your printer can directly print
+ plain text. If you have a PostScript printer, you will need an
+ external program to generate the header page; see <xref
+ linkend="printing-advanced-header-pages-ps" remap="Header Pages
+ on PostScript Printers">.</para>
+
+
+ <sect3 id="printing-advanced-header-pages-enabling">
+ <title>Enabling Header Pages</title>
+
+ <para>In the <xref linkend="printing-simple" remap="Simple
+ Printer Setup">, we turned off header pages by
+ specifying <literal>sh</literal> (meaning &ldquo;suppress
+ header&rdquo;) in the <filename>/etc/printcap</filename> file. To
+ enable header pages for a printer, just remove the <literal>sh</literal> capability.</para>
+
+ <para>Sounds too easy, right?</para>
+
+ <para>You are right. You <emphasis>might</emphasis> have to
+ provide an output filter to send initialization strings to the
+ printer. Here is an example output filter for Hewlett Packard
+ PCL-compatible printers:</para>
+
+ <programlisting>
+#!/bin/sh
+#
+# hpof - Output filter for Hewlett Packard PCL-compatible printers
+# Installed in /usr/local/libexec/hpof
+
+printf "\033&amp;k2G" || exit 2 exec
+/usr/libexec/lpr/lpf</programlisting>
+
+ <para>Specify the path to the output filter in the
+ <literal>of</literal> capability. See <xref
+ linkend="printing-advanced-of"
+ remap="Output Filters"> for more information.</para>
+
+ <para>Here is an example <filename>/etc/printcap</filename> file
+ for the printer <literal>teak</literal> that we
+ introduced earlier; we enabled header pages and added the above
+ output filter:</para>
+
+ <programlisting>
+#
+# /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:</programlisting>
+
+ <para>Now, when users print jobs to <literal>teak</literal>, 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
+ <command>lpr -h</command>; see <xref
+ linkend="printing-lpr-options-misc" remap="Header Page
+ Options"> for more <citerefentry>
+ <refentrytitle>lpr</refentrytitle></citerefentry>
+ options.</para>
+
+ <note>
+ <para>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 <literal>ff</literal> capability in
+ <filename>/etc/printcap</filename>.</para>
+ </note>
+
+ </sect3>
+
+ <sect3 id="printing-advanced-header-pages-controlling">
+ <title>Controlling Header Pages</title>
+
+ <para>By enabling header pages, LPD will produce a <emphasis>long
+ header</emphasis>, a full page of large letters identifying
+ the user, host, and job. Here is an example (kelly printed the
+ job named outline from host rose):</para>
+
+ <programlisting>
+ 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</programlisting>
+
+ <para>LPD appends a form feed after this text so
+ the job starts on a new page (unless you have <literal>sf</literal> (suppress form feeds) in the
+ destination printer's entry in
+ <filename>/etc/printcap</filename>).</para>
+
+ <para>If you prefer, LPD can make a <emphasis>short
+ header</emphasis>; specify <literal>sb</literal>
+ (short banner) in the <filename>/etc/printcap</filename> file.
+ The header page will look like this:</para>
+
+ <programlisting>
+rose:kelly Job: outline Date: Sun Sep 17 11:07:51 1995</programlisting>
+
+ <para>Also by default, LPD prints the header page
+ first, then the job. To reverse that, specify <literal>hl</literal> (header last) in
+ <filename>/etc/printcap</filename>.</para>
+
+ </sect3>
+
+ <sect3 id="printing-advanced-header-pages-accounting">
+ <title>Accounting for Header Pages</title>
+
+ <para>Using LPD's built-in header pages enforces a particular
+ paradigm when it comes to printer accounting: header pages must
+ be <emphasis>free of charge</emphasis>.</para>
+
+ <para>Why?</para>
+
+ <para>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 is not provided with any <emphasis>user or
+ host</emphasis> information or an accounting file, so it has
+ no idea whom to charge for printer use. It is also not enough
+ to just &ldquo;add one page&rdquo; to the text filter or any of the
+ conversion filters (which do have user and host information)
+ since users can suppress header pages with <command>lpr
+ -h</command>. They could still be charged for header pages
+ they did not print. Basically, <command>lpr -h</command> will
+ be the preferred option of environmentally-minded users, but you
+ cannot offer any incentive to use it.</para>
+
+ <para>It is <emphasis>still not enough</emphasis> 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 <command>lpr -h</command>, they will still
+ get them and be charged for them since LPD does not pass any
+ knowledge of the <option>-h</option> option to any of the
+ filters.</para>
+
+ <para>So, what are your options?</para>
+
+ <para>You can:</para>
+ <itemizedlist>
+
+ <listitem>
+ <para>Accept LPD's paradigm and make header pages free.</para>
+ </listitem>
+
+ <listitem>
+ <para>Install an alternative to LPD, such as LPDng or PLP.
+ Section <xref linkend="printing-lpd-alternatives"
+ remap="Alternatives to the Standard Spooler"> tells
+ more about other spooling software you can substitute for
+ LPD.</para>
+ </listitem>
+
+ <listitem>
+ <para>Write a <emphasis>smart</emphasis> output filter.
+ Normally, an output filter is not meant to do anything
+ more than initialize a printer or do some simple character
+ conversion. It is suited for header pages and plain text
+ jobs (when there is 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 does not know what
+ accounting file to use (it is not passed the name of the
+ file from the <literal>af</literal>
+ 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 <literal>sh</literal> (short header) capability in
+ <filename>/etc/printcap</filename>. Then again, all that
+ might be too much trouble, and users will certainly
+ appreciate the more generous system administrator who
+ makes header pages free.</para>
+ </listitem>
+
+ </itemizedlist>
+
+
+ </sect3>
+
+ <sect3 id="printing-advanced-header-pages-ps">
+ <title>Header Pages on PostScript Printers</title>
+
+ <para>As described above, LPD can generate a plain text header
+ page suitable for many printers. Of course, PostScript cannot
+ directly print plain text, so the header page feature of LPD is
+ useless&mdash;or mostly so.</para>
+
+ <para>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 <command>lpr -h</command>.</para>
+
+ <para>Let us explore this method. The following script takes
+ three arguments (user login name, host name, and job name) and
+ makes a simple PostScript header page:</para>
+
+ <programlisting>
+#!/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 are using:
+#
+page_width=612
+page_height=792
+border=72
+
+#
+# Check arguments
+#
+if [ $# -ne 3 ]; then
+ echo "Usage: `basename $0` &lt;user&gt; &lt;host&gt; &lt;job&gt;" 1&gt;&amp;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 &lt;&lt;EOF
+%!PS
+
+%
+% Make sure we do not 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 is it
+%
+restore
+showpage
+EOF</programlisting>
+
+ <para>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 is the DVI conversion
+ filter from earlier in this document, modified to make a header
+ page:</para>
+
+ <programlisting>
+#!/bin/sh
+#
+# psdf - DVI to PostScript printer filter
+# Installed in /usr/local/libexec/psdf
+#
+# Invoked by lpd when user runs lpr -d
+#
+
+orig_args="$@"
+
+fail() {
+ echo "$@" 1&gt;&amp;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&gt;&amp;2
+ exit 2
+ ;;
+ esac
+done
+
+[ "$login" ] || fail "No login name"
+[ "$host" ] || fail "No host name"
+
+( /usr/local/libexec/make-ps-header $login $host "DVI File"
+ /usr/local/bin/dvips -f ) | eval /usr/local/libexec/lprps $orig_args</programlisting>
+
+ <para>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 <xref linkend="printing-advanced-filters"
+ remap="How Filters Work">).</para>
+
+ <para>As we have mentioned before, the above scheme, though fairly
+ simple, disables the &ldquo;suppress header page&rdquo; option (the
+ <option>-h</option> option) to <command>lpr</command>. If users wanted to save a tree (or a
+ few pennies, if you charge for header pages), they would not be
+ able to do so, since every filter's going to print a header page
+ with every job.</para>
+
+ <para>To allow users to shut off header pages on a per-job basis,
+ you will need to use the trick introduced in section
+ <xref linkend="printing-advanced-header-pages-accounting"
+ remap="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
+ <command>lpr -h</command>, then LPD will not 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.</para>
+
+ <para>If you have a PostScript printer on a serial line, you can
+ make use of <command>lprps</command>, which comes
+ with an output filter, <command>psof</command>, which
+ does the above. Note that <command>psof</command>
+ does not charge for header pages.</para>
+
+ </sect3>
+ </sect2>
+
+ <sect2 id="printing-advanced-network-printers">
+ <title>Networked Printing</title>
+
+ <para>FreeBSD supports networked printing: sending jobs to remote
+ printers. Networked printing generally refers to two different
+ things:</para>
+ <itemizedlist>
+
+ <listitem>
+ <para>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 <xref
+ linkend="printing-advanced-network-rm" remap="Printers
+ Installed on Remote Hosts"> tells how to do this.</para>
+ </listitem>
+
+ <listitem>
+ <para>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:</para>
+
+ <itemizedlist>
+
+ <listitem>
+ <para>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 <xref
+ linkend="printing-advanced-network-rm"
+ remap="Printers Installed on Remote Hosts"> to
+ set up such a printer.</para>
+ </listitem>
+
+ <listitem>
+ <para>It might support a data stream network connection.
+ In this case, you &ldquo;attach&rdquo; the printer to one host
+ on the network by making that host responsible for
+ spooling jobs and sending them to the printer.
+ Section <xref
+ linkend="printing-advanced-network-net-if"
+ remap="Printers with Networked Data Stream
+ Interfaces"> gives some suggestions on installing
+ such printers.</para>
+ </listitem>
+
+ </itemizedlist>
+
+ </listitem>
+
+ </itemizedlist>
+
+
+
+ <sect3 id="printing-advanced-network-rm">
+ <title>Printers Installed on Remote Hosts</title>
+
+ <para>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.</para>
+
+ <para>To enable this kind of remote printing, first install a
+ printer on one host, the <emphasis>printer host</emphasis>,
+ using the simple printer setup described in <xref
+ linkend="printing-simple" remap="Simple Printer Setup">. Do
+ any advanced setup in <xref linkend="printing-advanced"
+ remap="Advanced Printer Setup"> that you need. Make sure to
+ test the printer and see if it works with the features of LPD
+ you have enabled.</para>
+
+ <para>If you are using a printer with a network interface that is
+ compatible with LPD, then the <emphasis>printer host</emphasis>
+ in the discussion below is the printer itself, and the
+ <emphasis>printer name</emphasis> is the name you configured for
+ the printer. See the documentation that accompanied your
+ printer and/or printer-network interface.</para>
+
+ <para>Then, on the other hosts you want to have access to the
+ printer, make an entry in their
+ <filename>/etc/printcap</filename> files with the following:</para>
+ <orderedlist>
+
+ <listitem>
+ <para>Name the entry anything you want. For simplicity,
+ though, you probably want to use the same name and aliases
+ as on the printer host.</para>
+ </listitem>
+
+ <listitem>
+ <para>Leave the <literal>lp</literal> capability
+ blank, explicitly (<literal>:lp=:</literal>).</para>
+ </listitem>
+
+ <listitem>
+ <para>Make a spooling directory and specify its location in
+ the <literal>sd</literal> capability. LPD will
+ store jobs here before they get sent to the printer host.</para>
+ </listitem>
+
+ <listitem>
+ <para>Place the name of the printer host in the <literal>rm</literal> capability.</para>
+ </listitem>
+
+ <listitem>
+ <para>Place the printer name on the <emphasis>printer
+ host</emphasis> in the <literal>rp</literal>
+ capability.</para>
+ </listitem>
+
+ </orderedlist>
+
+ <para>That is it. You do not need to list conversion
+ filters, page dimensions, or anything else in the
+ <filename>/etc/printcap</filename> file.</para>
+
+ <para>Here is an example. The host <hostid>rose</hostid> has two printers,
+ <literal>bamboo</literal> and <literal>rattan</literal>. We will enable users on the host
+ orchid to print to those printers. Here is the
+ <filename>/etc/printcap</filename> file for <hostid>orchid</hostid> (back from
+ section
+ <xref linkend="printing-advanced-header-pages-enabling"
+ remap="Enabling Header Pages">). It already had the entry for
+ the printer <literal>teak</literal>; we have added
+ entries for the two printers on the host rose:</para>
+
+ <programlisting>
+#
+# /etc/printcap for host orchid - added (remote) printers on rose
+#
+
+#
+# teak is local; it is 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:</programlisting>
+
+ <para>Then, we just need to make spooling
+ directories on <hostid>orchid</hostid>:</para>
+
+ <informalexample>
+ <screen>&prompt.root; <userinput>mkdir -p /var/spool/lpd/rattan /var/spool/lpd/bamboo</userinput>
+&prompt.root; <userinput>chmod 770 /var/spool/lpd/rattan /var/spool/lpd/bamboo</userinput>
+&prompt.root; <userinput>chown daemon.daemon /var/spool/lpd/rattan /var/spool/lpd/bamboo</userinput></screen>
+ </informalexample>
+
+ <para>Now, users on <hostid>orchid</hostid> can print to
+ <literal>rattan</literal> and <literal>bamboo</literal>. If, for example, a user on orchid
+ typed
+
+ <informalexample>
+ <screen>&prompt.user; <userinput>lpr -P bamboo -d sushi-review.dvi</userinput></screen>
+ </informalexample> the LPD system on orchid would copy the job
+ to the spooling directory
+ <filename>/var/spool/lpd/bamboo</filename> and note that it was
+ a DVI job. As soon as the host rose has room in its <hostid>bamboo</hostid> 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.</para>
+
+ </sect3>
+
+ <sect3 id="printing-advanced-network-net-if">
+ <title>Printers with Networked Data Stream Interfaces</title>
+
+ <para>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 <xref
+ linkend="printing-advanced-network-rm" remap="Printers
+ Installed on Remote Hosts">.</para>
+
+ <para>The format of the <filename>/etc/printcap</filename> file
+ lets you specify what serial or parallel interface to use, and
+ (if you are using a serial interface), what baud rate, whether
+ to use flow control, delays for tabs, conversion of newlines,
+ and more. But there is no way to specify a connection to a
+ printer that is listening on a TCP/IP or other network
+ port.</para>
+
+ <para>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 is one such example: the script
+ <command>netprint</command> 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
+ <command>netprint</command>. 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.).</para>
+
+ <programlisting>
+#!/usr/bin/perl
+#
+# netprint - Text filter for printer attached to network
+# Installed in /usr/local/libexec/netprint
+#
+$#ARGV eq 1 || die "Usage: $0 &lt;printer-hostname&gt; &lt;port-number&gt;";
+
+$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', &amp;AF_INET, $printer_port, $address);
+
+socket(PRINTER, &amp;PF_INET, &amp;SOCK_STREAM, $protocol)
+ || die "Can't create TCP/IP stream socket: $!";
+connect(PRINTER, $sockaddr) || die "Can't contact $printer_host: $!";
+while (&lt;STDIN&gt;) { print PRINTER; }
+exit 0;</programlisting>
+
+ <para>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
+ is the text filter for the printer:</para>
+
+ <programlisting>
+#!/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</programlisting>
+
+ </sect3>
+ </sect2>
+
+ <sect2 id="printing-advanced-restricting">
+ <title>Restricting Printer Usage</title>
+
+ <para>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.</para>
+
+
+ <sect3 id="printing-advanced-restricting-copies">
+ <title>Restricting Multiple Copies</title>
+
+ <para>The LPD system makes it easy for users to print multiple
+ copies of a file. Users can print jobs with <command>lpr
+ -#5</command> (for example) and get five copies of each file
+ in the job. Whether this is a good thing is up to you.</para>
+
+ <para>If you feel multiple copies cause unnecessary wear and tear
+ on your printers, you can disable the <option>-#</option> option
+ to <citerefentry>
+ <refentrytitle>lpr</refentrytitle></citerefentry> by
+ adding the <literal>sc</literal> capability to the
+ <filename>/etc/printcap</filename> file. When users submit jobs
+ with the <option>-#</option> option, they will see:</para>
+
+ <informalexample>
+ <screen>lpr: multiple copies are not allowed</screen>
+ </informalexample>
+
+ <para>Note that if you have set up access to a printer remotely
+ (see section <xref linkend="printing-advanced-network-rm"
+ remap="Printers Installed on Remote Hosts">), you need
+ the <literal>sc</literal> capability on the remote
+ <filename>/etc/printcap</filename> files as well, or else users
+ will still be able to submit multiple-copy jobs by using another
+ host.</para>
+
+ <para>Here is an example. This is the
+ <filename>/etc/printcap</filename> file for the host <hostid>rose</hostid>. The
+ printer <literal>rattan</literal> is quite hearty, so
+ we will allow multiple copies, but the laser printer <literal>bamboo</literal>'s a bit more delicate, so we will
+ disable multiple copies by adding the <literal>sc</literal> capability:</para>
+
+ <programlisting>
+#
+# /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:</programlisting>
+
+ <para>Now, we also need to add the <literal>sc</literal> capability on the host <hostid>orchid</hostid>'s
+ <filename>/etc/printcap</filename> (and while we are at it, let
+ us disable multiple copies for the printer <literal>teak</literal>):</para>
+
+ <programlisting>
+#
+# /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:</programlisting>
+
+ <para>By using the <literal>sc</literal>
+ capability, we prevent the use of <command>lpr -#</command>, but
+ that still does not prevent users from running <citerefentry>
+ <refentrytitle>lpr</refentrytitle></citerefentry>
+ multiple times, or from submitting the same file multiple times
+ in one job like this:</para>
+
+ <informalexample>
+ <screen>&prompt.user; <userinput>lpr forsale.sign forsale.sign forsale.sign forsale.sign forsale.sign</userinput></screen>
+ </informalexample>
+
+ <para>There are many ways to prevent this abuse
+ (including ignoring it) which you are free to explore.</para>
+
+ </sect3>
+
+ <sect3 id="printing-advanced-restricting-access">
+ <title>Restricting Access To Printers</title>
+
+ <para>You can control who can print to what printers by using the
+ UNIX group mechanism and the <literal>rg</literal>
+ capability in <filename>/etc/printcap</filename>. Just place
+ the users you want to have access to a printer in a certain
+ group, and then name that group in the <literal>rg</literal> capability.</para>
+
+ <para>Users outside the group (including root) will be greeted
+ with
+
+ <errorname>
+ lpr: Not a member of the restricted group
+ </errorname>
+
+ if they try to print to the controlled
+ printer.</para>
+
+ <para>As with the <literal>sc</literal> (suppress
+ multiple copies) capability, you need to specify <literal>rg</literal> on remote hosts that also have access
+ to your printers, if you feel it is appropriate (see section
+ <xref linkend="printing-advanced-network-rm"
+ remap="Printers Installed on Remote Hosts">).</para>
+
+ <para>For example, we will let anyone access the printer
+ <literal>rattan</literal>, but only those in group
+ <literal>artists</literal> can use <literal>bamboo</literal>. Here is the familiar
+ <filename>/etc/printcap</filename> for host <hostid>rose</hostid>:</para>
+
+ <programlisting>
+#
+# /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:</programlisting>
+
+ <para>Let us leave the other example
+ <filename>/etc/printcap</filename> file (for the host <hostid>orchid</hostid>)
+ alone. Of course, anyone on <hostid>orchid</hostid> can print to
+ <literal>bamboo</literal>. It might be the case that we only
+ allow certain logins on <hostid>orchid</hostid> anyway, and want them to have
+ access to the printer. Or not.</para>
+
+ <note>
+ <para>There can be only one restricted group per printer.</para>
+ </note>
+ </sect3>
+
+ <sect3 id="printing-advanced-restricting-sizes">
+ <title>Controlling Sizes of Jobs Submitted</title>
+
+ <para>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 is only so much free space on
+ the filesystem that houses the spooling directories, and you
+ also need to make sure there is room for the jobs of other
+ users.</para>
+
+ <para>LPD enables you to limit the maximum byte size a file in a
+ job can be with the <literal>mx</literal> capability.
+ The units are in BUFSIZ blocks, which are 1024 bytes. If you
+ put a zero for this capability, there will be no limit on file
+ size.</para>
+
+ <note>
+ <para>The limit applies to <emphasis>files</emphasis> in a job,
+ and <emphasis>not</emphasis> the total job size.</para>
+ </note>
+
+ <para>LPD will not refuse a file that is larger than the limit you
+ place on a printer. Instead, it will 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.</para>
+
+ <para>Let us add limits to our example printers
+ <literal>rattan</literal> and <literal>bamboo</literal>. Since those artists' PostScript
+ files tend to be large, we will limit them to five megabytes.
+ We will put no limit on the plain text line printer:</para>
+
+ <programlisting>
+#
+# /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:</programlisting>
+
+ <para>Again, the limits apply to the local users
+ only. If you have set up access to your printers remotely,
+ remote users will not get those limits. You will need to
+ specify the <literal>mx</literal> capability in the
+ remote <filename>/etc/printcap</filename> files as well. See
+ section <xref
+ linkend="printing-advanced-network-rm" remap="Printers
+ Installed on Remote Hosts"> for more information on
+ remote printing.</para>
+
+ <para>There is another specialized way to limit job sizes from
+ remote printers; see section <xref
+ linkend="printing-advanced-restricting-remote"
+ remap="Restricting Jobs from Remote Printers">.</para>
+
+ </sect3>
+
+ <sect3 id="printing-advanced-restricting-remote">
+ <title>Restricting Jobs from Remote Printers</title>
+
+ <para>The LPD spooling system provides several ways to restrict
+ print jobs submitted from remote hosts:</para>
+
+
+ <variablelist>
+ <varlistentry><term>Host restrictions</term>
+ <listitem>
+ <para>You can control from which remote hosts a local LPD
+ accepts requests with the files
+ <filename>/etc/hosts.equiv</filename> and
+ <filename>/etc/hosts.lpd</filename>. 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.</para>
+
+ <para>The format of these files is simple: one host name
+ per line. Note that the file
+ <filename>/etc/hosts.equiv</filename> is also used by
+ the
+ <citerefentry><refentrytitle>ruserok</refentrytitle><manvolnum>3</manvolnum></citerefentry> protocol, and affects programs like <citerefentry>
+ <refentrytitle>rsh</refentrytitle></citerefentry> and
+ <citerefentry>
+ <refentrytitle>rcp</refentrytitle></citerefentry>, so be careful.</para>
+
+ <para>For example, here is the
+ <filename>/etc/hosts.lpd</filename> file on the host
+ <hostid>rose</hostid>:</para>
+
+ <programlisting>
+orchid
+violet
+madrigal.fishbaum.de</programlisting>
+
+ <para>This means <hostid>rose</hostid> will accept requests
+ from the hosts <hostid>orchid</hostid>,
+ <hostid>violet</hostid>, and <hostid role="fqdn">madrigal.fishbaum.de</hostid>.
+ If any other host tries to access <hostid>rose</hostid>'s LPD, LPD will
+ refuse them.</para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry><term>Size restrictions</term>
+
+ <listitem>
+ <para>You can control how much free space there needs to
+ remain on the filesystem where a spooling directory
+ resides. Make a file called
+ <filename>minfree</filename> 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.</para>
+
+ <para>This lets you insure that remote users will not fill
+ your filesystem. You can also use it to give a certain
+ priority to local users: they will be able to queue jobs
+ long after the free disk space has fallen below the
+ amount specified in the <filename>minfree</filename>
+ file.</para>
+
+ <para>For example, let us add a
+ <filename>minfree</filename> file for the printer
+ <hostid>bamboo</hostid>. We examine
+ <filename>/etc/printcap</filename> to find the spooling
+ directory for this printer; here is
+ <hostid>bamboo</hostid>'s entry:</para>
+
+ <programlisting>
+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:</programlisting>
+
+ <para>The spooling directory is the given
+ in the <literal>sd</literal> capability. We
+ will 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:</para>
+
+ <informalexample>
+ <screen>&prompt.root; <userinput>echo 6144 &gt; /var/spool/lpd/bamboo/minfree</userinput></screen>
+ </informalexample>
+
+ </listitem>
+ </varlistentry>
+
+ <varlistentry><term>User restrictions</term>
+
+ <listitem>
+ <para>You can control which remote users can print to
+ local printers by specifying the <literal>rs</literal> capability in
+ <filename>/etc/printcap</filename>. When <literal>rs</literal> appears in the entry for a
+ locally-attached printer, LPD will accept jobs from
+ remote hosts <emphasis>if</emphasis> the user submitting
+ the job also has an account of the same login name on
+ the local host. Otherwise, LPD refuses the job.</para>
+
+ <para>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 would rather allow them to
+ use <emphasis>only</emphasis> your printers and not your
+ compute resources, you can give them &ldquo;token&rdquo; accounts,
+ with no home directory and a useless shell like
+ <filename>/usr/bin/false</filename>.</para>
+
+ </listitem>
+ </varlistentry>
+ </variablelist>
+
+
+ </sect3>
+ </sect2>
+
+ <sect2 id="printing-advanced-acct">
+ <title>Accounting for Printer Usage</title>
+
+ <para>So, you need to charge for printouts. And why not? Paper
+ and ink cost money. And then there are maintenance
+ costs&mdash;printers are loaded with moving parts and tend to break
+ down. You have 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?</para>
+
+ <para>Well, the bad news is the LPD spooling system does not provide
+ much help in this department. Accounting is highly dependent on
+ the kind of printer in use, the formats being printed, and
+ <emphasis>your</emphasis> requirements in charging for printer
+ usage.</para>
+
+ <para>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 cannot get away with using the
+ simple output filter, since it cannot do accounting. See section
+ <xref
+ linkend="printing-advanced-filter-intro"
+ remap="Filters">.</para>
+
+ <para>Generally, there are two ways to do accounting:</para>
+ <itemizedlist>
+
+ <listitem>
+ <para><emphasis>Periodic accounting</emphasis> is the more
+ common way, possibly because it is 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.</para>
+ </listitem>
+
+ <listitem>
+ <para><emphasis>Timely accounting</emphasis> is less common,
+ probably because it is 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 &ldquo;print quotas.&rdquo; But this method requires some
+ database code to track users and their quotas.</para>
+ </listitem>
+
+ </itemizedlist>
+
+
+ <para>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.</para>
+
+
+ <sect3>
+ <title>Quick and Dirty Printer Accounting</title>
+
+ <para>FreeBSD comes with two programs that can get you set up
+ with simple periodic accounting right away. They are the text
+ filter <command>lpf</command>, described in section
+ <xref linkend="printing-advanced-lpf" remap="lpf: a Text
+ Filter">, and <citerefentry>
+ <refentrytitle>pac</refentrytitle></citerefentry>, a
+ program to gather and total entries from printer accounting
+ files.</para>
+
+ <para>As mentioned in the section on filters (<xref
+ linkend="printing-advanced-filters" remap="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 <literal>af</literal> capability in
+ <filename>/etc/printcap</filename>, and if not specified as an
+ absolute path, is relative to the spooling directory.</para>
+
+ <para>LPD starts <command>lpf</command> with page width
+ and length arguments (from the <literal>pw</literal>
+ and <literal>pl</literal> capabilities). <command>lpf</command> 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:</para>
+
+ <programlisting>
+2.00 rose:andy
+3.00 rose:kelly
+3.00 orchid:mary
+5.00 orchid:mary
+2.00 orchid:zhang</programlisting>
+
+ <para>You should use a separate accounting file for
+ each printer, as <command>lpf</command> has no file
+ locking logic built into it, and two <command>lpf</command>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
+ <literal>af=acct</literal> in
+ <filename>/etc/printcap</filename>. Then, each accounting file
+ will be in the spooling directory for a printer, in a file named
+ <filename>acct</filename>.</para>
+
+ <para>When you are ready to charge users for printouts, run
+ the <citerefentry>
+ <refentrytitle>pac</refentrytitle></citerefentry>
+ program. Just change to the spooling directory for the printer
+ you want to collect on and type <citerefentry>
+ <refentrytitle>pac</refentrytitle></citerefentry>. You
+ will get a dollar-centric summary like the following:</para>
+
+ <informalexample>
+ <screen> 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</screen>
+ </informalexample>
+
+ <para>These are the arguments <citerefentry>
+ <refentrytitle>pac</refentrytitle></citerefentry>
+ expects:</para>
+
+ <variablelist>
+ <varlistentry><term><option>-P<replaceable>printer</replaceable></option></term>
+ <listitem>
+ <para>Which <replaceable>printer</replaceable> to
+ summarize. This option works only if there is an
+ absolute path in the <literal>af</literal>
+ capability in <filename>/etc/printcap</filename>.</para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry><term><option>-c</option></term>
+
+ <listitem>
+ <para>Sort the output by cost instead of alphabetically by
+ user name.</para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry><term><option>-m</option></term>
+
+ <listitem>
+ <para>Ignore host name in the accounting files. With this
+ option, user <username>smith</username> on host <hostid>alpha</hostid> is the same user <username>smith</username>
+ on host <hostid>gamma</hostid>. Without, they are different
+ users.</para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry><term><option>-p<replaceable>price</replaceable></option></term>
+
+ <listitem>
+ <para>Compute charges with <replaceable>price</replaceable> dollars per page or per foot
+ instead of the price from the <literal>pc</literal> capability in
+ <filename>/etc/printcap</filename>, or two cents (the
+ default). You can specify <replaceable>price</replaceable> as a floating point
+ number.</para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry><term><option>-r</option></term>
+
+ <listitem>
+ <para>Reverse the sort order.</para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry><term><option>-s</option></term>
+
+ <listitem>
+ <para>Make an accounting summary file and truncate the
+ accounting file.</para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry><term><replaceable>name</replaceable> <replaceable>&hellip;</replaceable></term>
+
+ <listitem>
+ <para>Print accounting information for the given user
+ <replaceable>names</replaceable> only.</para>
+
+ </listitem>
+ </varlistentry>
+ </variablelist>
+
+ <para>In the default summary that <citerefentry>
+ <refentrytitle>pac</refentrytitle></citerefentry>
+ produces, you see the number of pages printed by each user from
+ various hosts. If, at your site, host does not matter (because
+ users can use any host), run <command>pac -m</command>, to
+ produce the following summary:</para>
+
+ <informalexample>
+ <screen> 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</screen>
+ </informalexample>
+
+ <para>To compute the dollar amount due,
+ <citerefentry>
+ <refentrytitle>pac</refentrytitle></citerefentry> uses
+ the <literal>pc</literal> capability in the
+ <filename>/etc/printcap</filename> file (default of 200, or 2
+ cents per page). Specify, in hundredths 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
+ <citerefentry>
+ <refentrytitle>pac</refentrytitle></citerefentry> with
+ the <option>-p</option> option. The units for the
+ <option>-p</option> option are in dollars, though, not
+ hundredths of cents. For example,
+
+ <informalexample>
+ <screen>&prompt.root; <userinput>pac -p1.50</userinput></screen>
+ </informalexample>
+
+ makes each page cost one dollar and fifty
+ cents. You can really rake in the profits by using this
+ option.</para>
+
+ <para>Finally, running <command>pac -s</command> will save the
+ summary information in a summary accounting file, which is named
+ the same as the printer's accounting file, but with
+ <literal>_sum</literal> appended to the name. It then truncates
+ the accounting file. When you run <citerefentry>
+ <refentrytitle>pac</refentrytitle></citerefentry>
+ again, it rereads the summary file to get starting totals, then
+ adds information from the regular accounting file.</para>
+
+ </sect3>
+
+ <sect3>
+ <title>How Can You Count Pages Printed?</title>
+
+ <para>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.</para>
+
+ <para>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. Do not 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.</para>
+
+ <para>The text filter <command>lpf</command>
+ (introduced in <xref linkend="printing-advanced-lpf" remap="lpf:
+ a Text Filter">) takes into account these things when it does
+ accounting. If you are writing a text filter which needs to do
+ accounting, you might want to examine <command>lpf</command>'s source code.</para>
+
+ <para>How do you handle other file formats, though?</para>
+
+ <para>Well, for DVI-to-LaserJet or DVI-to-PostScript conversion,
+ you can have your filter parse the diagnostic output of <citerefentry>
+ <refentrytitle>dvilj</refentrytitle></citerefentry> or
+ <citerefentry>
+ <refentrytitle>dvips</refentrytitle></citerefentry> and look to see how many pages were converted. You might be able to do similar things with other file formats and conversion programs.</para>
+
+ <para>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&mdash;and the user would still get
+ charged.</para>
+
+ <para>So, what can you do?</para>
+
+ <para>There is only one <emphasis>sure</emphasis> way to do
+ <emphasis>accurate</emphasis> 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 <emphasis>only</emphasis>. There is no line counting
+ nor error-prone file examination required.</para>
+
+ <para>Of course, you can always be generous and make all printouts
+ free.</para>
+
+ </sect3>
+ </sect2>
+ </sect1>
+
+ <sect1 id="printing-lpd-alternatives">
+ <title>Alternatives to the Standard Spooler</title>
+
+ <para>If you have been reading straight through this manual, by now
+ you have 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: &ldquo;What other spooling systems are out there (and work with
+ FreeBSD)?&rdquo;</para>
+
+ <para>Unfortunately, I have located only <emphasis>two</emphasis>
+ alternatives&mdash;and they are almost identical to each other! They
+ are:</para>
+
+ <variablelist>
+ <varlistentry><term>PLP, the Portable Line Printer Spooler
+ System</term>
+ <listitem>
+ <para>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 <ulink
+ URL="ftp://ftp.iona.ie/pub/plp">ftp://ftp.iona.ie/pub/plp</ulink>. There is also a <ulink URL="http://www.iona.ie:8000/www/hyplan/jmason/plp.html">web page</ulink>.</para>
+
+ <para>It is quite similar to the BSD LPD spooler, but boasts a
+ host of features, including:</para>
+ <itemizedlist>
+
+ <listitem>
+ <para>Better network support, including built-in support
+ for networked printers, NIS-maintained printcaps, and
+ NFS-mounted spooling directories</para>
+ </listitem>
+
+ <listitem>
+ <para>Sophisticated queue management, allowing multiple
+ printers on a queue, transfer of jobs between queues,
+ and queue redirection</para>
+ </listitem>
+
+ <listitem>
+ <para>Remote printer control functions</para>
+ </listitem>
+
+ <listitem>
+ <para>Prioritization of jobs</para>
+ </listitem>
+
+ <listitem>
+ <para>Expansive security and access options</para>
+ </listitem>
+
+ </itemizedlist>
+
+ </listitem>
+ </varlistentry>
+
+ <varlistentry><term>LPRng</term>
+
+ <listitem>
+ <para>LPRng, which purportedly means &ldquo;LPR: the Next
+ Generation&rdquo; 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
+ <ulink
+ URL="ftp://dickory.sdsu.edu/pub/LPRng">ftp://dickory.sdsu.edu/pub/LPRng</ulink>.</para>
+
+ </listitem>
+ </varlistentry>
+ </variablelist>
+
+ </sect1>
+
+ <sect1>
+ <title>Acknowledgments</title>
+
+ <para>I would like to thank the following people who have assisted in
+ the development of this document:</para>
+
+
+ <variablelist>
+ <varlistentry><term>Daniel Eischen
+ <email>deischen@iworks.interworks.org</email></term>
+ <listitem>
+ <para>For providing a plethora of HP filter programs for
+ perusal.</para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry><term>&a.jehamby;</term>
+
+ <listitem>
+ <para>For the Ghostscript-to-HP filter.</para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry><term>My wife, Mary Kelly
+ <email>urquhart@argyre.colorado.edu</email></term>
+
+ <listitem>
+ <para>For allowing me to spend more time with FreeBSD than
+ with her.</para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+
+ </sect1>
+ </chapter> \ No newline at end of file