Printers
In this chapter, we'll look at some aspects of using printers with FreeBSD. As a user, you don't access printers directly. Instead, a series of processes, collectively called the spooler, manage print data. One process, lpr, writes user print data to disk, and another, lpd, copies the print data to the printers. This method enables processes to write print data even if the printers are busy and ensures optimum printer availability.
In this section, we'll look briefly at what you need to do to set up printers. For more details, look in the online handbook section on printing.
lpd is the central spooler process. It is responsible for a number of things:
- It controls access to attached printers and to printers attached to other hosts on the network.
- It enables users to submit files to be printed. These submissions are known as jobs.
- It prevents multiple users from accessing a printer at the same time by maintaining a queue for each printer.
- It can print header pages, also known as banner or burst pages, so users can easily find jobs they have printed in a stack of printouts.
- It takes care of communications parameters for printers connected on serial ports.
- It can send jobs over the network to another spooler on another host.
- It can run special filters to format jobs to be printed for various printer languages or printer capabilities.
- It can account for printer usage.
Through a configuration file, and by providing the special filter programs, you can enable the spooler to do all or some subset of the above for a great variety of printer hardware.
This may sound like overkill if you are the only user on the system. It is possible to access the printer directly, but it's not a good idea:
- The spooler prints jobs in the background. You don't have to wait for data to be copied to the printer.
- The spooler can conveniently run a job to be printed through filters to add headers or convert special formats (such as PostScript) into a format the printer will understand.
- Most programs that provide a print feature expect to talk to the spooler on your system.
Printer configuration
There are three commonly used ways to connect a printer to a computer:
- Older UNIX systems frequently used serial printers, but they are no longer in common use. Serial printers seldom transmit more than 1,920 characters per second, which is too slow for modern printers.
- Most printers are still connected by a parallel port. Parallel ports enable faster communication with the printer, up to about 100,000 bytes per second. Such speeds may still not be enough for complex PostScript or bit-mapped images. Most parallel ports require CPU intervention via an interrupt for each character transmitted, and 100,000 interrupts per second can use the entire processing power of a fast machine.
- More modern printers have USB or Ethernet interfaces, which enable them to connect to several machines at once at much higher speeds. The load on the host computer is also much lower.
It's pretty straightforward to connect a parallel printer. You don't need to do anything special to configure the line printer driver lpt: it's in the kernel by default. All you need to do is to plug in the cable between the printer and the computer. If you have more than one parallel interface, of course, you'll have to decide which one to use. Parallel printer devices are called /dev/lptn, where n is the number, starting with 0. USB devices have names like /dev/ulptn. See Table 10-4 on page 195 for further details.
Configuring an Ethernet-connected printer is more complicated. You obviously need an IP address, which you configure on the printer. Most modern printers then appear like a remote computer to the spooler. We look at spooling to remote computers on page 266.
Testing the printer
When you have connected and powered on a parallel port printer, run the built-in test if one is supplied: typically there's a function that produces a printout describing the printer's features. After that, check the communication between the computer and the printer.
# lptest > /dev/lpt0
If you have a pure PostScript printer, one which can't print anything else, you won't get any out put. Even here, though, you should see some reaction on the status display.
Configuring /etc/printcap
The next step is to configure the central configuration file, /etc/printcap. This file is not the easiest to read, but after a while you'll get used to it. Here are some typical entries:
lp|lj|ps|local LaserJet 6MP printer:\ :lp=/dev/lpt0:sd=/var/spool/output/lpd:lf=/var/log/lpd-errs:sh:mx#0:\ :if=/usr/local/libexec/lpfilter: rlp|sample remote printer:\ :rm=freebie:sd=/var/spool/output/freebie:lf=/var/log/lpd-errs:\ :rp=lp:
Let's look at this in detail:
- All fields are delimited by a colon (:).
- Continuation lines require a backslash character (\). Note particularly that you require a colon at the end of a continued line, and another at the beginning of the following line.
- The first line of each entry specifies a number of names that you can use to specify this printer when talking to lpr or lpd. The names are separated by vertical bar symbols|. By tradition, the last name is a more verbose description, and you wouldn't normally use it to talk to programs.
- The following fields describe capabilities, descriptions of how to do something. Capabilities are described by a two-letter keyword and optionally a parameter, which is separated by a delimiter indicating the type of parameter. If the field takes a string parameter, the delimiter is =, and if it takes a numeric value, the delimiter is #. You'll find a full description in the man page.
- The first entry defines a local printer, called lp, lj, ps and local LaserJet 6MP printer. Why so many names? lp is the default, so you should have it somewhere. lj is frequently used to talk to printers that understand HP's LaserJet language (now PCL), and ps might be used to talk to a printer that understands PostScript. The final name is more of a description.
- The entry lp=/dev/lpt0 tells the spooler the name of the physical device to which the printer is connected. Remote printers don't have physical devices.
- sd tells the spooler the directory in which to store jobs awaiting printing. This directory must exist; the spooler doesn't create it.
- lf=/var/log/lpd-errs specifies the name of a file in which to log errors.
- sh is a flag telling lpd to omit a header page. If you don't have that, every job will be preceded by a descriptor page. In a small environment, this doesn't make sense and is just a waste of paper.
- The parameter mx tells lpd the maximum size of a spool job in kilobytes. If the job is larger than this value, lpd refuses to print it. In our case, we don't want to limit the size. We do this by setting mx to 0.
- if tells lpd to apply a filter to the job before printing. We'll look at this below.
- In the remote printer entry, rm=freebie tells lpd to send the data to the machine called freebie. This could be a fully qualified domain name, of course.
- In the remote printer entry, rp=lp tells lpd the name of the printer on the remote machine. This doesn't have to be the same name as the name on the local machine.
Remote printing
In a network, you don't need to have a printer on every machine; you can print on another machine (which may be a printer) on the same network. There are a couple of things to consider:
- There are two machines involved in remote printing, the client ("local") machine and the server ("remote") machine.
- On the client, you specify the name of the server machine with the rm capability, and you specify the name of the printer with the rp capability. You don't specify any lp (device name) capability. A typical entry might look like this:
lp|HP LaserJet 6MP on freebie:\ :rm=freebie:sd=/var/spool/output/freebie:lf=/var/log/lpd-errs:mx#0:
- On the client machine, you must also create the spool directory, /var/spool/out-put/freebie in the example above.
- On the server machine, you don't need to do anything special with the /etc/printcap file. You need an entry for the printer specified in the client machine's rp entry, of course.
- On the server machine you must allow spooler access from the client machine. For a BSD machine, you add the name of the machine to the file /etc/hosts.lpd on a line by it self.
Spooler filters
Probably the least intelligible entry in the configuration file on page 265 was the if entry. It specifies the name of an input filter, a program through which Lpd passes the complete print data before printing.
What does it do that for? There can be a number of reasons. Maybe you have data in a format that isn't fit to print. For example, it might be PostScript, and your printer might not understand PostScript. Or it could be the other way around: your printer understands only PostScript, and the input isn't PostScript.
There's a more likely reason to require a filter, though: most printers still emulate the old teletypes, so they require a carriage return character (Ctrl-M or ^M) to start at the beginning of the line, and a new line character (Ctrl-J or ^J) to advance to the next line. UNIX uses only ^J, so if you copy data to it, you're liable to see a staircase effect. For example, may tell you:
$ ps PID TT STAT TIME COMMAND 2252 pi Ss 0:01.35 /bin/bash 2287 p1 IW 0:04.77 e/etc/printcap 2346 p1 R+ 0:00.05 ps
When you try to print it, however, you get:
PID TT STAT TIME COMMAND 2252 p1 Ss 0:01.35 /bin/bash 2287 p1 IW 0
The rest of the page is empty: you've gone off the right margin. There are a number of ways to solve this problem:
- You may be able to configure your printer to interpret Ctrl-J as both new line and return, and to ignore Ctrl-M. Check your printer handbook.
- You may be able to issue a control sequence to your printer to tell it to interpret Ctrl-J as both new line and return to the beginning of the line, and to ignore Ctrl-M. For example, HP Laser Jets and compatibles will do this if you send them the control sequence ESC&k2G.
- You can write an input filter that transforms the print job into a form that the printer understands. We'll look at this option below.
There are a couple of options for the print filter. One of them, taken from the online handbook, sends out a LaserJet control sequence before every job. Put the following shell script in /usr/local/libexec/lpfilter:
#!/bin/sh printf "\033&k2G" && cat && printf "\f" && exit 0 exit 2Листинг 15.1. Simple print filter
This approach does not work well with some printers, such as my HP LaserJet 6MP, which can print both PostScript and LaserJet (natural) formats at random. They do this by recognizing the text at the beginning of the job. This particular filter confuses them by sending a LaserJet command code, so the printer prints the PostScript as if it were plain text.
In this kind of situation, the standard filters are no longer sufficient. You can solve the problem with the port apsfilter, which is in the Ports Collection.
Starting the spooler
As we saw above, the line printer daemon lpd is responsible for printing spooled jobs. By default it isn't started at boot time. If you're root, you can start it by name:
# lpd
Normally, however, you will want it to be started automatically when the system starts up. You do this by setting the variable lpd_enable in /etc/rc.conf:
lpd_enable="YES" # Run the line printer daemon
See page 552 for more details of /etc/rc.conf.
You can also add another line referring to the line printer daemon to /etc/rc.conf:
lpd_flags="" # Flags to lpd (if enabled).
You don't normally need this line. See the man page for lpd for details of the fags.
Testing the spooler
To test the spooler, you can run the lptest program again. This time, however, instead of sending it directly to the printer, you send it to the spooler:
$ lptest 80 5 | lpr
!"#$%&'()* + ,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_,abcdefghijklmnop "#$%&'()* + ,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_,abcdefghijklmnopq #$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJK^OPQRSTUVWXYZ[\]^_,abcdefghijklmnopqr $%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_,abcdefghijklmnopqrs %&'()*+,-./0123456789:;<=>?@ABCDEFGHIJK^OPQRSTUVWXYZ[\]^_,abcdefghijklmnopqrst
Troubleshooting
Here's a list of the most common problems and how to solve them.
Problem | Cause |
---|---|
The printer prints, but the last page doesn't appear. The status shows that the printer still has data in the buffer. After several minutes, the last page may appear. | Your output data is not ejecting the last page. The printer is configured to either wait for an explicit eject request (the ASCII Form
feed character, Ctrl-L) or to eject after a certain period of time.
You have a choice as to what you do about this. Usually you can configure the printer, or you could get the print filter to print a form feed character at the end of the job. Listing 15-1 already does this — that's the printf "\f". |
The lines wander off to the right edge of the paper and are never seen again | This is the staircase effect. Refer to page 268 for a couple of solutions. |
Individual characters or whole sections of text are missing. | This problem occurs almost only on serial printers. It's a result of incorrect handshaking—see page 330 and the online handbook for more details. |
The output contained completely unintelligible random characters. | On a serial printer ,if the characters appear slowly, and there's a predominance of the characters {|}~, this probably means that you have set up the communication parameters in correctly. Check the online handbook for a solution. Makes sure you don't confuse this problem with the following one. |
The text was legible, but it bore no relationship to what you wanted to print. | One possibility is that you are sending PostScript output to your printer. See the discussion on page 271 to check if it is PostScript. If it is, your printer is not interpreting it correctly, either because it doesn't understand PostScript, or because it has been confused (see the discussion on page 268 for one reason). |
The display on the printer shows that data are arriving, but the printer doesn't print anything. | You might be sending normal text to a PostScript printer that doesn't understand normal text. In this case, too, you will need a filter to convert the text to PostScript—the opposite of the previous problem.
Alternatively, your printer port may not be interrupting correctly. This will not stop the printer from printing, but it can take up to 20 minutes to print a page. You can fix this by issuing the following command, which puts the printer /dev/lpt0 into polled mode: # lptcontrol -p |
You get the message lpr: cannot create freebie/.seq | You have forgotten to create the spool directory /var/spool/output/freebie. |