diff options
| author | Nik Clayton <nik@FreeBSD.org> | 1998-11-03 23:17:06 +0000 |
|---|---|---|
| committer | Nik Clayton <nik@FreeBSD.org> | 1998-11-03 23:17:06 +0000 |
| commit | 2207769022c0b726ecdd97003a494c796dfb022b (patch) | |
| tree | 2f26f2909f28edb06c950ac6fbbb830cf0db746c /en/handbook/printing/chapter.sgml | |
| parent | 05dc329be3f5fae2b8a8dc537730f3ea884900b0 (diff) | |
Notes
Diffstat (limited to 'en/handbook/printing/chapter.sgml')
| -rw-r--r-- | en/handbook/printing/chapter.sgml | 4938 |
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 “Simple Printer Setup,” 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 + “Centronics” 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—such as a + terminal or a modem—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 “proper serial cable” 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 “DTE-to-DCE” + 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 + “DTE-to-DTE” 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 + “in-band” or “software”) + 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 > /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 > /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> > /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>><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 && 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> +!"#$%&'()*+,-./01234 +"#$%&'()*+,-./012345 +#$%&'()*+,-./0123456 +$%&'()*+,-./01234567 +%&'()*+,-./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 && printf "\f" && exit 0 +exit 2</programlisting> + </listitem> + </varlistentry> + + <varlistentry><term>It produced the “staircase + effect.”</term> + + <listitem> + <para>You got the following on paper:</para> + + <programlisting> +!"#$%&'()*+,-./01234 + "#$%&'()*+,-./012345 + #$%&'()*+,-./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&k2G" && cat && printf "\f" && 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 “opposite” of the staircase + effect, described above, and is much rarer. Somewhere, + the LF characters that FreeBSD uses to end a line are + being treated as CR characters to return the print + location to the left edge of the paper, but not also + down a line.</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 + “print job”, which is sent to the LPD spooling + system. Each printer has a queue of jobs, and your job waits in + that queue along with other jobs from yourself and from other + users. The printer prints those jobs in a first-come, first-served + order.</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 “job number” 9. Every + job for a printer gets a unique job number. Most of the time you + can ignore the job number, but you 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 “Rank” column), which means the printer should be + currently printing that job. The second job consists of data + passed as the standard input to the</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—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 “under + the hood” when LPD uses filters. This knowledge could help + you anticipate and debug problems you might encounter as you + install more and more filters on each of your printers.</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 && cat && printf "\004" && exit 0 + exit 2 +else + # + # Plain text, convert it, then print it. + # + ( echo $first_line; cat ) | /usr/local/bin/textps && printf "\004" && 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&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=- - \ + && 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 && cat && printf "\f" && 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 “print + Printerleaf files.”</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 \ + && 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&k2G" && fpr && printf "\f" && 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>&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&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—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 “suppress + header”) 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&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 “add one page” to the text filter or any of the + conversion filters (which do have user and host information) + since users can suppress header pages with <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—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` <user> <host> <job>" 1>&2 + exit 1 +fi + +# +# Save these, mostly for readability in the PostScript, below. +# +user=$1 +host=$2 +job=$3 +date=`date` + +# +# Send the PostScript code to stdout. +# +exec cat <<EOF +%!PS + +% +% Make sure we 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>&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>&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 “suppress header page” 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 “attach” 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 <printer-hostname> <port-number>"; + +$printer_host = $ARGV[0]; +$printer_port = $ARGV[1]; + +require 'sys/socket.ph'; + +($ignore, $ignore, $protocol) = getprotobyname('tcp'); +($ignore, $ignore, $ignore, $ignore, $address) + = gethostbyname($printer_host); + +$sockaddr = pack('S n a4 x8', &AF_INET, $printer_port, $address); + +socket(PRINTER, &PF_INET, &SOCK_STREAM, $protocol) + || die "Can't create TCP/IP stream socket: $!"; +connect(PRINTER, $sockaddr) || die "Can't contact $printer_host: $!"; +while (<STDIN>) { print PRINTER; } +exit 0;</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 > /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 “token” 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—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 “print quotas.” 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>…</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—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: “What other spooling systems are out there (and work with + FreeBSD)?”</para> + + <para>Unfortunately, I have located only <emphasis>two</emphasis> + alternatives—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 “LPR: the Next + Generation” is a complete rewrite of PLP. Patrick Powell + and Justin Mason (the principal maintainer of PLP) + collaborated to make LPRng. The main site for LPRng is + <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 |
