diff --git a/en_US.ISO8859-1/books/handbook/printing/chapter.sgml b/en_US.ISO8859-1/books/handbook/printing/chapter.sgml index 596b90c8eb..faff1afa92 100644 --- a/en_US.ISO8859-1/books/handbook/printing/chapter.sgml +++ b/en_US.ISO8859-1/books/handbook/printing/chapter.sgml @@ -1,557 +1,558 @@ Printing - - Contributed by &a.kelly; 30 September - 1995 - - 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. - - If you are already familiar with LPD or another printer spooling - system, you may wish to skip to section Restructured and updated by &a.jim;, March + 2000. + + + Synopsis + + 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 chapter introduces the LPD spooling + system, often simply called LPD, and will guide you through it's + configuration. + + If you are already familiar with LPD or another printer spooling + system, you may wish to skip to section Setting up the spooling system. - - - What the Spooler Does + - LPD controls everything about a host's printers. It is responsible - for a number of things: + + Introduction + + LPD controls everything about a host's printers. It is + responsible for a number of things: - It controls access to attached printers and printers attached to - other hosts on the network. + It controls access to attached printers and 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 + 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 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 LPD 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 LPD system to do all or some subset of the - above for a great variety of printer hardware. + + Through a configuration file + (/etc/printcap), 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. + + + Why You Should Use the Spooler + + 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: + + + + LPD prints jobs in the background; you do not have to wait + for data to be copied to the printer. + + + + 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. + + + + 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. + + + - - - Why You Should Use the Spooler - - 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 - - - - LPD prints jobs in the background; you do not have to wait for - data to be copied to the printer. - - - - 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. - - - - 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. - - - - + - Setting Up the Spooling System - - 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: - + Basic Setup + + 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: + See section Simple Printer - Setup to learn how to connect a printer, tell LPD how to + Setup to learn how to connect a printer, tell LPD how to communicate with it, and print plain text files to the printer. - + - See section 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. + See section 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. - - - - Simple Printer Setup - - This section tells how to configure printer hardware and the LPD - software to use the printer. It teaches the basics: - - - - Section Hardware Setup - gives some hints on connecting the printer to a port on your - computer. - - - - Section Software Setup - shows how to setup the LPD spooler configuration file - /etc/printcap. - - - - 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 - Printers With Networked - Data Stream Interaces. - 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. + + Simple Printer Setup - - Hardware Setup - - 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. + This section tells how to configure printer hardware and the + LPD software to use the printer. It teaches the basics: + + + + Section Hardware + Setup gives some hints on connecting the printer to a + port on your computer. + + + + Section Software + Setup shows how to setup the LPD spooler configuration + file (/etc/printcap). + + + + 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 Printers With + Networked Data Stream Interaces. + + 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. + + + Hardware Setup + + This section tells about the various ways you can connect a + printer to your PC. It talks about the kinds of ports and + cables, and also the kernel configuration you may need to enable + FreeBSD to speak to the printer. + + If you have already connected your printer and have + successfully printed with it under another operating system, you + can probably skip to section Software Setup. + + + Ports and Cables + + Nearly all printers you can get for a PC today support one + or both of the following interfaces: + + + + Serial interfaces use a serial + port on your computer to send data to the printer. Serial + interfaces are common in the computer industry and cables + are readily available and also easy to construct. Serial + interfaces sometimes need special cables and might require + you to configure somewhat complex communications + options. + + + + Parallel interfaces use a + parallel port on your computer to send data to the + printer. Parallel interfaces are common in the PC market. + Cables are readily available but more difficult to + construct by hand. There are usually no communications + options with parallel interfaces, making their + configuration exceedingly simple. + + Parallel interfaces are sometimes known as + “Centronics” interfaces, named after the + connector type on the printer. + + + + 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. + + 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. + - If you have already connected your printer and have successfully - printed with it under another operating system, you can probably skip - to section Software - Setup. - - - Ports and Cables + + Parallel Ports - Nearly all printers you can get for a PC today support one or - both of the following interfaces: - - - - Serial interfaces use a serial port on - your computer to send data to the printer. Serial interfaces - are common in the computer industry and cables are readily - available and also easy to construct. Serial interfaces - sometimes need special cables and might require you to configure - somewhat complex communications options. - - - - Parallel interfaces use a parallel port - on your computer to send data to the printer. Parallel - interfaces are common in the PC market. Cables are readily - available but more difficult to construct by hand. There are - usually no communications options with parallel interfaces, - making their configuration exceedingly simple. - - Parallel interfaces are sometimes known as - “Centronics” interfaces, named after the connector - type on the printer. - - - - 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. - - 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. - - So, which interface should you use? - - - - If you need two-way communication, use a serial port. - FreeBSD does not yet support two-way communication over a - parallel port. - - - - 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. - - - - Finally, use whatever works. - - - - - - Parallel Ports + 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. - To hook up a printer using a parallel interface, connect the - Centronics cable between the printer and the computer. The - instructions that came with the printer, the computer, or both - should give you complete guidance. - - Remember which parallel port you used on the computer. The - first parallel port is /dev/lpt0 to FreeBSD; - the second is /dev/lpt1, and so on. - - - - Serial Ports - - To hook up a printer using a serial interface, connect the - proper serial cable between the printer and the computer. The - instructions that came with the printer, the computer, or both - should give you complete guidance. - - If you are unsure what the “proper serial cable” is, - you may wish to try one of the following alternatives: - - - - A modem cable connects each pin of the - connector on one end of the cable straight through to its - corresponding pin of the connector on the other end. This type - of cable is also known as a “DTE-to-DCE” - cable. - - - - A null-modem cable connects some pins - straight through, swaps others (send data to receive data, for - example), and shorts some internally in each connector hood. - This type of cable is also known as a “DTE-to-DTE” - cable. - - - - A serial printer cable, required for - some unusual printers, is like the null modem cable, but sends - some signals to their counterparts instead of being internally - shorted. - - - - 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 - baud rate) rate that both your computer and the - printer can support. Choose 7 or 8 data bits; none, even, or odd - parity; and 1 or 2 stop bits. Also choose a flow control protocol: - either none, or XON/XOFF (also known as “in-band” or - “software”) flow control. Remember these settings for - the software configuration that follows. - - - - - Software Setup - - This section describes the software setup necessary to print - with the LPD spooling system in FreeBSD. - - Here is an outline of the steps involved: - - - - Configure your kernel, if necessary, for the port you are - using for the printer; section Kernel Configuration tells you - what you need to do. - - - - Set the communications mode for the parallel port, if you are - using a parallel port; section Setting the Communication - Mode for the Parallel Port gives details. - - - - Test if the operating system can send data to the printer. - Section Checking Printer - Communications gives some suggestions on how to do - this. - - - - Set up LPD for the printer by modifying the file - /etc/printcap. Section The /etc/printcap File shows - you how. - - - - - Kernel Configuration - - 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. - - To find out if the kernel you are currently using supports a - serial interface, type: - - &prompt.root; dmesg | grep sioN - - Where N is the number of the serial - port, starting from zero. If you see output similar to the - following: - - sio2 at 0x3e8-0x3ef irq 5 on isa -sio2: type 16550A - - then the kernel supports the port. - - To find out if the kernel supports a parallel interface, - type: - - &prompt.root; dmesg | grep lptN - - Where N is the number of the parallel - port, starting from zero. If you see output similar to the - following lpt0 at 0x378-0x37f on isa then the - kernel supports the port. - - You might have to reconfigure your kernel in order for the - operating system to recognize and use the parallel or serial port - you are using for the printer. - - To add support for a serial port, see the section on kernel - configuration. To add support for a parallel port, see that section - and the section that follows. - - - Adding <filename>/dev</filename> Entries for the Ports - - 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 /dev - directory are for. - - To add a /dev entry for a - port: - - - - Become root with the &man.su.1; command. Enter the root - password when prompted. - - - - Change to the /dev directory: - - &prompt.root; cd /dev - - - - - Type: - - &prompt.root; ./MAKEDEV port - - Where port is the device entry - for the port you want to make. Use lpt0 - for the first parallel port, lpt1 for the - second, and so on; use ttyd0 for the first - serial port, ttyd1 for the second, and so - on. - - - - Type: - - &prompt.root; ls -l port - - to make sure the device entry got created. - - + Remember which parallel port you used on the computer. + The first parallel port is /dev/lpt0 to + FreeBSD; the second is /dev/lpt1, and so + on. + + Serial Ports + + To hook up a printer using a serial interface, connect the + proper serial cable between the printer and the computer. The + instructions that came with the printer, the computer, or both + should give you complete guidance. + + If you are unsure what the “proper serial + cable” is, you may wish to try one of the following + alternatives: + + + + A modem cable connects each pin + of the connector on one end of the cable straight through + to its corresponding pin of the connector on the other + end. This type of cable is also known as a + “DTE-to-DCE” cable. + + + + A null-modem cable connects some + pins straight through, swaps others (send data to receive + data, for example), and shorts some internally in each + connector hood. This type of cable is also known as a + “DTE-to-DTE” cable. + + + + A serial printer cable, required + for some unusual printers, is like the null modem cable, + but sends some signals to their counterparts instead of + being internally shorted. + + + + 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 + baud rate) rate that both your computer + and the printer can support. Choose 7 or 8 data bits; none, + even, or odd parity; and 1 or 2 stop bits. Also choose a flow + control protocol: either none, or XON/XOFF (also known as + “in-band” or “software”) flow control. + Remember these settings for the software configuration that + follows. + + + + + Software Setup + + This section describes the software setup necessary to print + with the LPD spooling system in FreeBSD. + + Here is an outline of the steps involved: + + + + Configure your kernel, if necessary, for the port you + are using for the printer; section Kernel Configuration tells + you what you need to do. + + + + Set the communications mode for the parallel port, if + you are using a parallel port; section Setting the + Communication Mode for the Parallel Port gives + details. + + + + Test if the operating system can send data to the printer. + Section Checking Printer + Communications gives some suggestions on how to do + this. + + + + Set up LPD for the printer by modifying the file + /etc/printcap. You will find out how + to do this later in this chapter. + + + + + Kernel Configuration + + 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. + + To find out if the kernel you are currently using supports + a serial interface, type: + + &prompt.root; dmesg | grep sioN + + Where N is the number of the + serial port, starting from zero. If you see output similar to + the following: + + sio2 at 0x3e8-0x3ef irq 5 on isa +sio2: type 16550A + + then the kernel supports the port. + + To find out if the kernel supports a parallel interface, + type: + + &prompt.root; dmesg | grep lptN + + Where N is the number of the + parallel port, starting from zero. If you see output similar + to the following lpt0 at 0x378-0x37f on isa + then the kernel supports the port. + + You might have to reconfigure your kernel in order for the + operating system to recognize and use the parallel or serial + port you are using for the printer. + + To add support for a serial port, see the section on + kernel configuration. To add support for a parallel port, see + that section and the section that + follows. + + + + + Adding <filename>/dev</filename> Entries for the + Ports + + 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 + /dev directory are for. + + To add a /dev entry for a + port: + + + + Become root with the &man.su.1; command. Enter the + root password when prompted. + + + + Change to the /dev + directory: + + &prompt.root; cd /dev + + + + Type: + + &prompt.root; ./MAKEDEV port + + Where port is the device + entry for the port you want to make. Use + lpt0 for the first parallel port, + lpt1 for the second, and so on; use + ttyd0 for the first serial port, + ttyd1 for the second, and so on. + + + + Type: + + &prompt.root; ls -l port + + to make sure the device entry got created. + + + - Setting the Communication Mode for the Parallel Port - + Setting the Communication Mode for the Parallel + Port + When you are using the parallel interface, you can choose whether FreeBSD should use interrupt-driven or polled communication with the printer. - + - The interrupt-driven method is the - default with the GENERIC kernel. With this method, the - operating system uses an IRQ line to determine when the - printer is ready for data. + The interrupt-driven method is + the default with the GENERIC kernel. With this method, + the operating system uses an IRQ line to determine when + the printer is ready for data. - + The polled 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. + operating system to repeatedly ask the printer if it is + ready for more data. When it responds ready, the kernel + sends more data. - - The interrupt-driven method is somewhat faster but uses up a - precious IRQ line. You should use whichever one works. - + + The interrupt-driven method is somewhat faster but uses up + a precious IRQ line. You should use whichever one + works. + You can set the communications mode in two ways: by configuring the kernel or by using the &man.lptcontrol.8; program. - - To set the communications mode by configuring the - kernel: - + + To set the communications mode by configuring + the kernel: + - Edit your kernel configuration file. Look for or add an - lpt0 entry. If you are setting up the - second parallel port, use lpt1 instead. - Use lpt2 for the third port, and so - on. - + Edit your kernel configuration file. Look for or add + an lpt0 entry. If you are setting up + the second parallel port, use lpt1 + instead. Use lpt2 for the third port, + and so on. + If you want interrupt-driven mode, add the irq specifier: - + device lpt0 at isa? port? tty irq N vector lptintr - Where N is the IRQ number - for your computer's parallel port. + Where N is the IRQ + number for your computer's parallel port. - + If you want polled mode, do not add the irq specifier: - + device lpt0 at isa? port? tty vector lptintr - + Save the file. Then configure, build, and install the - kernel, then reboot. See kernel - configuration for more details. + kernel, then reboot. See kernel configuration for + more details. - + To set the communications mode with - &man.lptcontrol.8;: - + &man.lptcontrol.8;: + Type: - + &prompt.root; lptcontrol -i -u N - + to set interrupt-driven mode for lptN. - + Type: - + &prompt.root; lptcontrol -p -u N - + to set polled-mode for lptN. - + You could put these commands in your - /etc/rc.local file to set the mode each time - your system boots. See &man.lptcontrol.8; for more + /etc/rc.local file to set the mode each + time your system boots. See &man.lptcontrol.8; for more information. Checking Printer Communications - - 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. - + + 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. + To test the printer, we will send some text to it. For printers that can immediately print characters sent to them, the program &man.lptest.1; is perfect: it generates all 96 printable ASCII characters in 96 lines. - - 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: + + 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: %!PS @@ -559,288 +560,302 @@ device lpt0 at isa? port? tty vector lptintr 310 310 moveto /Helvetica findfont 12 scalefont setfont (Is this thing working?) show showpage - + - 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. - - + When this document refers to a printer language, it is + 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. + + Checking a Parallel Printer - + This section tells you how to check if FreeBSD can - communicate with a printer connected to a parallel port. - + communicate with a printer connected to a parallel + port. + To test a printer on a parallel - port: - + port: + Become root with &man.su.1;. - + Send data to the printer. If the printer can print plain text, then use - &man.lptest.1;. Type: - + &man.lptest.1;. Type: + &prompt.root; lptest > /dev/lptN - - Where N is the number of - the parallel port, starting from zero. + + Where N is the number + of the parallel port, starting from zero. - + If the printer understands PostScript or other printer language, then send a small program to the printer. Type: - + &prompt.root; cat > /dev/lptN - + Then, line by line, type the program - carefully 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. - - Alternatively, you can put the program in a file and - type: - + carefully 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. + + Alternatively, you can put the program in a file + and type: + &prompt.root; cat file > /dev/lptN - - Where file is the name of - the file containing the program you want to send to the - printer. + + Where file is the + name of the file containing the program you want to + send to the printer. - - You should see something print. Do not worry if the text - does not look right; we will fix such things later. + + You should see something print. Do not worry if the + text does not look right; we will fix such things + later. - + Checking a Serial Printer - + This section tells you how to check if FreeBSD can communicate with a printer on a serial port. - + To test a printer on a serial - port: - + port: + Become root with &man.su.1;. - + - Edit the file /etc/remote. Add the - following entry: - + Edit the file /etc/remote. Add + the following entry: + printer:dv=/dev/port:br#bps-rate:pa=parity Where port is the device entry for the serial port (ttyd0, ttyd1, etc.), - bps-rate is the bits-per-second - rate at which the printer communicates, and - parity is the parity required by - the printer (either even, + bps-rate is the + bits-per-second rate at which the printer communicates, + and parity is the parity + required by the printer (either even, odd, none, or zero). - - Here is a sample entry for a printer connected via a - serial line to the third serial port at 19200 bps with no - parity: - + + Here is a sample entry for a printer connected via + a serial line to the third serial port at 19200 bps with + no parity: + printer:dv=/dev/ttyd2:br#19200:pa=none - + - Connect to the printer with &man.tip.1;. Type: - + Connect to the printer with &man.tip.1;. + Type: + &prompt.root; tip printer - + If this step does not work, edit the file /etc/remote again and try using /dev/cuaaN instead of /dev/ttydN. - + Send data to the printer. If the printer can print plain text, then use - &man.lptest.1;. Type: - + &man.lptest.1;. Type: + ~$lptest - + If the printer understands PostScript or other printer language, then send a small program to the - printer. Type the program, line by line, very - carefully as backspacing or other editing - keys may be significant to the printer. You may also - need to type a special end-of-file key for the printer - so it knows it received the whole program. For - PostScript printers, press CONTROL+D. - - Alternatively, you can put the program in a file and - type: - + printer. Type the program, line by line, + very carefully as backspacing + or other editing keys may be significant to the + printer. You may also need to type a special + end-of-file key for the printer so it knows it + received the whole program. For PostScript + printers, press CONTROL+D. + + Alternatively, you can put the program in a file + and type: + ~>file - - Where file is the name of - the file containing the program. After - &man.tip.1; sends the file, press any required + + Where file is the + name of the file containing the program. After + &man.tip.1; sends the file, press any required end-of-file key. - - You should see something print. Do not worry if the text - does not look right; we will fix that later. + + You should see something print. Do not worry if the + text does not look right; we will fix that later. - + Enabling the Spooler: The <filename>/etc/printcap</filename> File 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. - + 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. + You configure LPD by editing the file - /etc/printcap. The LPD spooling system reads - this file each time the spooler is used, so updates to the file take - immediate effect. - - The format of the &man.printcap.5; file is straightforward. Use - your favorite text editor to make changes to + /etc/printcap. The LPD spooling system + reads this file each time the spooler is used, so updates to the + file take immediate effect. + + The format of the &man.printcap.5; file is straightforward. + Use your favorite text editor to make changes to /etc/printcap. The format is identical to other capability files like /usr/share/misc/termcap and - /etc/remote. For complete information about - the format, see the &man.cgetent.3;. - + /etc/remote. For complete information + about the format, see the &man.cgetent.3;. + The simple spooler configuration consists of the following steps: - Pick a name (and a few convenient aliases) for the printer, - and put them in the /etc/printcap file; see - Naming the - Printer. + Pick a name (and a few convenient aliases) for the + printer, and put them in the + /etc/printcap file; see the + Naming the Printer + section for more information on naming. - + - Turn off header pages (which are on by default) by inserting - the sh capability; see Suppressing Header - Pages. + Turn off header pages (which are on by default) by + inserting the sh capability; see the + Suppressing Header + Pages section for more information. - + - Make a spooling directory, and specify its location with the - sd capability; see Making the Spooling - Directory. + Make a spooling directory, and specify its location with + the sd capability; see the Making the Spooling + Directory section for more information. - + Set the /dev entry to use for the - printer, and note it in /etc/printcap with - the lp capability; see Identifying the Printer - Device. Also, if the printer is on a serial port, set - up the communication parameters with the fs, - fc, xs, and - xc capabilities; see Configuring Spooler - Communications Parameters. + printer, and note it in /etc/printcap + with the lp capability; see the Identifying the Printer + Device for more information. Also, if the printer is + on a serial port, set up the communication parameters with + the fs, fc, + xs, and xc + capabilities; which is discussed in the Configuring Spooler + Communications Parameters section. - + - Install a plain text input filter; see Installing the Text - Filter + Install a plain text input filter; see the Installing the Text + Filter section for details. - + Test the setup by printing something with the - &man.lpr.1; command; see Trying It Out and Troubleshooting. + &man.lpr.1; command. More details are available in the + Trying It Out and + Troubleshooting + sections. - 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. + 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. - 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 and 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 Accommodating Plain Text - Jobs on PostScript Printers tells how to do this. - + 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 and + 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. The section entitled Accommodating Plain + Text Jobs on PostScript Printers tells how to do + this. + Naming the Printer - - 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. - + + 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. + At least one of the printers specified in the /etc/printcap should have the alias - lp. This is the default printer's name. If - users do not have the PRINTER environment variable - nor specify a printer name on the command line of any of the LPD - commands, then lp will be the default printer - they get to use. - + lp. This is the default printer's name. + If users do not have the PRINTER environment + variable nor specify a printer name on the command line of any + of the LPD commands, then lp will be the + default printer they get to use. + Also, it is common practice to make the last alias for a - printer be a full description of the printer, including make and - model. - - Once you have picked a name and some common aliases, put them - in the /etc/printcap file. The name of the - printer should start in the leftmost column. Separate each alias - with a vertical bar and put a colon after the last alias. - + printer be a full description of the printer, including make + and model. + + Once you have picked a name and some common aliases, put + them in the /etc/printcap file. The name + of the printer should start in the leftmost column. Separate + each alias with a vertical bar and put a colon after the last + alias. + In the following example, we start with a skeletal - /etc/printcap that defines two printers (a - Diablo 630 line printer and a Panasonic KX-P4455 PostScript laser - printer): + /etc/printcap that defines two printers + (a Diablo 630 line printer and a Panasonic KX-P4455 PostScript + laser printer): # @@ -849,14 +864,14 @@ printer:dv=/dev/ttyd2:br#19200:pa=none rattan|line|diablo|lp|Diablo 630 Line Printer: bamboo|ps|PS|S|panasonic|Panasonic KX-P4455 PostScript v51.4: - + In this example, the first printer is named rattan and has as aliases line, diablo, lp, and Diablo 630 Line - Printer. Since it has the alias - lp, it is also the default printer. The second - is named bamboo, and has as aliases + Printer. Since it has the alias + lp, it is also the default printer. The + second is named bamboo, and has as aliases ps, PS, S, panasonic, and Panasonic KX-P4455 PostScript v51.4. @@ -864,20 +879,21 @@ bamboo|ps|PS|S|panasonic|Panasonic KX-P4455 PostScript v51.4: Suppressing Header Pages - + The LPD spooling system will by default print a - header page for each job. The header page - contains the user name who requested the job, the host from which - the job came, and the name of the job, in nice large letters. - Unfortunately, all this extra text gets in the way of debugging - the simple printer setup, so we will suppress header pages. - + header page for each job. The header + page contains the user name who requested the job, the host + from which the job came, and the name of the job, in nice + large letters. Unfortunately, all this extra text gets in the + way of debugging the simple printer setup, so we will suppress + header pages. + To suppress header pages, add the sh capability to the entry for the printer in - /etc/printcap. Here is the example + /etc/printcap. Here is an example /etc/printcap with sh added: - + # # /etc/printcap for host rose - no header pages anywhere @@ -888,59 +904,61 @@ rattan|line|diablo|lp|Diablo 630 Line Printer:\ bamboo|ps|PS|S|panasonic|Panasonic KX-P4455 PostScript v51.4:\ :sh: - 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. + 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. Making the Spooling Directory - + The next step in the simple spooler setup is to make a - spooling directory, a directory where print - jobs reside until they are printed, and where a number of other - spooler support files live. - - Because of the variable nature of spooling directories, it is - customary to put these directories under - /var/spool. It is not necessary to backup - the contents of spooling directories, either. Recreating them is - as simple as running &man.mkdir.1;. - - It is also customary to make the directory with a name that is - identical to the name of the printer, as shown below: - + spooling directory, a directory where + print jobs reside until they are printed, and where a number + of other spooler support files live. + + Because of the variable nature of spooling directories, it + is customary to put these directories under + /var/spool. It is not necessary to + backup the contents of spooling directories, either. + Recreating them is as simple as running &man.mkdir.1;. + + It is also customary to make the directory with a name + that is identical to the name of the printer, as shown + below: + &prompt.root; mkdir /var/spool/printer-name - - 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 rattan and + + 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 + rattan and bamboo: - + &prompt.root; mkdir /var/spool/lpd &prompt.root; mkdir /var/spool/lpd/rattan &prompt.root; mkdir /var/spool/lpd/bamboo - + - 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: - + 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: + &prompt.root; chown daemon.daemon /var/spool/lpd/rattan &prompt.root; chown daemon.daemon /var/spool/lpd/bamboo &prompt.root; chmod 770 /var/spool/lpd/rattan &prompt.root; chmod 770 /var/spool/lpd/bamboo - - Finally, you need to tell LPD about these directories using - the /etc/printcap file. You specify the - pathname of the spooling directory with the sd - capability: + + Finally, you need to tell LPD about these directories + using the /etc/printcap file. You + specify the pathname of the spooling directory with the + sd capability: # @@ -952,35 +970,37 @@ rattan|line|diablo|lp|Diablo 630 Line Printer:\ bamboo|ps|PS|S|panasonic|Panasonic KX-P4455 PostScript v51.4:\ :sh:sd=/var/spool/lpd/bamboo: - 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. - + Note that the name of the printer starts in the first + column but all other entries describing the printer should be + indented with a tab and each line escaped with a + backslash. + If you do not specify a spooling directory with sd, the spooling system will use /var/spool/lpd as a default. - + Identifying the Printer Device - - In section Adding /dev - Entries for the Ports, we identified which entry in the + + In the Adding + /dev Entries for the Ports + section, we identified which entry in the /dev directory FreeBSD will use to - communicate with the printer. Now, we tell LPD that information. - When the spooling system has a job to print, it will open the - specified device on behalf of the filter program (which is - responsible for passing data to the printer). - + communicate with the printer. Now, we tell LPD that + information. When the spooling system has a job to print, it + will open the specified device on behalf of the filter program + (which is responsible for passing data to the printer). + List the /dev entry pathname in the /etc/printcap file using the lp capability. - + In our running example, let us assume that rattan is on the first parallel port, and - bamboo is on a sixth serial port; here are the - additions to /etc/printcap: - + bamboo is on a sixth serial port; here are + the additions to /etc/printcap: + # # /etc/printcap for host rose - identified what devices to use @@ -992,45 +1012,46 @@ rattan|line|diablo|lp|Diablo 630 Line Printer:\ bamboo|ps|PS|S|panasonic|Panasonic KX-P4455 PostScript v51.4:\ :sh:sd=/var/spool/lpd/bamboo:\ :lp=/dev/ttyd5: - - If you do not specify the lp capability for - a printer in your /etc/printcap file, LPD - uses /dev/lp as a default. + + If you do not specify the lp capability + for a printer in your /etc/printcap file, + LPD uses /dev/lp as a default. /dev/lp currently does not exist in FreeBSD. - - If the printer you are installing is connected to a parallel - port, skip to the section Installing the Text Filter. - Otherwise, be sure to follow the instructions in the next - section. + + If the printer you are installing is connected to a + parallel port, skip to the section entitled, Installing the Text + Filter. Otherwise, be sure to follow the instructions + in the next section. - + Configuring Spooler Communication Parameters - + 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 + parity, and other serial communication parameters on behalf of + the filter program that sends data to the printer. This is advantageous since: - + It lets you try different communication parameters by - simply editing the /etc/printcap file; - you do not have to recompile the filter program. + simply editing the /etc/printcap + file; you do not have to recompile the filter + program. - + It enables the spooling system to use the same filter - program for multiple printers which may have different serial - communication settings. + program for multiple printers which may have different + serial communication settings. - The following /etc/printcap capabilities - control serial communication parameters of the device listed in - the lp capability: + The following /etc/printcap + capabilities control serial communication parameters of the + device listed in the lp capability: @@ -1039,69 +1060,75 @@ bamboo|ps|PS|S|panasonic|Panasonic KX-P4455 PostScript v51.4:\ Sets the communications speed of the device to bps-rate, where - bps-rate can be 50, 75, 110, 134, - 150, 200, 300, 600, 1200, 1800, 2400, 4800, 9600, 19200, or - 38400 bits-per-second. + bps-rate can be 50, 75, 110, + 134, 150, 200, 300, 600, 1200, 1800, 2400, 4800, 9600, + 19200, or 38400 bits-per-second. - + fc#clear-bits - + Clears the flag bits clear-bits in the - sgttyb structure after opening - the device. + sgttyb structure after + opening the device. - + fs#set-bits - + - Sets the flag bits set-bits - in the sgttyb structure. + Sets the flag bits + set-bits in the + sgttyb structure. - + xc#clear-bits - + Clears local mode bits clear-bits after opening the device. - + xs#set-bits - + Sets local mode bits set-bits. - + For more information on the bits for the fc, fs, - xc, and xs capabilities, see - the file + xc, and xs capabilities, + see the file /usr/include/sys/ioctl_compat.h. - + When LPD opens the device specified by the - lp capability, it reads the flag bits in the - sgttyb structure; it clears any bits in the - fc capability, then sets bits in the + lp capability, it reads the flag bits in + the sgttyb structure; it clears any bits in + the fc capability, then sets bits in the fs capability, then applies the resultant - setting. It does the same for the local mode bits as well. - - 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: + setting. It does the same for the local mode bits as + well. + + 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: bamboo|ps|PS|S|panasonic|Panasonic KX-P4455 PostScript v51.4:\ @@ -1111,35 +1138,38 @@ bamboo|ps|PS|S|panasonic|Panasonic KX-P4455 PostScript v51.4:\ Installing the Text Filter - - We are now ready to tell LPD what text filter to use to send - jobs to the printer. A text filter, also - known as an input filter, is a program that - LPD runs when it has a job to print. When LPD runs the text - filter for a printer, it sets the filter's standard input to the - job to print, and its standard output to the printer device - specified with the lp 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 Filters. - - For our simple printer setup, the text filter can be a small - shell script that just executes /bin/cat to - send the job to the printer. FreeBSD comes with another filter - called lpf that handles backspacing and - underlining for printers that might not deal with such character - streams well. And, of course, you can use any other filter - program you want. The filter lpf is described - in detail in section lpf: a - Text Filter. - + + We are now ready to tell LPD what text filter to use to + send jobs to the printer. A text filter, + also known as an input filter, is a + program that LPD runs when it has a job to print. When LPD + runs the text filter for a printer, it sets the filter's + standard input to the job to print, and its standard output to + the printer device specified with the lp + 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 + the Filters + section. + + For our simple printer setup, the text filter can be a + small shell script that just executes + /bin/cat to send the job to the printer. + FreeBSD comes with another filter called + lpf that handles backspacing and + underlining for printers that might not deal with such + character streams well. And, of course, you can use any other + filter program you want. The filter lpf is + described in detail in section entitled lpf: a Text + Filter. + First, let us make the shell script - /usr/local/libexec/if-simple be a simple text - filter. Put the following text into that file with your favorite - text editor: - + /usr/local/libexec/if-simple be a simple + text filter. Put the following text into that file with your + favorite text editor: + #!/bin/sh # @@ -1150,17 +1180,17 @@ bamboo|ps|PS|S|panasonic|Panasonic KX-P4455 PostScript v51.4:\ /bin/cat && exit 0 exit 2 - + Make the file executable: - + &prompt.root; chmod 555 /usr/local/libexec/if-simple - + And then tell LPD to use it by specifying it with the if capability in /etc/printcap. We will add it to the two printers we have so far in the example /etc/printcap: - + # # /etc/printcap for host rose - added text filter @@ -1177,357 +1207,2346 @@ bamboo|ps|PS|S|panasonic|Panasonic KX-P4455 PostScript v51.4:\ Trying It Out - + 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 &man.lpr.1;, + 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 &man.lpr.1;, which submits a job for printing. - - You can combine &man.lpr.1; with the &man.lptest.1; program, - introduced in section Checking - Printer Communications to generate some test text. + + You can combine &man.lpr.1; with the &man.lptest.1; + program, introduced in section Checking Printer + Communications to generate some test text. To test the simple LPD setup: - + Type: - + &prompt.root; lptest 20 5 | lpr -Pprinter-name - Where printer-name is a the name of - a printer (or an alias) specified in - /etc/printcap. To test the default printer, - type &man.lpr.1; without any - argument. Again, if you are testing a printer - that expects PostScript, send a PostScript program in that - language instead of using &man.lptest.1;. You can do so by - putting the program in a file and typing lpr - file. + Where printer-name is a the + name of a printer (or an alias) specified in + /etc/printcap. To test the default + printer, type &man.lpr.1; without any + argument. Again, if you are testing a printer that expects + PostScript, send a PostScript program in that language instead + of using &man.lptest.1;. You can do so by putting the program + in a file and typing lpr + file. - For a PostScript printer, you should get the results of the - program. If you are using &man.lptest.1;, then your results - should look like the following: + For a PostScript printer, you should get the results of + the program. If you are using &man.lptest.1;, then your + results should look like the following: - + !"#$%&'()*+,-./01234 "#$%&'()*+,-./012345 #$%&'()*+,-./0123456 $%&'()*+,-./01234567 %&'()*+,-./012345678 - - To further test the printer, try downloading larger programs - (for language-based printers) or running &man.lptest.1; with - different arguments. For example, lptest 80 60 - will produce 60 lines of 80 characters each. - - If the printer did not work, see the next section, Troubleshooting. - - - Troubleshooting - - After performing the simple test with &man.lptest.1;, you - might have gotten one of the following results instead of the - correct printout: - - - - It worked, after awhile; or, it did not eject a full - sheet. - - - 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. - - 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. - - The following replacement for the shell script - /usr/local/libexec/if-simple prints a - form feed after it sends the job to the printer: + To further test the printer, try downloading larger + programs (for language-based printers) or running + &man.lptest.1; with different arguments. For example, + lptest 80 60 will produce 60 lines of 80 + characters each. - -#!/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 - - - - - It produced the “staircase effect.” - - - You got the following on paper: - - -!"#$%&'()*+,-./01234 - "#$%&'()*+,-./012345 - #$%&'()*+,-./0123456 - - You have become another victim of the - staircase effect, caused by conflicting - interpretations of what characters should indicate a - new-line. UNIX-style operating systems use a single - character: ASCII code 10, the line feed (LF). MS-DOS, OS/2, - and others uses a pair of characters, ASCII code 10 - and ASCII code 13 (the carriage return - or CR). Many printers use the MS-DOS convention for - representing new-lines. - - When you print with FreeBSD, your text used just the - line feed character. The printer, upon seeing a line feed - character, advanced the paper one line, but maintained the - same horizontal position on the page for the next character - to print. That is what the carriage return is for: to move - the location of the next character to print to the left edge - of the paper. - - Here is what FreeBSD wants your printer to do: - - - - - - Printer received CR - Printer prints CR - - - - Printer received LF - Printer prints CR + LF - - - - - - Here are some ways to achieve this: - - - - 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. - - - If you boot your system into other operating - systems besides FreeBSD, you may have to - reconfigure the printer to use a - an interpretation for CR and LF characters that those - other operating systems use. You might prefer one of - the other solutions, below. - - - - - Have FreeBSD's serial line driver automatically - convert LF to CR+LF. Of course, this works with - printers on serial ports only. To - enable this feature, set the CRMOD bit in - fs capability in the - /etc/printcap file for the - printer. - - - - Send an escape code to the - printer to have it temporarily treat LF characters - differently. Consult your printer's manual for escape - codes that your printer might support. When you find - the proper escape code, modify the text filter to send - the code first, then send the print job. - - 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. - - -#!/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. Ejects the page when done. - -printf "\033&k2G" && cat && printf "\033&l0H" && exit 0 -exit 2 - - Here is an example - /etc/printcap from a host called - orchid. It has a single printer attached to its first - parallel port, a Hewlett Packard LaserJet 3Si named - teak. It is using the above script as - its text filter: - - -# -# /etc/printcap for host orchid -# -teak|hp|laserjet|Hewlett Packard LaserJet 3Si:\ - :lp=/dev/lpt0:sh:sd=/var/spool/lpd/teak:mx#0:\ - :if=/usr/local/libexec/hpif: - - - - - - - It overprinted each line. - - - The printer never advanced a line. All of the lines of - text were printed on top of each other on one line. - - This problem is the “opposite” of the - staircase effect, described above, and is much rarer. - Somewhere, the LF characters that FreeBSD uses to end a line - are being treated as CR characters to return the print - location to the left edge of the paper, but not also down a - line. - - Use the printer's configuration switches or control - panel to enforce the following interpretation of LF and CR - characters: - - - - - - Printer receives - Printer prints - - - - - - CR - CR - - - - LF - CR + LF - - - - - - - - The printer lost characters. - - - 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. - - 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: - - - - If the printer supports XON/XOFF flow control, have - FreeBSD use it by specifying the TANDEM bit in the - fs capability. - - - - If the printer supports carrier flow control, - specify the MDMBUF bit in the fs - capability. Make sure the cable connecting the printer - to the computer is correctly wired for carrier flow - control. - - - - If the printer does not support any flow control, - use some combination of the NLDELAY, TBDELAY, CRDELAY, - VTDELAY, and BSDELAY bits in the fs - capability to add appropriate delays to the stream of - data sent to the printer. - - - - - - - It printed garbage. - - - The printer printed what appeared to be random garbage, - but not the desired text. - - This is usually another symptom of incorrect - communications parameters with a serial printer. - Double-check the bps rate in the br - capability, and the parity bits in the fs - and fc capabilities; make sure the - printer is using the same settings as specified in the - /etc/printcap file. - - - - - Nothing happened. - - - If nothing happened, the problem is probably within - FreeBSD and not the hardware. Add the log file - (lf) capability to the entry for the - printer you are debugging in the - /etc/printcap file. For example, here - is the entry for rattan, with the - lf capability: - - -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 - - Then, try printing again. Check the log file (in our - example, /var/log/rattan.log) to see - any error messages that might appear. Based on the messages - you see, try to correct the problem. - - If you do not specify a lf - capability, LPD uses /dev/console as a - default. - - - + If the printer did not work, see the Troubleshooting + section. + + Advanced Printer Setup + + This section describes filters for printing specially formatted + files, header pages, printing across networks, and restricting and + accounting for printer usage. + + + Filters + + Although LPD handles network protocols, queuing, access control, + and other aspects of printing, most of the real + work happens in the filters. Filters are + programs that communicate with the printer and handle its device + dependencies and special requirements. In the simple printer setup, + we installed a plain text filter—an extremely simple one that + should work with most printers (section Installing the Text + Filter). + + However, in order to take advantage of format conversion, printer + accounting, specific printer quirks, and so on, you should understand + how filters work. It will ultimately be the filter's responsibility + to handle these aspects. And the bad news is that most of the time + you have to provide filters yourself. The good + news is that many are generally available; when they are not, they are + usually easy to write. + + Also, FreeBSD comes with one, + /usr/libexec/lpr/lpf, that works with many + printers that can print plain text. (It handles backspacing and tabs + in the file, and does accounting, but that is about all it does.) + There are also several filters and filter components in the FreeBSD + ports collection. + + Here is what you will find in this section: + + + + Section 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. + + + + 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 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. + + + + PostScript is a popular output format for many programs. Even + some people (myself included) write PostScript code directly. But + PostScript printers are expensive. Section 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 + non-PostScript printer. I recommend reading + this section if you do not have a PostScript printer. + + + + Section 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 lpr -t to print troff data, or + lpr -d to print TeX DVI data, or lpr + -v to print raster image data, and so forth. I + recommend reading this section. + + + + Section Output + Filters tells all about a not often used feature of LPD: + output filters. Unless you are printing header pages (see Header Pages), + you can probably skip that section altogether. + + + + Section lpf: a Text + Filter describes lpf, a fairly + complete if simple text filter for line printers (and laser + printers that act like line printers) that comes with FreeBSD. If + you need a quick way to get printer accounting working for plain + text, or if you have a printer which emits smoke when it sees + backspace characters, you should definitely consider + lpf. + + + + + How Filters Work + + As mentioned before, a filter is an executable program started + by LPD to handle the device-dependent part of communicating with the + printer. + + When LPD wants to print a file in a job, it starts a filter + program. It sets the filter's standard input to the file to print, + its standard output to the printer, and its standard error to the + error logging file (specified in the lf + capability in /etc/printcap, or + /dev/console by default). + + Which filter LPD starts and the filter's arguments depend on + what is listed in the /etc/printcap file and + what arguments the user specified for the job on the + &man.lpr.1; command line. For example, if the user typed + lpr -t, LPD would start the troff filter, listed + in the tf capability for the destination printer. + If the user wanted to print plain text, it would start the + if filter (this is mostly true: see Output Filters for + details). + + There are three kinds of filters you can specify in + /etc/printcap: + + + + The text filter, confusingly called the + input filter in LPD documentation, handles + regular text printing. Think of it as the default filter. LPD + expects every printer to be able to print plain text by default, + and it 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: + + + filter-name + -c + -wwidth + -llength + -iindent + -n login + -h host + acct-file + + + where + + + + + + + appears if the job's submitted with lpr + -l + + + + + width + + + is the value from the pw (page + width) capability specified in + /etc/printcap, default 132 + + + + + length + + + is the value from the pl (page + length) capability, default 66 + + + + + indent + + + is the amount of the indentation from lpr + -i, default 0 + + + + + login + + + is the account name of the user printing the + file + + + + + host + + + is the host name from which the job was + submitted + + + + + acct-file + + + is the name of the accounting file from the + af capability. + + + + + + + + A conversion filter 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 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: + + + filter-name + -xpixel-width + -ypixel-height + -n login + -h host + acct-file + + + where pixel-width is the value + from the px capability (default 0) and + pixel-height is the value from the + py capability (default 0). + + + + The output filter is used only if there + is no text filter, or if header pages are enabled. In my + experience, output filters are rarely used. Section Output Filters describe + them. There are only two arguments to an output filter: + + + filter-name + -wwidth + -llength + + + which are identical to the text filters and + arguments. + + + + Filters should also exit with the + following exit status: + + + + exit 0 + + + If the filter printed the file successfully. + + + + + exit 1 + + + If the filter failed to print the file but wants LPD to + try to print the file again. LPD will restart a filter if it + exits with this status. + + + + + exit 2 + + + If the filter failed to print the file and does not want + LPD to try again. LPD will throw out the file. + + + + + The text filter that comes with the FreeBSD release, + /usr/libexec/lpr/lpf, takes advantage of the + page width and length arguments to determine when to send a form + feed and how to account for printer usage. It uses the login, host, + and accounting file arguments to make the accounting entries. + + If you 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. + + + + Accommodating Plain Text Jobs on PostScript Printers + + 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. + + 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 + %! (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. + + How do we do this? + + If you have got a serial printer, a great way to do it is to + install lprps. lprps is a + PostScript printer filter which performs two-way communication with + the printer. It updates the printer's status file with verbose + information from the printer, so users and administrators can see + exactly what the state of the printer is (such as toner + low or paper jam). But more + importantly, it includes a program called psif + which detects whether the incoming job is plain text and calls + textps (another program that comes with + lprps) to convert it to PostScript. It then uses + lprps to send the job to the printer. + + lprps is part of the FreeBSD ports collection + (see The Ports Collection). You can + fetch, build and install it yourself, of course. After installing + lprps, just specify the pathname to the + psif program that is part of + lprps. If you installed lprps + from the ports collection, use the following in the serial + PostScript printer's entry in + /etc/printcap: + + +:if=/usr/local/libexec/psif: + + You should also specify the rw capability; + that tells LPD to open the printer in read-write mode. + + If you have a parallel PostScript printer (and therefore cannot + use two-way communication with the printer, which + lprps needs), you can use the following shell + script as the text filter: + + +#!/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 + + In the above script, textps is a program we + installed separately to convert plain text to PostScript. You can + use any text-to-PostScript program you wish. The FreeBSD ports + collection (see The Ports Collection) + includes a full featured text-to-PostScript program called + a2ps that you might want to investigate. + + + + Simulating PostScript on Non-PostScript Printers + + PostScript is the de facto standard for + high quality typesetting and printing. PostScript is, however, an + expensive standard. Thankfully, Alladin + Enterprises has a free PostScript work-alike called + Ghostscript that runs with FreeBSD. + Ghostscript can read most PostScript files and can render their + pages onto a variety of devices, including many brands of + non-PostScript printers. By installing Ghostscript and using a + special text filter for your printer, you can make your + non-PostScript printer act like a real PostScript printer. + + Ghostscript should be in the FreeBSD ports collection, if you + would like to install it from there. You can fetch, build, and + install it quite easily yourself, as well. + + To simulate PostScript, we have the text filter detect if it 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. + + Here is an example: the following script is a text filter + for Hewlett Packard DeskJet 500 printers. For other printers, + substitute the argument to the + gs (Ghostscript) command. (Type gs + -h to get a list of devices the current installation of + Ghostscript supports.) + + +#!/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. + # + # Note that PostScript files are actually interpreted programs, + # and those programs are allowed to write to stdout, which will + # mess up the printed output. So, we redirect stdout to stderr + # and then make descriptor 3 go to stdout, and have Ghostscript + # write its output there. Exercise for the clever reader: + # capture the stderr output from Ghostscript and mail it back to + # the user originating the print job. + # + exec 3>&1 1>&2 + /usr/local/bin/gs -dSAFER -dNOPAUSE -q -sDEVICE=djet500 \ + -sOutputFile=/dev/fd/3 - && exit 0 + + # + /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 "\033&l0H" && +exit 0 +fi + +exit 2 + + Finally, you need to notify LPD of the filter via the + if capability: + + +:if=/usr/local/libexec/hpif: + + That is it. You can type lpr plain.text and + lpr whatever.ps and both should print + successfully. + + + + Conversion Filters + + After completing the simple setup described in 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). + + + Why Install Conversion Filters? + + 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: + + &prompt.user; dvips seaweed-analysis.dvi +&prompt.user; lpr seaweed-analysis.ps + + 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: + + &prompt.user; lpr -d seaweed-analysis.dvi + + We got LPD to do the DVI file conversion for us by specifying + the option. Section Formatting and Conversion + Options lists the conversion options. + + For each of the conversion options you want a printer to + support, install a conversion filter and + specify its pathname in /etc/printcap. A + conversion filter is like the text filter for the simple printer + setup (see section Installing + the Text Filter) except that instead of printing plain + text, the filter converts the file into a format the printer can + understand. + + + + Which Conversions Filters Should I Install? + + 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. + + The following table summarizes the filters that LPD works + with, their capability entries for the + /etc/printcap file, and how to invoke them + with the lpr command: + + + + + + File type + /etc/printcap capability + lpr option + + + + + + cifplot + cf + + + + + DVI + df + + + + + plot + gf + + + + + ditroff + nf + + + + + FORTRAN text + rf + + + + + troff + rf + + + + + raster + vf + + + + + plain text + if + none, , or + + + + + + + In our example, using lpr -d means the + printer needs a df capability in its entry in + /etc/printcap. + + Despite what others might contend, formats like FORTRAN text + and plot are probably obsolete. At your site, you can give new + meanings to these or any of the formatting options just by + installing custom filters. For example, suppose you 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 + gf capability and then educate your users that + lpr -g mean “print Printerleaf + files.” + + + + Installing Conversion Filters + + Since conversion filters are programs you install outside of + the base FreeBSD installation, they should probably go under + /usr/local. The directory + /usr/local/libexec is a popular location, + since they are specialized programs that only LPD will run; + regular users should not ever need to run them. + + To enable a conversion filter, specify its pathname under the + appropriate capability for the destination printer in + /etc/printcap. + + In our example, we will add the DVI conversion filter to the + entry for the printer named bamboo. Here is + the example /etc/printcap file again, with + the new df capability for the printer + bamboo. + + +# +# /etc/printcap for host rose - added df filter for bamboo +# +rattan|line|diablo|lp|Diablo 630 Line Printer:\ + :sh:sd=/var/spool/lpd/rattan:\ + :lp=/dev/lpt0:\ + :if=/usr/local/libexec/if-simple: + +bamboo|ps|PS|S|panasonic|Panasonic KX-P4455 PostScript v51.4:\ + :sh:sd=/var/spool/lpd/bamboo:\ + :lp=/dev/ttyd5:fs#0x82000e1:xs#0x820:rw:\ + :if=/usr/local/libexec/psif:\ + :df=/usr/local/libexec/psdf: + + The DVI filter is a shell script named + /usr/local/libexec/psdf. Here is that + script: + + +#!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 "$@" + + This script runs dvips in filter mode (the + argument) on standard input, which is the job + to print. It then starts the PostScript printer filter + lprps (see section Accommodating Plain + Text Jobs on PostScript Printers) with the arguments LPD + passed to this script. lprps will use those + arguments to account for the pages printed. + + + + More Conversion Filter Examples + + 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. + + This example script is a raster (well, GIF file, actually) + conversion filter for a Hewlett Packard LaserJet III-Si + printer: + + +#!/bin/sh +# +# hpvf - Convert GIF files into HP/PCL, then print +# Installed in /usr/local/libexec/hpvf + +PATH=/usr/X11R6/bin:$PATH; export PATH +giftopnm | ppmtopgm | pgmtopbm | pbmtolj -resolution 300 \ + && exit 0 \ + || exit 2 + + It works by converting the GIF file into a portable anymap, + converting that into a portable graymap, converting that into a + portable bitmap, and converting that into LaserJet/PCL-compatible + data. + + Here is the /etc/printcap file with an + entry for a printer using the above filter: + + +# +# /etc/printcap for host orchid +# +teak|hp|laserjet|Hewlett Packard LaserJet 3Si:\ + :lp=/dev/lpt0:sh:sd=/var/spool/lpd/teak:mx#0:\ + :if=/usr/local/libexec/hpif:\ + :vf=/usr/local/libexec/hpvf: + + The following script is a conversion filter for troff data + from the groff typesetting system for the PostScript printer named + bamboo: + + +#!/bin/sh +# +# pstf - Convert groff's troff data into PS, then print. +# Installed in /usr/local/libexec/pstf +# +exec grops | /usr/local/libexec/lprps "$@" + + The above script makes use of lprps again + to handle the communication with the printer. If the printer were + on a parallel port, we would use this script instead: + + +#!/bin/sh +# +# pstf - Convert groff's troff data into PS, then print. +# Installed in /usr/local/libexec/pstf +# +exec grops + + That is it. Here is the entry we need to add to + /etc/printcap to enable the filter: + + +:tf=/usr/local/libexec/pstf: + + 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 + teak: + + +#!/bin/sh +# +# hprf - FORTRAN text filter for LaserJet 3si: +# Installed in /usr/local/libexec/hprf +# + +printf "\033&k2G" && fpr && printf "\033&l0H" && + exit 0 +exit 2 + + And we will add this line to the + /etc/printcap for the printer + teak to enable this filter: + + +:rf=/usr/local/libexec/hprf: + + Here is one final, somewhat complex example. We will add a + DVI filter to the LaserJet printer teak + introduced earlier. First, the easy part: updating + /etc/printcap with the location of the DVI + filter: + + +:df=/usr/local/libexec/hpdf: + + Now, for the hard part: making the filter. For that, we need + a DVI-to-LaserJet/PCL conversion program. The FreeBSD ports + collection (see The Ports Collection) + has one: dvi2xx is the name of the package. + Installing this package gives us the program we need, + dvilj2p, which converts DVI into LaserJet IIp, + LaserJet III, and LaserJet 2000 compatible codes. + + dvilj2p makes the filter + hpdf quite complex since + dvilj2p cannot read from standard input. It + wants to work with a filename. What is worse, the filename has to + end in .dvi so using + /dev/fd/0 for standard input is problematic. + We can get around that problem by linking (symbolically) a + temporary file name (one that ends in .dvi) + to /dev/fd/0, thereby forcing + dvilj2p to read from standard input. + + The only other fly in the ointment is the fact that we cannot + use /tmp for the temporary link. Symbolic + links are owned by user and group bin. The + filter runs as user daemon. And the + /tmp 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. + + Instead, the filter will make the symbolic link in the current + working directory, which is the spooling directory (specified by + the sd capability in + /etc/printcap). 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 + /tmp. + + Here, finally, is the filter: + + +#!/bin/sh +# +# hpdf - Print DVI data on HP/PCL printer +# Installed in /usr/local/libexec/hpdf + +PATH=/usr/local/bin:$PATH; export PATH + +# +# Define a function to clean up our temporary files. These exist +# in the current directory, which will be the spooling directory +# for the printer. +# +cleanup() { + rm -f hpdf$$.dvi +} + +# +# Define a function to handle fatal errors: print the given message +# and exit 2. Exiting with 2 tells LPD to 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 + + + + Automated Conversion: An Alternative To Conversion + Filters + + All these conversion filters accomplish a lot for your + printing environment, but at the cost forcing the user to specify + (on the &man.lpr.1; 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. + + 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 + file can be of help here. Of course, it will + be hard to determine the differences between + some file types—and, of course, you can + still provide conversion filters just for them. + + The FreeBSD ports collection has a text filter that performs + automatic conversion called apsfilter. It can + detect plain text, PostScript, and DVI files, run the proper + conversions, and print. + + + + + Output Filters + + 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: + + + + LPD starts an output filter once for the entire job instead + of once for each file in the job. + + + + LPD does not make any provision to identify the start or the + end of files within the job for the output filter. + + + + 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: + + + filter-name + -wwidth + -llength + + + Where width is from the + pw capability and + length is from the + pl capability for the printer in + question. + + + + 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 will not work. Use a text filter (also + known as an input filter); see section Installing the Text Filter. + Furthermore, an output filter is actually more + complex in that it has to examine the byte stream being + sent to it for special flag characters and must send signals to + itself on behalf of LPD. + + However, an output filter is necessary if + you want header pages and need to send escape sequences or other + initialization strings to be able to print the header page. (But it + is also futile 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.) + + 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 Header Pages) + only. LPD then expects the output filter to stop + itself by sending two bytes to the filter: ASCII 031 + followed by ASCII 001. When an output filter sees these two bytes + (031, 001), it should stop by sending SIGSTOP to itself. When LPD's + done running other filters, it will restart the output filter by + sending SIGCONT to it. + + If there is an output filter but no text + filter and LPD is working on a plain text job, LPD uses the output + filter to do the job. As stated before, the output filter will + print each file of the job in sequence with no intervening form + feeds or other paper advancement, and this is probably + not what you want. In almost all cases, you + need a text filter. + + The program lpf, 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 lpf. You + can also wrap lpf in a shell script to handle any + initialization codes the printer might require. + + + + <command>lpf</command>: a Text Filter + + The program /usr/libexec/lpr/lpf that comes + with FreeBSD binary distribution is a text filter (input filter) + that can indent output (job submitted with lpr + -i), allow literal characters to pass (job submitted + with lpr -l), adjust the printing position for + backspaces and tabs in the job, and account for pages printed. It + can also act like an output filter. + + lpf 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 + lpf. + + In order for lpf to do page accounting + correctly, it needs correct values filled in for the + pw and pl capabilities in the + /etc/printcap file. It uses these values to + determine how much text can fit on a page and how many pages were in + a user's job. For more information on printer accounting, see Accounting for Printer + Usage. + + + + + Header Pages + + If you have lots of users, all of them using + various printers, then you probably want to consider header + pages as a necessary evil. + + Header pages, also known as banner or + burst pages 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.) + + The LPD system can provide header pages automatically for your + printouts if 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 Header Pages on + PostScript Printers. + + + Enabling Header Pages + + In the Simple Printer + Setup, we turned off header pages by specifying + sh (meaning “suppress header”) in the + /etc/printcap file. To enable header pages for + a printer, just remove the sh capability. + + Sounds too easy, right? + + You are right. You might 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: + + +#!/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 + + Specify the path to the output filter in the + of capability. See Output Filters for more + information. + + Here is an example /etc/printcap file for + the printer teak that we introduced earlier; we + enabled header pages and added the above output filter: + + +# +# /etc/printcap for host orchid +# +teak|hp|laserjet|Hewlett Packard LaserJet 3Si:\ + :lp=/dev/lpt0:sd=/var/spool/lpd/teak:mx#0:\ + :if=/usr/local/libexec/hpif:\ + :vf=/usr/local/libexec/hpvf:\ + :of=/usr/local/libexec/hpof: + + Now, when users print jobs to teak, they get + a header page with each job. If users want to spend time searching + for their printouts, they can suppress header pages by submitting + the job with lpr -h; see Header Page Options for + more &man.lpr.1; options. + + + 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 ff + capability in /etc/printcap. + + + + + Controlling Header Pages + + By enabling header pages, LPD will produce a long + header, 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): + + + 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 + + LPD appends a form feed after this text so the job starts on a + new page (unless you have sf (suppress form + feeds) in the destination printer's entry in + /etc/printcap). + + If you prefer, LPD can make a short header; + specify sb (short banner) in the + /etc/printcap file. The header page will look + like this: + + +rose:kelly Job: outline Date: Sun Sep 17 11:07:51 1995 + + Also by default, LPD prints the header page first, then the job. + To reverse that, specify hl (header last) in + /etc/printcap. + + + + Accounting for Header Pages + + Using LPD's built-in header pages enforces a particular paradigm + when it comes to printer accounting: header pages must be + free of charge. + + Why? + + Because the output filter is the only external program that will + have control when the header page is printed that could do + accounting, and it is not provided with any user or + host 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 lpr -h. + They could still be charged for header pages they did not print. + Basically, lpr -h will be the preferred option of + environmentally-minded users, but you cannot offer any incentive to + use it. + + It is still not enough to have each of the + filters generate their own header pages (thereby being able to + charge for them). If users wanted the option of suppressing the + header pages with lpr -h, they will still get + them and be charged for them since LPD does not pass any knowledge + of the option to any of the filters. + + So, what are your options? + + You can: + + + + Accept LPD's paradigm and make header pages free. + + + + Install an alternative to LPD, such as LPRng or PLP. Section + Alternatives to the + Standard Spooler tells more about other spooling + software you can substitute for LPD. + + + + Write a smart 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 af capability), but if you have a + well-known accounting file, you can hard-code that into the + output filter. To facilitate the parsing step, use the + sh (short header) capability in + /etc/printcap. Then again, all that might + be too much trouble, and users will certainly appreciate the + more generous system administrator who makes header pages + free. + + + + + + Header Pages on PostScript Printers + + 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. + + 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 lpr + -h. + + 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: + + +#!/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 + + 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: + + +#!/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 + + 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 How Filters + Work). + + As we have mentioned before, the above scheme, though fairly + simple, disables the “suppress header page” option (the + option) to lpr. 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. + + To allow users to shut off header pages on a per-job basis, you + will need to use the trick introduced in section 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 lpr -h, 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. + + If you have a PostScript printer on a serial line, you can make + use of lprps, which comes with an output filter, + psof, which does the above. Note that + psof does not charge for header pages. + + + + + Networked Printing + + FreeBSD supports networked printing: sending jobs to remote + printers. Networked printing generally refers to two different + things: + + + + 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 Printers Installed on + Remote Hosts tells how to do this. + + + + 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: + + + + 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 Printers + Installed on Remote Hosts to set up such a + printer. + + + + 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 Printers with + Networked Data Stream Interfaces gives some + suggestions on installing such printers. + + + + + + + Printers Installed on Remote Hosts + + The LPD spooling system has built-in support for sending jobs to + other hosts also running LPD (or are compatible with LPD). This + feature enables you to install a printer on one host and make it + accessible from other hosts. It also works with printers that have + network interfaces that understand the LPD protocol. + + To enable this kind of remote printing, first install a printer + on one host, the printer host, using the simple + printer setup described in Simple + Printer Setup. Do any advanced setup in 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. Also ensure that the + local host has authorization to use the LPD + service in the remote host (see Restricting Jobs + from Remote Printers). + + If you are using a printer with a network interface that is + compatible with LPD, then the printer host in + the discussion below is the printer itself, and the + printer name is the name you configured for the + printer. See the documentation that accompanied your printer and/or + printer-network interface. + + + If you are using a Hewlett Packard Laserjet then the printer + name text will automatically perform the LF to + CRLF conversion for you, so you will not require the + hpif script. + + + Then, on the other hosts you want to have access to the printer, + make an entry in their /etc/printcap files with + the following: + + + + Name the entry anything you want. For simplicity, though, + you probably want to use the same name and aliases as on the + printer host. + + + + Leave the lp capability blank, explicitly + (:lp=:). + + + + Make a spooling directory and specify its location in the + sd capability. LPD will store jobs here + before they get sent to the printer host. + + + + Place the name of the printer host in the + rm capability. + + + + Place the printer name on the printer + host in the rp + capability. + + + + That is it. You do not need to list conversion filters, page + dimensions, or anything else in the + /etc/printcap file. + + Here is an example. The host rose has two + printers, bamboo and rattan. + We will enable users on the host orchid to print to those printers. + Here is the /etc/printcap file for + orchid (back from section Enabling Header + Pages). It already had the entry for the printer + teak; we have added entries for the two printers + on the host rose: + + +# +# /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: + + Then, we just need to make spooling directories on + orchid: + + &prompt.root; mkdir -p /var/spool/lpd/rattan /var/spool/lpd/bamboo +&prompt.root; chmod 770 /var/spool/lpd/rattan /var/spool/lpd/bamboo +&prompt.root; chown daemon.daemon /var/spool/lpd/rattan /var/spool/lpd/bamboo + + Now, users on orchid can print to + rattan and bamboo. If, for + example, a user on orchid typed + + &prompt.user; lpr -P bamboo -d sushi-review.dvi + + the LPD system on orchid would copy the job to the spooling + directory /var/spool/lpd/bamboo and note that + it was a DVI job. As soon as the host rose has room in its + bamboo spooling directory, the two LPDs would + transfer the file to rose. The file would wait in rose's queue + until it was finally printed. It would be converted from DVI to + PostScript (since bamboo is a PostScript printer) on rose. + + + + Printers with Networked Data Stream Interfaces + + 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 Printers Installed on + Remote Hosts. + + The format of the /etc/printcap 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. + + 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 + netprint takes all data on standard input and + sends it to a network-attached printer. We specify the hostname of + the printer as the first argument and the port number to which to + connect as the second argument to netprint. Note + that this supports one-way communication only (FreeBSD to printer); + many network printers support two-way communication, and you might + want to take advantage of that (to get printer status, perform + accounting, etc.). + + +#!/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; + + 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: + + +#!/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 + + + + + Restricting Printer Usage + + 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. + + + Restricting Multiple Copies + + The LPD system makes it easy for users to print multiple copies + of a file. Users can print jobs with lpr -#5 + (for example) and get five copies of each file in the job. Whether + this is a good thing is up to you. + + If you feel multiple copies cause unnecessary wear and tear on + your printers, you can disable the option to + &man.lpr.1; by adding the sc capability to the + /etc/printcap file. When users submit jobs + with the option, they will see: + + lpr: multiple copies are not allowed + + + Note that if you have set up access to a printer remotely (see + section Printers + Installed on Remote Hosts), you need the + sc capability on the remote + /etc/printcap files as well, or else users will + still be able to submit multiple-copy jobs by using another + host. + + Here is an example. This is the + /etc/printcap file for the host + rose. The printer rattan is + quite hearty, so we will allow multiple copies, but the laser + printer bamboo's a bit more delicate, so we will + disable multiple copies by adding the sc + capability: + + +# +# /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: + + Now, we also need to add the sc capability on + the host orchid's + /etc/printcap (and while we are at it, let us + disable multiple copies for the printer + teak): + + +# +# /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: + + By using the sc capability, we prevent the + use of lpr -#, but that still does not prevent + users from running &man.lpr.1; + multiple times, or from submitting the same file multiple times in + one job like this: + + &prompt.user; lpr forsale.sign forsale.sign forsale.sign forsale.sign forsale.sign + + There are many ways to prevent this abuse (including ignoring + it) which you are free to explore. + + + + Restricting Access To Printers + + You can control who can print to what printers by using the UNIX + group mechanism and the rg capability in + /etc/printcap. Just place the users you want + to have access to a printer in a certain group, and then name that + group in the rg capability. + + Users outside the group (including root) will be greeted with + + lpr: Not a member of the restricted group + + if they try to print to the controlled printer. + + As with the sc (suppress multiple copies) + capability, you need to specify rg on remote + hosts that also have access to your printers, if you feel it is + appropriate (see section Printers Installed on + Remote Hosts). + + For example, we will let anyone access the printer + rattan, but only those in group + artists can use bamboo. Here + is the familiar /etc/printcap for host + rose: + + +# +# /etc/printcap for host rose - restricted group for bamboo +# +rattan|line|diablo|lp|Diablo 630 Line Printer:\ + :sh:sd=/var/spool/lpd/rattan:\ + :lp=/dev/lpt0:\ + :if=/usr/local/libexec/if-simple: + +bamboo|ps|PS|S|panasonic|Panasonic KX-P4455 PostScript v51.4:\ + :sh:sd=/var/spool/lpd/bamboo:sc:rg=artists:\ + :lp=/dev/ttyd5:fs#0x82000e1:xs#0x820:rw:\ + :if=/usr/local/libexec/psif:\ + :df=/usr/local/libexec/psdf: + + Let us leave the other example + /etc/printcap file (for the host + orchid) alone. Of course, anyone on + orchid can print to bamboo. It + might be the case that we only allow certain logins on + orchid anyway, and want them to have access to the + printer. Or not. + + + There can be only one restricted group per printer. + + + + + Controlling Sizes of Jobs Submitted + + 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. + + LPD enables you to limit the maximum byte size a file in a job + can be with the mx 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; however, if no + mx capability is specified, then a default limit + of 1000 blocks will be used. + + + The limit applies to files in a job, and + not the total job size. + + + 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. + + Let us add limits to our example printers + rattan and bamboo. 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: + + +# +# /etc/printcap for host rose +# + +# +# No limit on job size: +# +rattan|line|diablo|lp|Diablo 630 Line Printer:\ + :sh:mx#0:sd=/var/spool/lpd/rattan:\ + :lp=/dev/lpt0:\ + :if=/usr/local/libexec/if-simple: + +# +# Limit of five megabytes: +# +bamboo|ps|PS|S|panasonic|Panasonic KX-P4455 PostScript v51.4:\ + :sh:sd=/var/spool/lpd/bamboo:sc:rg=artists:mx#5000:\ + :lp=/dev/ttyd5:fs#0x82000e1:xs#0x820:rw:\ + :if=/usr/local/libexec/psif:\ + :df=/usr/local/libexec/psdf: + + Again, the limits apply to the local users only. If you have + set up access to your printers remotely, remote users will not get + those limits. You will need to specify the mx + capability in the remote /etc/printcap files as + well. See section Printers Installed on + Remote Hosts for more information on remote + printing. + + There is another specialized way to limit job sizes from remote + printers; see section Restricting Jobs + from Remote Printers. + + + + Restricting Jobs from Remote Printers + + The LPD spooling system provides several ways to restrict print + jobs submitted from remote hosts: + + + + Host restrictions + + + You can control from which remote hosts a local LPD + accepts requests with the files + /etc/hosts.equiv and + /etc/hosts.lpd. LPD checks to see if an + incoming request is from a host listed in either one of these + files. If not, LPD refuses the request. + + The format of these files is simple: one host name per + line. Note that the file + /etc/hosts.equiv is also used by the + &man.ruserok.3; protocol, and affects programs like + &man.rsh.1; and &man.rcp.1;, so be careful. + + For example, here is the + /etc/hosts.lpd file on the host + rose: + + +orchid +violet +madrigal.fishbaum.de + + This means rose will accept requests from + the hosts orchid, violet, + and madrigal.fishbaum.de. If any + other host tries to access rose's LPD, LPD + will refuse them. + + + + + Size restrictions + + + You can control how much free space there needs to remain + on the filesystem where a spooling directory resides. Make a + file called minfree in the spooling + directory for the local printer. Insert in that file a number + representing how many disk blocks (512 bytes) of free space + there has to be for a remote job to be accepted. + + This lets you insure that remote users 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 + minfree file. + + For example, let us add a minfree + file for the printer bamboo. We examine + /etc/printcap to find the spooling + directory for this printer; here is bamboo's + entry: + + +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: + + The spooling directory is the given in the + sd 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: + + &prompt.root; echo 6144 > /var/spool/lpd/bam +boo/minfree + + + + + User restrictions + + + You can control which remote users can print to local + printers by specifying the rs capability in + /etc/printcap. When + rs appears in the entry for a + locally-attached printer, LPD will accept jobs from remote + hosts if the user submitting the job also + has an account of the same login name on the local host. + Otherwise, LPD refuses the job. + + This capability is particularly useful in an environment + where there are (for example) different departments sharing a + network, and some users transcend departmental boundaries. By + giving them accounts on your systems, they can use your + printers from their own departmental systems. If you would + rather allow them to use only your + printers and not your compute resources, you can give them + “token” accounts, with no home directory and a + useless shell like /usr/bin/false. + + + + + + + + Accounting for Printer Usage + + 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? + + 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 + your requirements in charging for printer + usage. + + To implement accounting, you have to modify a printer's text + filter (to charge for plain text jobs) and the conversion filters (to + charge for other file formats), to count pages or query the printer + for pages printed. You cannot get away with using the simple output + filter, since it cannot do accounting. See section Filters. + + Generally, there are two ways to do accounting: + + + + Periodic accounting 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. + + + + Timely accounting 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. + + + + 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. + + + Quick and Dirty Printer Accounting + + FreeBSD comes with two programs that can get you set up with + simple periodic accounting right away. They are the text filter + lpf, described in section lpf: a Text Filter, and + &man.pac.8;, a program to gather and total + entries from printer accounting files. + + As mentioned in the section on filters (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 af capability in + /etc/printcap, and if not specified as an + absolute path, is relative to the spooling directory. + + LPD starts lpf with page width and length + arguments (from the pw and pl + capabilities). lpf uses these arguments to + determine how much paper will be used. After sending the file to + the printer, it then writes an accounting entry in the accounting + file. The entries look like this: + + +2.00 rose:andy +3.00 rose:kelly +3.00 orchid:mary +5.00 orchid:mary +2.00 orchid:zhang + + You should use a separate accounting file for each printer, as + lpf has no file locking logic built into it, and + two lpfs 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 + af=acct in /etc/printcap. + Then, each accounting file will be in the spooling directory for a + printer, in a file named acct. + + When you are ready to charge users for printouts, run the + &man.pac.8; program. Just change to the spooling directory for + the printer you want to collect on and type pac. + You will get a dollar-centric summary like the following: + + 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 + + These are the arguments &man.pac.8; expects: + + + + + + + Which printer to summarize. + This option works only if there is an absolute path in the + af capability in + /etc/printcap. + + + + + + + + Sort the output by cost instead of alphabetically by user + name. + + + + + + + + Ignore host name in the accounting files. With this + option, user smith on host + alpha is the same user + smith on host gamma. + Without, they are different users. + + + + + + + + Compute charges with price + dollars per page or per foot instead of the price from the + pc capability in + /etc/printcap, or two cents (the + default). You can specify price as + a floating point number. + + + + + + + + Reverse the sort order. + + + + + + + + Make an accounting summary file and truncate the + accounting file. + + + + + name + + + + Print accounting information for the given user + names only. + + + + + In the default summary that &man.pac.8; 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 pac -m, to produce the following + summary: + + 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 + + + To compute the dollar amount due, + &man.pac.8; uses the pc capability in the + /etc/printcap 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 &man.pac.8; with the + option. The units for the + option are in dollars, though, not hundredths of cents. For + example, + + &prompt.root; pac -p1.50 + + makes each page cost one dollar and fifty cents. You can really + rake in the profits by using this option. + + Finally, running pac -s will save the summary + information in a summary accounting file, which is named the same as + the printer's accounting file, but with _sum + appended to the name. It then truncates the accounting file. When + you run &man.pac.8; again, it rereads the + summary file to get starting totals, then adds information from the + regular accounting file. + + + + How Can You Count Pages Printed? + + In order to perform even remotely accurate accounting, you need + to be able to determine how much paper a job uses. This is the + essential problem of printer accounting. + + For plain text jobs, the problem's not that hard to solve: you + count how many lines are in a job and compare it to how many lines + per page your printer supports. 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. + + The text filter lpf (introduced in 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 lpf's source code. + + How do you handle other file formats, though? + + Well, for DVI-to-LaserJet or DVI-to-PostScript conversion, you + can have your filter parse the diagnostic output of + dvilj or dvips and look to see + how many pages were converted. You might be able to do similar + things with other file formats and conversion programs. + + But these methods suffer from the fact that the printer may not + actually print all those pages. For example, it could jam, run out + of toner, or explode—and the user would still get + charged. + + So, what can you do? + + There is only one sure way to do + accurate accounting. Get a printer that can + tell you how much paper it uses, and attach it via a serial line or + a network connection. Nearly all PostScript printers support this + notion. Other makes and models do as well (networked Imagen laser + printers, for example). Modify the filters for these printers to + get the page usage after they print each job and have them log + accounting information based on that value + only. There is no line counting nor + error-prone file examination required. + + Of course, you can always be generous and make all printouts + free. + + + + Using Printers @@ -2243,2289 +4262,6 @@ cfA013rose dequeued - - Advanced Printer Setup - - This section describes filters for printing specially formatted - files, header pages, printing across networks, and restricting and - accounting for printer usage. - - - Filters - - Although LPD handles network protocols, queuing, access control, - and other aspects of printing, most of the real - work happens in the filters. Filters are - programs that communicate with the printer and handle its device - dependencies and special requirements. In the simple printer setup, - we installed a plain text filter—an extremely simple one that - should work with most printers (section Installing the Text - Filter). - - However, in order to take advantage of format conversion, printer - accounting, specific printer quirks, and so on, you should understand - how filters work. It will ultimately be the filter's responsibility - to handle these aspects. And the bad news is that most of the time - you have to provide filters yourself. The good - news is that many are generally available; when they are not, they are - usually easy to write. - - Also, FreeBSD comes with one, - /usr/libexec/lpr/lpf, that works with many - printers that can print plain text. (It handles backspacing and tabs - in the file, and does accounting, but that is about all it does.) - There are also several filters and filter components in the FreeBSD - ports collection. - - Here is what you will find in this section: - - - - Section 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. - - - - 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 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. - - - - PostScript is a popular output format for many programs. Even - some people (myself included) write PostScript code directly. But - PostScript printers are expensive. Section 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 - non-PostScript printer. I recommend reading - this section if you do not have a PostScript printer. - - - - Section 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 lpr -t to print troff data, or - lpr -d to print TeX DVI data, or lpr - -v to print raster image data, and so forth. I - recommend reading this section. - - - - Section Output - Filters tells all about a not often used feature of LPD: - output filters. Unless you are printing header pages (see Header Pages), - you can probably skip that section altogether. - - - - Section lpf: a Text - Filter describes lpf, a fairly - complete if simple text filter for line printers (and laser - printers that act like line printers) that comes with FreeBSD. If - you need a quick way to get printer accounting working for plain - text, or if you have a printer which emits smoke when it sees - backspace characters, you should definitely consider - lpf. - - - - - How Filters Work - - As mentioned before, a filter is an executable program started - by LPD to handle the device-dependent part of communicating with the - printer. - - When LPD wants to print a file in a job, it starts a filter - program. It sets the filter's standard input to the file to print, - its standard output to the printer, and its standard error to the - error logging file (specified in the lf - capability in /etc/printcap, or - /dev/console by default). - - Which filter LPD starts and the filter's arguments depend on - what is listed in the /etc/printcap file and - what arguments the user specified for the job on the - &man.lpr.1; command line. For example, if the user typed - lpr -t, LPD would start the troff filter, listed - in the tf capability for the destination printer. - If the user wanted to print plain text, it would start the - if filter (this is mostly true: see Output Filters for - details). - - There are three kinds of filters you can specify in - /etc/printcap: - - - - The text filter, confusingly called the - input filter in LPD documentation, handles - regular text printing. Think of it as the default filter. LPD - expects every printer to be able to print plain text by default, - and it 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: - - - filter-name - -c - -wwidth - -llength - -iindent - -n login - -h host - acct-file - - - where - - - - - - - appears if the job's submitted with lpr - -l - - - - - width - - - is the value from the pw (page - width) capability specified in - /etc/printcap, default 132 - - - - - length - - - is the value from the pl (page - length) capability, default 66 - - - - - indent - - - is the amount of the indentation from lpr - -i, default 0 - - - - - login - - - is the account name of the user printing the - file - - - - - host - - - is the host name from which the job was - submitted - - - - - acct-file - - - is the name of the accounting file from the - af capability. - - - - - - - - A conversion filter 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 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: - - - filter-name - -xpixel-width - -ypixel-height - -n login - -h host - acct-file - - - where pixel-width is the value - from the px capability (default 0) and - pixel-height is the value from the - py capability (default 0). - - - - The output filter is used only if there - is no text filter, or if header pages are enabled. In my - experience, output filters are rarely used. Section Output Filters describe - them. There are only two arguments to an output filter: - - - filter-name - -wwidth - -llength - - - which are identical to the text filters and - arguments. - - - - Filters should also exit with the - following exit status: - - - - exit 0 - - - If the filter printed the file successfully. - - - - - exit 1 - - - If the filter failed to print the file but wants LPD to - try to print the file again. LPD will restart a filter if it - exits with this status. - - - - - exit 2 - - - If the filter failed to print the file and does not want - LPD to try again. LPD will throw out the file. - - - - - The text filter that comes with the FreeBSD release, - /usr/libexec/lpr/lpf, takes advantage of the - page width and length arguments to determine when to send a form - feed and how to account for printer usage. It uses the login, host, - and accounting file arguments to make the accounting entries. - - If you 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. - - - - Accommodating Plain Text Jobs on PostScript Printers - - 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. - - 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 - %! (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. - - How do we do this? - - If you have got a serial printer, a great way to do it is to - install lprps. lprps is a - PostScript printer filter which performs two-way communication with - the printer. It updates the printer's status file with verbose - information from the printer, so users and administrators can see - exactly what the state of the printer is (such as toner - low or paper jam). But more - importantly, it includes a program called psif - which detects whether the incoming job is plain text and calls - textps (another program that comes with - lprps) to convert it to PostScript. It then uses - lprps to send the job to the printer. - - lprps is part of the FreeBSD ports collection - (see The Ports Collection). You can - fetch, build and install it yourself, of course. After installing - lprps, just specify the pathname to the - psif program that is part of - lprps. If you installed lprps - from the ports collection, use the following in the serial - PostScript printer's entry in - /etc/printcap: - - -:if=/usr/local/libexec/psif: - - You should also specify the rw capability; - that tells LPD to open the printer in read-write mode. - - If you have a parallel PostScript printer (and therefore cannot - use two-way communication with the printer, which - lprps needs), you can use the following shell - script as the text filter: - - -#!/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 - - In the above script, textps is a program we - installed separately to convert plain text to PostScript. You can - use any text-to-PostScript program you wish. The FreeBSD ports - collection (see The Ports Collection) - includes a full featured text-to-PostScript program called - a2ps that you might want to investigate. - - - - Simulating PostScript on Non-PostScript Printers - - PostScript is the de facto standard for - high quality typesetting and printing. PostScript is, however, an - expensive standard. Thankfully, Alladin - Enterprises has a free PostScript work-alike called - Ghostscript that runs with FreeBSD. - Ghostscript can read most PostScript files and can render their - pages onto a variety of devices, including many brands of - non-PostScript printers. By installing Ghostscript and using a - special text filter for your printer, you can make your - non-PostScript printer act like a real PostScript printer. - - Ghostscript should be in the FreeBSD ports collection, if you - would like to install it from there. You can fetch, build, and - install it quite easily yourself, as well. - - To simulate PostScript, we have the text filter detect if it 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. - - Here is an example: the following script is a text filter - for Hewlett Packard DeskJet 500 printers. For other printers, - substitute the argument to the - gs (Ghostscript) command. (Type gs - -h to get a list of devices the current installation of - Ghostscript supports.) - - -#!/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. - # - # Note that PostScript files are actually interpreted programs, - # and those programs are allowed to write to stdout, which will - # mess up the printed output. So, we redirect stdout to stderr - # and then make descriptor 3 go to stdout, and have Ghostscript - # write its output there. Exercise for the clever reader: - # capture the stderr output from Ghostscript and mail it back to - # the user originating the print job. - # - exec 3>&1 1>&2 - /usr/local/bin/gs -dSAFER -dNOPAUSE -q -sDEVICE=djet500 \ - -sOutputFile=/dev/fd/3 - && exit 0 - - # - /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 "\033&l0H" && exit 0 -fi - -exit 2 - - Finally, you need to notify LPD of the filter via the - if capability: - - -:if=/usr/local/libexec/hpif: - - That is it. You can type lpr plain.text and - lpr whatever.ps and both should print - successfully. - - - - Conversion Filters - - After completing the simple setup described in 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). - - - Why Install Conversion Filters? - - 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: - - &prompt.user; dvips seaweed-analysis.dvi -&prompt.user; lpr seaweed-analysis.ps - - 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: - - &prompt.user; lpr -d seaweed-analysis.dvi - - We got LPD to do the DVI file conversion for us by specifying - the option. Section Formatting and Conversion - Options lists the conversion options. - - For each of the conversion options you want a printer to - support, install a conversion filter and - specify its pathname in /etc/printcap. A - conversion filter is like the text filter for the simple printer - setup (see section Installing - the Text Filter) except that instead of printing plain - text, the filter converts the file into a format the printer can - understand. - - - - Which Conversions Filters Should I Install? - - 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. - - The following table summarizes the filters that LPD works - with, their capability entries for the - /etc/printcap file, and how to invoke them - with the lpr command: - - - - - - File type - /etc/printcap capability - lpr option - - - - - - cifplot - cf - - - - - DVI - df - - - - - plot - gf - - - - - ditroff - nf - - - - - FORTRAN text - rf - - - - - troff - rf - - - - - raster - vf - - - - - plain text - if - none, , or - - - - - - - In our example, using lpr -d means the - printer needs a df capability in its entry in - /etc/printcap. - - Despite what others might contend, formats like FORTRAN text - and plot are probably obsolete. At your site, you can give new - meanings to these or any of the formatting options just by - installing custom filters. For example, suppose you 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 - gf capability and then educate your users that - lpr -g mean “print Printerleaf - files.” - - - - Installing Conversion Filters - - Since conversion filters are programs you install outside of - the base FreeBSD installation, they should probably go under - /usr/local. The directory - /usr/local/libexec is a popular location, - since they are specialized programs that only LPD will run; - regular users should not ever need to run them. - - To enable a conversion filter, specify its pathname under the - appropriate capability for the destination printer in - /etc/printcap. - - In our example, we will add the DVI conversion filter to the - entry for the printer named bamboo. Here is - the example /etc/printcap file again, with - the new df capability for the printer - bamboo. - - -# -# /etc/printcap for host rose - added df filter for bamboo -# -rattan|line|diablo|lp|Diablo 630 Line Printer:\ - :sh:sd=/var/spool/lpd/rattan:\ - :lp=/dev/lpt0:\ - :if=/usr/local/libexec/if-simple: - -bamboo|ps|PS|S|panasonic|Panasonic KX-P4455 PostScript v51.4:\ - :sh:sd=/var/spool/lpd/bamboo:\ - :lp=/dev/ttyd5:fs#0x82000e1:xs#0x820:rw:\ - :if=/usr/local/libexec/psif:\ - :df=/usr/local/libexec/psdf: - - The DVI filter is a shell script named - /usr/local/libexec/psdf. Here is that - script: - - -#!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 "$@" - - This script runs dvips in filter mode (the - argument) on standard input, which is the job - to print. It then starts the PostScript printer filter - lprps (see section Accommodating Plain - Text Jobs on PostScript Printers) with the arguments LPD - passed to this script. lprps will use those - arguments to account for the pages printed. - - - - More Conversion Filter Examples - - 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. - - This example script is a raster (well, GIF file, actually) - conversion filter for a Hewlett Packard LaserJet III-Si - printer: - - -#!/bin/sh -# -# hpvf - Convert GIF files into HP/PCL, then print -# Installed in /usr/local/libexec/hpvf - -PATH=/usr/X11R6/bin:$PATH; export PATH -giftopnm | ppmtopgm | pgmtopbm | pbmtolj -resolution 300 \ - && exit 0 \ - || exit 2 - - It works by converting the GIF file into a portable anymap, - converting that into a portable graymap, converting that into a - portable bitmap, and converting that into LaserJet/PCL-compatible - data. - - Here is the /etc/printcap file with an - entry for a printer using the above filter: - - -# -# /etc/printcap for host orchid -# -teak|hp|laserjet|Hewlett Packard LaserJet 3Si:\ - :lp=/dev/lpt0:sh:sd=/var/spool/lpd/teak:mx#0:\ - :if=/usr/local/libexec/hpif:\ - :vf=/usr/local/libexec/hpvf: - - The following script is a conversion filter for troff data - from the groff typesetting system for the PostScript printer named - bamboo: - - -#!/bin/sh -# -# pstf - Convert groff's troff data into PS, then print. -# Installed in /usr/local/libexec/pstf -# -exec grops | /usr/local/libexec/lprps "$@" - - The above script makes use of lprps again - to handle the communication with the printer. If the printer were - on a parallel port, we would use this script instead: - - -#!/bin/sh -# -# pstf - Convert groff's troff data into PS, then print. -# Installed in /usr/local/libexec/pstf -# -exec grops - - That is it. Here is the entry we need to add to - /etc/printcap to enable the filter: - - -:tf=/usr/local/libexec/pstf: - - 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 - teak: - - -#!/bin/sh -# -# hprf - FORTRAN text filter for LaserJet 3si: -# Installed in /usr/local/libexec/hprf -# - -printf "\033&k2G" && fpr && printf "\033&l0H" && exit 0 -exit 2 - - And we will add this line to the - /etc/printcap for the printer - teak to enable this filter: - - -:rf=/usr/local/libexec/hprf: - - Here is one final, somewhat complex example. We will add a - DVI filter to the LaserJet printer teak - introduced earlier. First, the easy part: updating - /etc/printcap with the location of the DVI - filter: - - -:df=/usr/local/libexec/hpdf: - - Now, for the hard part: making the filter. For that, we need - a DVI-to-LaserJet/PCL conversion program. The FreeBSD ports - collection (see The Ports Collection) - has one: dvi2xx is the name of the package. - Installing this package gives us the program we need, - dvilj2p, which converts DVI into LaserJet IIp, - LaserJet III, and LaserJet 2000 compatible codes. - - dvilj2p makes the filter - hpdf quite complex since - dvilj2p cannot read from standard input. It - wants to work with a filename. What is worse, the filename has to - end in .dvi so using - /dev/fd/0 for standard input is problematic. - We can get around that problem by linking (symbolically) a - temporary file name (one that ends in .dvi) - to /dev/fd/0, thereby forcing - dvilj2p to read from standard input. - - The only other fly in the ointment is the fact that we cannot - use /tmp for the temporary link. Symbolic - links are owned by user and group bin. The - filter runs as user daemon. And the - /tmp 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. - - Instead, the filter will make the symbolic link in the current - working directory, which is the spooling directory (specified by - the sd capability in - /etc/printcap). 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 - /tmp. - - Here, finally, is the filter: - - -#!/bin/sh -# -# hpdf - Print DVI data on HP/PCL printer -# Installed in /usr/local/libexec/hpdf - -PATH=/usr/local/bin:$PATH; export PATH - -# -# Define a function to clean up our temporary files. These exist -# in the current directory, which will be the spooling directory -# for the printer. -# -cleanup() { - rm -f hpdf$$.dvi -} - -# -# Define a function to handle fatal errors: print the given message -# and exit 2. Exiting with 2 tells LPD to 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 - - - - Automated Conversion: An Alternative To Conversion - Filters - - All these conversion filters accomplish a lot for your - printing environment, but at the cost forcing the user to specify - (on the &man.lpr.1; 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. - - 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 - file can be of help here. Of course, it will - be hard to determine the differences between - some file types—and, of course, you can - still provide conversion filters just for them. - - The FreeBSD ports collection has a text filter that performs - automatic conversion called apsfilter. It can - detect plain text, PostScript, and DVI files, run the proper - conversions, and print. - - - - - Output Filters - - 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: - - - - LPD starts an output filter once for the entire job instead - of once for each file in the job. - - - - LPD does not make any provision to identify the start or the - end of files within the job for the output filter. - - - - 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: - - - filter-name - -wwidth - -llength - - - Where width is from the - pw capability and - length is from the - pl capability for the printer in - question. - - - - 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 will not work. Use a text filter (also - known as an input filter); see section Installing the Text Filter. - Furthermore, an output filter is actually more - complex in that it has to examine the byte stream being - sent to it for special flag characters and must send signals to - itself on behalf of LPD. - - However, an output filter is necessary if - you want header pages and need to send escape sequences or other - initialization strings to be able to print the header page. (But it - is also futile 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.) - - 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 Header Pages) - only. LPD then expects the output filter to stop - itself by sending two bytes to the filter: ASCII 031 - followed by ASCII 001. When an output filter sees these two bytes - (031, 001), it should stop by sending SIGSTOP to itself. When LPD's - done running other filters, it will restart the output filter by - sending SIGCONT to it. - - If there is an output filter but no text - filter and LPD is working on a plain text job, LPD uses the output - filter to do the job. As stated before, the output filter will - print each file of the job in sequence with no intervening form - feeds or other paper advancement, and this is probably - not what you want. In almost all cases, you - need a text filter. - - The program lpf, 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 lpf. You - can also wrap lpf in a shell script to handle any - initialization codes the printer might require. - - - - <command>lpf</command>: a Text Filter - - The program /usr/libexec/lpr/lpf that comes - with FreeBSD binary distribution is a text filter (input filter) - that can indent output (job submitted with lpr - -i), allow literal characters to pass (job submitted - with lpr -l), adjust the printing position for - backspaces and tabs in the job, and account for pages printed. It - can also act like an output filter. - - lpf 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 - lpf. - - In order for lpf to do page accounting - correctly, it needs correct values filled in for the - pw and pl capabilities in the - /etc/printcap file. It uses these values to - determine how much text can fit on a page and how many pages were in - a user's job. For more information on printer accounting, see Accounting for Printer - Usage. - - - - - Header Pages - - If you have lots of users, all of them using - various printers, then you probably want to consider header - pages as a necessary evil. - - Header pages, also known as banner or - burst pages 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.) - - The LPD system can provide header pages automatically for your - printouts if 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 Header Pages on - PostScript Printers. - - - Enabling Header Pages - - In the Simple Printer - Setup, we turned off header pages by specifying - sh (meaning “suppress header”) in the - /etc/printcap file. To enable header pages for - a printer, just remove the sh capability. - - Sounds too easy, right? - - You are right. You might 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: - - -#!/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 - - Specify the path to the output filter in the - of capability. See Output Filters for more - information. - - Here is an example /etc/printcap file for - the printer teak that we introduced earlier; we - enabled header pages and added the above output filter: - - -# -# /etc/printcap for host orchid -# -teak|hp|laserjet|Hewlett Packard LaserJet 3Si:\ - :lp=/dev/lpt0:sd=/var/spool/lpd/teak:mx#0:\ - :if=/usr/local/libexec/hpif:\ - :vf=/usr/local/libexec/hpvf:\ - :of=/usr/local/libexec/hpof: - - Now, when users print jobs to teak, they get - a header page with each job. If users want to spend time searching - for their printouts, they can suppress header pages by submitting - the job with lpr -h; see Header Page Options for - more &man.lpr.1; options. - - - 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 ff - capability in /etc/printcap. - - - - - Controlling Header Pages - - By enabling header pages, LPD will produce a long - header, 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): - - - 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 - - LPD appends a form feed after this text so the job starts on a - new page (unless you have sf (suppress form - feeds) in the destination printer's entry in - /etc/printcap). - - If you prefer, LPD can make a short header; - specify sb (short banner) in the - /etc/printcap file. The header page will look - like this: - - -rose:kelly Job: outline Date: Sun Sep 17 11:07:51 1995 - - Also by default, LPD prints the header page first, then the job. - To reverse that, specify hl (header last) in - /etc/printcap. - - - - Accounting for Header Pages - - Using LPD's built-in header pages enforces a particular paradigm - when it comes to printer accounting: header pages must be - free of charge. - - Why? - - Because the output filter is the only external program that will - have control when the header page is printed that could do - accounting, and it is not provided with any user or - host 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 lpr -h. - They could still be charged for header pages they did not print. - Basically, lpr -h will be the preferred option of - environmentally-minded users, but you cannot offer any incentive to - use it. - - It is still not enough to have each of the - filters generate their own header pages (thereby being able to - charge for them). If users wanted the option of suppressing the - header pages with lpr -h, they will still get - them and be charged for them since LPD does not pass any knowledge - of the option to any of the filters. - - So, what are your options? - - You can: - - - - Accept LPD's paradigm and make header pages free. - - - - Install an alternative to LPD, such as LPRng or PLP. Section - Alternatives to the - Standard Spooler tells more about other spooling - software you can substitute for LPD. - - - - Write a smart 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 af capability), but if you have a - well-known accounting file, you can hard-code that into the - output filter. To facilitate the parsing step, use the - sh (short header) capability in - /etc/printcap. Then again, all that might - be too much trouble, and users will certainly appreciate the - more generous system administrator who makes header pages - free. - - - - - - Header Pages on PostScript Printers - - 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. - - 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 lpr - -h. - - 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: - - -#!/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 - - 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: - - -#!/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 - - 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 How Filters - Work). - - As we have mentioned before, the above scheme, though fairly - simple, disables the “suppress header page” option (the - option) to lpr. 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. - - To allow users to shut off header pages on a per-job basis, you - will need to use the trick introduced in section 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 lpr -h, 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. - - If you have a PostScript printer on a serial line, you can make - use of lprps, which comes with an output filter, - psof, which does the above. Note that - psof does not charge for header pages. - - - - - Networked Printing - - FreeBSD supports networked printing: sending jobs to remote - printers. Networked printing generally refers to two different - things: - - - - 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 Printers Installed on - Remote Hosts tells how to do this. - - - - 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: - - - - 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 Printers - Installed on Remote Hosts to set up such a - printer. - - - - 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 Printers with - Networked Data Stream Interfaces gives some - suggestions on installing such printers. - - - - - - - Printers Installed on Remote Hosts - - The LPD spooling system has built-in support for sending jobs to - other hosts also running LPD (or are compatible with LPD). This - feature enables you to install a printer on one host and make it - accessible from other hosts. It also works with printers that have - network interfaces that understand the LPD protocol. - - To enable this kind of remote printing, first install a printer - on one host, the printer host, using the simple - printer setup described in Simple - Printer Setup. Do any advanced setup in 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. Also ensure that the - local host has authorization to use the LPD - service in the remote host (see Restricting Jobs - from Remote Printers). - - If you are using a printer with a network interface that is - compatible with LPD, then the printer host in - the discussion below is the printer itself, and the - printer name is the name you configured for the - printer. See the documentation that accompanied your printer and/or - printer-network interface. - - - If you are using a Hewlett Packard Laserjet then the printer - name text will automatically perform the LF to - CRLF conversion for you, so you will not require the - hpif script. - - - Then, on the other hosts you want to have access to the printer, - make an entry in their /etc/printcap files with - the following: - - - - Name the entry anything you want. For simplicity, though, - you probably want to use the same name and aliases as on the - printer host. - - - - Leave the lp capability blank, explicitly - (:lp=:). - - - - Make a spooling directory and specify its location in the - sd capability. LPD will store jobs here - before they get sent to the printer host. - - - - Place the name of the printer host in the - rm capability. - - - - Place the printer name on the printer - host in the rp - capability. - - - - That is it. You do not need to list conversion filters, page - dimensions, or anything else in the - /etc/printcap file. - - Here is an example. The host rose has two - printers, bamboo and rattan. - We will enable users on the host orchid to print to those printers. - Here is the /etc/printcap file for - orchid (back from section Enabling Header - Pages). It already had the entry for the printer - teak; we have added entries for the two printers - on the host rose: - - -# -# /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: - - Then, we just need to make spooling directories on - orchid: - - &prompt.root; mkdir -p /var/spool/lpd/rattan /var/spool/lpd/bamboo -&prompt.root; chmod 770 /var/spool/lpd/rattan /var/spool/lpd/bamboo -&prompt.root; chown daemon.daemon /var/spool/lpd/rattan /var/spool/lpd/bamboo - - Now, users on orchid can print to - rattan and bamboo. If, for - example, a user on orchid typed - - &prompt.user; lpr -P bamboo -d sushi-review.dvi - - the LPD system on orchid would copy the job to the spooling - directory /var/spool/lpd/bamboo and note that - it was a DVI job. As soon as the host rose has room in its - bamboo spooling directory, the two LPDs would - transfer the file to rose. The file would wait in rose's queue - until it was finally printed. It would be converted from DVI to - PostScript (since bamboo is a PostScript printer) on rose. - - - - Printers with Networked Data Stream Interfaces - - 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 Printers Installed on - Remote Hosts. - - The format of the /etc/printcap 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. - - 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 - netprint takes all data on standard input and - sends it to a network-attached printer. We specify the hostname of - the printer as the first argument and the port number to which to - connect as the second argument to netprint. Note - that this supports one-way communication only (FreeBSD to printer); - many network printers support two-way communication, and you might - want to take advantage of that (to get printer status, perform - accounting, etc.). - - -#!/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; - - 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: - - -#!/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 - - - - - Restricting Printer Usage - - 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. - - - Restricting Multiple Copies - - The LPD system makes it easy for users to print multiple copies - of a file. Users can print jobs with lpr -#5 - (for example) and get five copies of each file in the job. Whether - this is a good thing is up to you. - - If you feel multiple copies cause unnecessary wear and tear on - your printers, you can disable the option to - &man.lpr.1; by adding the sc capability to the - /etc/printcap file. When users submit jobs - with the option, they will see: - - lpr: multiple copies are not allowed - - - Note that if you have set up access to a printer remotely (see - section Printers - Installed on Remote Hosts), you need the - sc capability on the remote - /etc/printcap files as well, or else users will - still be able to submit multiple-copy jobs by using another - host. - - Here is an example. This is the - /etc/printcap file for the host - rose. The printer rattan is - quite hearty, so we will allow multiple copies, but the laser - printer bamboo's a bit more delicate, so we will - disable multiple copies by adding the sc - capability: - - -# -# /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: - - Now, we also need to add the sc capability on - the host orchid's - /etc/printcap (and while we are at it, let us - disable multiple copies for the printer - teak): - - -# -# /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: - - By using the sc capability, we prevent the - use of lpr -#, but that still does not prevent - users from running &man.lpr.1; - multiple times, or from submitting the same file multiple times in - one job like this: - - &prompt.user; lpr forsale.sign forsale.sign forsale.sign forsale.sign forsale.sign - - There are many ways to prevent this abuse (including ignoring - it) which you are free to explore. - - - - Restricting Access To Printers - - You can control who can print to what printers by using the UNIX - group mechanism and the rg capability in - /etc/printcap. Just place the users you want - to have access to a printer in a certain group, and then name that - group in the rg capability. - - Users outside the group (including root) will be greeted with - - lpr: Not a member of the restricted group - - if they try to print to the controlled printer. - - As with the sc (suppress multiple copies) - capability, you need to specify rg on remote - hosts that also have access to your printers, if you feel it is - appropriate (see section Printers Installed on - Remote Hosts). - - For example, we will let anyone access the printer - rattan, but only those in group - artists can use bamboo. Here - is the familiar /etc/printcap for host - rose: - - -# -# /etc/printcap for host rose - restricted group for bamboo -# -rattan|line|diablo|lp|Diablo 630 Line Printer:\ - :sh:sd=/var/spool/lpd/rattan:\ - :lp=/dev/lpt0:\ - :if=/usr/local/libexec/if-simple: - -bamboo|ps|PS|S|panasonic|Panasonic KX-P4455 PostScript v51.4:\ - :sh:sd=/var/spool/lpd/bamboo:sc:rg=artists:\ - :lp=/dev/ttyd5:fs#0x82000e1:xs#0x820:rw:\ - :if=/usr/local/libexec/psif:\ - :df=/usr/local/libexec/psdf: - - Let us leave the other example - /etc/printcap file (for the host - orchid) alone. Of course, anyone on - orchid can print to bamboo. It - might be the case that we only allow certain logins on - orchid anyway, and want them to have access to the - printer. Or not. - - - There can be only one restricted group per printer. - - - - - Controlling Sizes of Jobs Submitted - - 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. - - LPD enables you to limit the maximum byte size a file in a job - can be with the mx 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; however, if no - mx capability is specified, then a default limit - of 1000 blocks will be used. - - - The limit applies to files in a job, and - not the total job size. - - - 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. - - Let us add limits to our example printers - rattan and bamboo. 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: - - -# -# /etc/printcap for host rose -# - -# -# No limit on job size: -# -rattan|line|diablo|lp|Diablo 630 Line Printer:\ - :sh:mx#0:sd=/var/spool/lpd/rattan:\ - :lp=/dev/lpt0:\ - :if=/usr/local/libexec/if-simple: - -# -# Limit of five megabytes: -# -bamboo|ps|PS|S|panasonic|Panasonic KX-P4455 PostScript v51.4:\ - :sh:sd=/var/spool/lpd/bamboo:sc:rg=artists:mx#5000:\ - :lp=/dev/ttyd5:fs#0x82000e1:xs#0x820:rw:\ - :if=/usr/local/libexec/psif:\ - :df=/usr/local/libexec/psdf: - - Again, the limits apply to the local users only. If you have - set up access to your printers remotely, remote users will not get - those limits. You will need to specify the mx - capability in the remote /etc/printcap files as - well. See section Printers Installed on - Remote Hosts for more information on remote - printing. - - There is another specialized way to limit job sizes from remote - printers; see section Restricting Jobs - from Remote Printers. - - - - Restricting Jobs from Remote Printers - - The LPD spooling system provides several ways to restrict print - jobs submitted from remote hosts: - - - - Host restrictions - - - You can control from which remote hosts a local LPD - accepts requests with the files - /etc/hosts.equiv and - /etc/hosts.lpd. LPD checks to see if an - incoming request is from a host listed in either one of these - files. If not, LPD refuses the request. - - The format of these files is simple: one host name per - line. Note that the file - /etc/hosts.equiv is also used by the - &man.ruserok.3; protocol, and affects programs like - &man.rsh.1; and &man.rcp.1;, so be careful. - - For example, here is the - /etc/hosts.lpd file on the host - rose: - - -orchid -violet -madrigal.fishbaum.de - - This means rose will accept requests from - the hosts orchid, violet, - and madrigal.fishbaum.de. If any - other host tries to access rose's LPD, LPD - will refuse them. - - - - - Size restrictions - - - You can control how much free space there needs to remain - on the filesystem where a spooling directory resides. Make a - file called minfree in the spooling - directory for the local printer. Insert in that file a number - representing how many disk blocks (512 bytes) of free space - there has to be for a remote job to be accepted. - - This lets you insure that remote users 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 - minfree file. - - For example, let us add a minfree - file for the printer bamboo. We examine - /etc/printcap to find the spooling - directory for this printer; here is bamboo's - entry: - - -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: - - The spooling directory is the given in the - sd 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: - - &prompt.root; echo 6144 > /var/spool/lpd/bamboo/minfree - - - - - User restrictions - - - You can control which remote users can print to local - printers by specifying the rs capability in - /etc/printcap. When - rs appears in the entry for a - locally-attached printer, LPD will accept jobs from remote - hosts if the user submitting the job also - has an account of the same login name on the local host. - Otherwise, LPD refuses the job. - - This capability is particularly useful in an environment - where there are (for example) different departments sharing a - network, and some users transcend departmental boundaries. By - giving them accounts on your systems, they can use your - printers from their own departmental systems. If you would - rather allow them to use only your - printers and not your compute resources, you can give them - “token” accounts, with no home directory and a - useless shell like /usr/bin/false. - - - - - - - - Accounting for Printer Usage - - 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? - - 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 - your requirements in charging for printer - usage. - - To implement accounting, you have to modify a printer's text - filter (to charge for plain text jobs) and the conversion filters (to - charge for other file formats), to count pages or query the printer - for pages printed. You cannot get away with using the simple output - filter, since it cannot do accounting. See section Filters. - - Generally, there are two ways to do accounting: - - - - Periodic accounting 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. - - - - Timely accounting 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. - - - - 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. - - - Quick and Dirty Printer Accounting - - FreeBSD comes with two programs that can get you set up with - simple periodic accounting right away. They are the text filter - lpf, described in section lpf: a Text Filter, and - &man.pac.8;, a program to gather and total - entries from printer accounting files. - - As mentioned in the section on filters (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 af capability in - /etc/printcap, and if not specified as an - absolute path, is relative to the spooling directory. - - LPD starts lpf with page width and length - arguments (from the pw and pl - capabilities). lpf uses these arguments to - determine how much paper will be used. After sending the file to - the printer, it then writes an accounting entry in the accounting - file. The entries look like this: - - -2.00 rose:andy -3.00 rose:kelly -3.00 orchid:mary -5.00 orchid:mary -2.00 orchid:zhang - - You should use a separate accounting file for each printer, as - lpf has no file locking logic built into it, and - two lpfs 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 - af=acct in /etc/printcap. - Then, each accounting file will be in the spooling directory for a - printer, in a file named acct. - - When you are ready to charge users for printouts, run the - &man.pac.8; program. Just change to the spooling directory for - the printer you want to collect on and type pac. - You will get a dollar-centric summary like the following: - - 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 - - These are the arguments &man.pac.8; expects: - - - - - - - Which printer to summarize. - This option works only if there is an absolute path in the - af capability in - /etc/printcap. - - - - - - - - Sort the output by cost instead of alphabetically by user - name. - - - - - - - - Ignore host name in the accounting files. With this - option, user smith on host - alpha is the same user - smith on host gamma. - Without, they are different users. - - - - - - - - Compute charges with price - dollars per page or per foot instead of the price from the - pc capability in - /etc/printcap, or two cents (the - default). You can specify price as - a floating point number. - - - - - - - - Reverse the sort order. - - - - - - - - Make an accounting summary file and truncate the - accounting file. - - - - - name - - - - Print accounting information for the given user - names only. - - - - - In the default summary that &man.pac.8; 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 pac -m, to produce the following - summary: - - 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 - - - To compute the dollar amount due, - &man.pac.8; uses the pc capability in the - /etc/printcap 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 &man.pac.8; with the - option. The units for the - option are in dollars, though, not hundredths of cents. For - example, - - &prompt.root; pac -p1.50 - - makes each page cost one dollar and fifty cents. You can really - rake in the profits by using this option. - - Finally, running pac -s will save the summary - information in a summary accounting file, which is named the same as - the printer's accounting file, but with _sum - appended to the name. It then truncates the accounting file. When - you run &man.pac.8; again, it rereads the - summary file to get starting totals, then adds information from the - regular accounting file. - - - - How Can You Count Pages Printed? - - In order to perform even remotely accurate accounting, you need - to be able to determine how much paper a job uses. This is the - essential problem of printer accounting. - - For plain text jobs, the problem's not that hard to solve: you - count how many lines are in a job and compare it to how many lines - per page your printer supports. 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. - - The text filter lpf (introduced in 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 lpf's source code. - - How do you handle other file formats, though? - - Well, for DVI-to-LaserJet or DVI-to-PostScript conversion, you - can have your filter parse the diagnostic output of - dvilj or dvips and look to see - how many pages were converted. You might be able to do similar - things with other file formats and conversion programs. - - But these methods suffer from the fact that the printer may not - actually print all those pages. For example, it could jam, run out - of toner, or explode—and the user would still get - charged. - - So, what can you do? - - There is only one sure way to do - accurate accounting. Get a printer that can - tell you how much paper it uses, and attach it via a serial line or - a network connection. Nearly all PostScript printers support this - notion. Other makes and models do as well (networked Imagen laser - printers, for example). Modify the filters for these printers to - get the page usage after they print each job and have them log - accounting information based on that value - only. There is no line counting nor - error-prone file examination required. - - Of course, you can always be generous and make all printouts - free. - - - - Alternatives to the Standard Spooler @@ -4597,61 +4333,297 @@ total 337.00 154 $ 6.74 - - - Acknowledgments - - I would like to thank the following people who have assisted in the - development of this document: + + + Troubleshooting + + After performing the simple test with &man.lptest.1;, you might + have gotten one of the following results instead of the correct + printout: - Daniel Eischen - deischen@iworks.interworks.org + It worked, after awhile; or, it did not eject a full + sheet. - For providing a plethora of HP filter programs for - perusal. - - - - - &a.jehamby; + 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. - - For the Ghostscript-to-HP filter. + 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. + + The following replacement for the shell script + /usr/local/libexec/if-simple prints a + form feed after it sends the job to the printer: + + +#!/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 - &a.jfieber; + It produced the “staircase effect.” - For debugging why printing from Windows 95 to a FreeBSD - system simulating a PostScript printer with Ghostscript didn't - produce correct output, and suggesting a fix, which is included - herein. + You got the following on paper: + + +!"#$%&'()*+,-./01234 + "#$%&'()*+,-./012345 + #$%&'()*+,-./0123456 + + You have become another victim of the staircase + effect, caused by conflicting interpretations of + what characters should indicate a new line. UNIX-style + operating systems use a single character: ASCII code 10, the + line feed (LF). MS-DOS, OS/2, and others uses a pair of + characters, ASCII code 10 and ASCII code + 13 (the carriage return or CR). Many printers use the MS-DOS + convention for representing new-lines. + + When you print with FreeBSD, your text used just the line + feed character. The printer, upon seeing a line feed + character, advanced the paper one line, but maintained the + same horizontal position on the page for the next character + to print. That is what the carriage return is for: to move + the location of the next character to print to the left edge + of the paper. + + Here is what FreeBSD wants your printer to do: + + + + + + Printer received CR + Printer prints CR + + + + Printer received LF + Printer prints CR + LF + + + + + + Here are some ways to achieve this: + + + + 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. + + + If you boot your system into other operating systems + besides FreeBSD, you may have to + reconfigure the printer to use a an + interpretation for CR and LF characters that those other + operating systems use. You might prefer one of the other + solutions, below. + + + + + Have FreeBSD's serial line driver automatically + convert LF to CR+LF. Of course, this works with printers + on serial ports only. To enable this + feature, set the CRMOD bit in fs + capability in the /etc/printcap file + for the printer. + + + + Send an escape code to the + printer to have it temporarily treat LF characters + differently. Consult your printer's manual for escape + codes that your printer might support. When you find the + proper escape code, modify the text filter to send the + code first, then send the print job. + + 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. + + +#!/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. Ejects the page when done. + +printf "\033&k2G" && cat && printf "\033&l0H" && exit 0 +exit 2 + + Here is an example /etc/printcap + from a host called orchid. It has a single printer + attached to its first parallel port, a Hewlett Packard + LaserJet 3Si named teak. It is using the + above script as its text filter: + + +# +# /etc/printcap for host orchid +# +teak|hp|laserjet|Hewlett Packard LaserJet 3Si:\ + :lp=/dev/lpt0:sh:sd=/var/spool/lpd/teak:mx#0:\ + :if=/usr/local/libexec/hpif: + + - Stephen Montgomery-Smith - stephen@math.missouri.edu + It overprinted each line. - For suggesting using "\033&l0H" instead of "\f" to eject - the last page on HP printers; the latter could eject an extra - blank page while the former never does. + The printer never advanced a line. All of the lines of + text were printed on top of each other on one line. + + This problem is the “opposite” of the + staircase effect, described above, and is much rarer. + Somewhere, the LF characters that FreeBSD uses to end a line + are being treated as CR characters to return the print + location to the left edge of the paper, but not also down a + line. + + Use the printer's configuration switches or control panel + to enforce the following interpretation of LF and CR + characters: + + + + + + Printer receives + Printer prints + + + + + + CR + CR + + + + LF + CR + LF + + + + - + - My wife, Mary Kelly - urquhart@argyre.colorado.edu + The printer lost characters. - For allowing me to spend more time with FreeBSD than - with her. + 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. + + 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: + + + + If the printer supports XON/XOFF flow control, have + FreeBSD use it by specifying the TANDEM bit in the + fs capability. + + + + If the printer supports carrier flow control, specify + the MDMBUF bit in the fs capability. + Make sure the cable connecting the printer to the computer + is correctly wired for carrier flow control. + + + + If the printer does not support any flow control, use + some combination of the NLDELAY, TBDELAY, CRDELAY, VTDELAY, + and BSDELAY bits in the fs capability + to add appropriate delays to the stream of data sent to + the printer. + + + + + + + It printed garbage. + + + The printer printed what appeared to be random garbage, + but not the desired text. + + This is usually another symptom of incorrect + communications parameters with a serial printer. Double-check + the bps rate in the br capability, and the + parity bits in the fs and + fc capabilities; make sure the printer is + using the same settings as specified in the + /etc/printcap file. + + + + + Nothing happened. + + + If nothing happened, the problem is probably within + FreeBSD and not the hardware. Add the log file + (lf) capability to the entry for the + printer you are debugging in the + /etc/printcap file. For example, here is + the entry for rattan, with the + lf capability: + + +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 + + Then, try printing again. Check the log file (in our + example, /var/log/rattan.log) to see any + error messages that might appear. Based on the messages you + see, try to correct the problem. + + If you do not specify a lf capability, + LPD uses /dev/console as a + default. diff --git a/en_US.ISO_8859-1/books/handbook/printing/chapter.sgml b/en_US.ISO_8859-1/books/handbook/printing/chapter.sgml index 596b90c8eb..faff1afa92 100644 --- a/en_US.ISO_8859-1/books/handbook/printing/chapter.sgml +++ b/en_US.ISO_8859-1/books/handbook/printing/chapter.sgml @@ -1,557 +1,558 @@ Printing - - Contributed by &a.kelly; 30 September - 1995 - - 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. - - If you are already familiar with LPD or another printer spooling - system, you may wish to skip to section Restructured and updated by &a.jim;, March + 2000. + + + Synopsis + + 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 chapter introduces the LPD spooling + system, often simply called LPD, and will guide you through it's + configuration. + + If you are already familiar with LPD or another printer spooling + system, you may wish to skip to section Setting up the spooling system. - - - What the Spooler Does + - LPD controls everything about a host's printers. It is responsible - for a number of things: + + Introduction + + LPD controls everything about a host's printers. It is + responsible for a number of things: - It controls access to attached printers and printers attached to - other hosts on the network. + It controls access to attached printers and 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 + 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 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 LPD 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 LPD system to do all or some subset of the - above for a great variety of printer hardware. + + Through a configuration file + (/etc/printcap), 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. + + + Why You Should Use the Spooler + + 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: + + + + LPD prints jobs in the background; you do not have to wait + for data to be copied to the printer. + + + + 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. + + + + 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. + + + - - - Why You Should Use the Spooler - - 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 - - - - LPD prints jobs in the background; you do not have to wait for - data to be copied to the printer. - - - - 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. - - - - 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. - - - - + - Setting Up the Spooling System - - 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: - + Basic Setup + + 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: + See section Simple Printer - Setup to learn how to connect a printer, tell LPD how to + Setup to learn how to connect a printer, tell LPD how to communicate with it, and print plain text files to the printer. - + - See section 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. + See section 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. - - - - Simple Printer Setup - - This section tells how to configure printer hardware and the LPD - software to use the printer. It teaches the basics: - - - - Section Hardware Setup - gives some hints on connecting the printer to a port on your - computer. - - - - Section Software Setup - shows how to setup the LPD spooler configuration file - /etc/printcap. - - - - 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 - Printers With Networked - Data Stream Interaces. - 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. + + Simple Printer Setup - - Hardware Setup - - 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. + This section tells how to configure printer hardware and the + LPD software to use the printer. It teaches the basics: + + + + Section Hardware + Setup gives some hints on connecting the printer to a + port on your computer. + + + + Section Software + Setup shows how to setup the LPD spooler configuration + file (/etc/printcap). + + + + 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 Printers With + Networked Data Stream Interaces. + + 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. + + + Hardware Setup + + This section tells about the various ways you can connect a + printer to your PC. It talks about the kinds of ports and + cables, and also the kernel configuration you may need to enable + FreeBSD to speak to the printer. + + If you have already connected your printer and have + successfully printed with it under another operating system, you + can probably skip to section Software Setup. + + + Ports and Cables + + Nearly all printers you can get for a PC today support one + or both of the following interfaces: + + + + Serial interfaces use a serial + port on your computer to send data to the printer. Serial + interfaces are common in the computer industry and cables + are readily available and also easy to construct. Serial + interfaces sometimes need special cables and might require + you to configure somewhat complex communications + options. + + + + Parallel interfaces use a + parallel port on your computer to send data to the + printer. Parallel interfaces are common in the PC market. + Cables are readily available but more difficult to + construct by hand. There are usually no communications + options with parallel interfaces, making their + configuration exceedingly simple. + + Parallel interfaces are sometimes known as + “Centronics” interfaces, named after the + connector type on the printer. + + + + 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. + + 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. + - If you have already connected your printer and have successfully - printed with it under another operating system, you can probably skip - to section Software - Setup. - - - Ports and Cables + + Parallel Ports - Nearly all printers you can get for a PC today support one or - both of the following interfaces: - - - - Serial interfaces use a serial port on - your computer to send data to the printer. Serial interfaces - are common in the computer industry and cables are readily - available and also easy to construct. Serial interfaces - sometimes need special cables and might require you to configure - somewhat complex communications options. - - - - Parallel interfaces use a parallel port - on your computer to send data to the printer. Parallel - interfaces are common in the PC market. Cables are readily - available but more difficult to construct by hand. There are - usually no communications options with parallel interfaces, - making their configuration exceedingly simple. - - Parallel interfaces are sometimes known as - “Centronics” interfaces, named after the connector - type on the printer. - - - - 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. - - 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. - - So, which interface should you use? - - - - If you need two-way communication, use a serial port. - FreeBSD does not yet support two-way communication over a - parallel port. - - - - 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. - - - - Finally, use whatever works. - - - - - - Parallel Ports + 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. - To hook up a printer using a parallel interface, connect the - Centronics cable between the printer and the computer. The - instructions that came with the printer, the computer, or both - should give you complete guidance. - - Remember which parallel port you used on the computer. The - first parallel port is /dev/lpt0 to FreeBSD; - the second is /dev/lpt1, and so on. - - - - Serial Ports - - To hook up a printer using a serial interface, connect the - proper serial cable between the printer and the computer. The - instructions that came with the printer, the computer, or both - should give you complete guidance. - - If you are unsure what the “proper serial cable” is, - you may wish to try one of the following alternatives: - - - - A modem cable connects each pin of the - connector on one end of the cable straight through to its - corresponding pin of the connector on the other end. This type - of cable is also known as a “DTE-to-DCE” - cable. - - - - A null-modem cable connects some pins - straight through, swaps others (send data to receive data, for - example), and shorts some internally in each connector hood. - This type of cable is also known as a “DTE-to-DTE” - cable. - - - - A serial printer cable, required for - some unusual printers, is like the null modem cable, but sends - some signals to their counterparts instead of being internally - shorted. - - - - 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 - baud rate) rate that both your computer and the - printer can support. Choose 7 or 8 data bits; none, even, or odd - parity; and 1 or 2 stop bits. Also choose a flow control protocol: - either none, or XON/XOFF (also known as “in-band” or - “software”) flow control. Remember these settings for - the software configuration that follows. - - - - - Software Setup - - This section describes the software setup necessary to print - with the LPD spooling system in FreeBSD. - - Here is an outline of the steps involved: - - - - Configure your kernel, if necessary, for the port you are - using for the printer; section Kernel Configuration tells you - what you need to do. - - - - Set the communications mode for the parallel port, if you are - using a parallel port; section Setting the Communication - Mode for the Parallel Port gives details. - - - - Test if the operating system can send data to the printer. - Section Checking Printer - Communications gives some suggestions on how to do - this. - - - - Set up LPD for the printer by modifying the file - /etc/printcap. Section The /etc/printcap File shows - you how. - - - - - Kernel Configuration - - 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. - - To find out if the kernel you are currently using supports a - serial interface, type: - - &prompt.root; dmesg | grep sioN - - Where N is the number of the serial - port, starting from zero. If you see output similar to the - following: - - sio2 at 0x3e8-0x3ef irq 5 on isa -sio2: type 16550A - - then the kernel supports the port. - - To find out if the kernel supports a parallel interface, - type: - - &prompt.root; dmesg | grep lptN - - Where N is the number of the parallel - port, starting from zero. If you see output similar to the - following lpt0 at 0x378-0x37f on isa then the - kernel supports the port. - - You might have to reconfigure your kernel in order for the - operating system to recognize and use the parallel or serial port - you are using for the printer. - - To add support for a serial port, see the section on kernel - configuration. To add support for a parallel port, see that section - and the section that follows. - - - Adding <filename>/dev</filename> Entries for the Ports - - 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 /dev - directory are for. - - To add a /dev entry for a - port: - - - - Become root with the &man.su.1; command. Enter the root - password when prompted. - - - - Change to the /dev directory: - - &prompt.root; cd /dev - - - - - Type: - - &prompt.root; ./MAKEDEV port - - Where port is the device entry - for the port you want to make. Use lpt0 - for the first parallel port, lpt1 for the - second, and so on; use ttyd0 for the first - serial port, ttyd1 for the second, and so - on. - - - - Type: - - &prompt.root; ls -l port - - to make sure the device entry got created. - - + Remember which parallel port you used on the computer. + The first parallel port is /dev/lpt0 to + FreeBSD; the second is /dev/lpt1, and so + on. + + Serial Ports + + To hook up a printer using a serial interface, connect the + proper serial cable between the printer and the computer. The + instructions that came with the printer, the computer, or both + should give you complete guidance. + + If you are unsure what the “proper serial + cable” is, you may wish to try one of the following + alternatives: + + + + A modem cable connects each pin + of the connector on one end of the cable straight through + to its corresponding pin of the connector on the other + end. This type of cable is also known as a + “DTE-to-DCE” cable. + + + + A null-modem cable connects some + pins straight through, swaps others (send data to receive + data, for example), and shorts some internally in each + connector hood. This type of cable is also known as a + “DTE-to-DTE” cable. + + + + A serial printer cable, required + for some unusual printers, is like the null modem cable, + but sends some signals to their counterparts instead of + being internally shorted. + + + + 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 + baud rate) rate that both your computer + and the printer can support. Choose 7 or 8 data bits; none, + even, or odd parity; and 1 or 2 stop bits. Also choose a flow + control protocol: either none, or XON/XOFF (also known as + “in-band” or “software”) flow control. + Remember these settings for the software configuration that + follows. + + + + + Software Setup + + This section describes the software setup necessary to print + with the LPD spooling system in FreeBSD. + + Here is an outline of the steps involved: + + + + Configure your kernel, if necessary, for the port you + are using for the printer; section Kernel Configuration tells + you what you need to do. + + + + Set the communications mode for the parallel port, if + you are using a parallel port; section Setting the + Communication Mode for the Parallel Port gives + details. + + + + Test if the operating system can send data to the printer. + Section Checking Printer + Communications gives some suggestions on how to do + this. + + + + Set up LPD for the printer by modifying the file + /etc/printcap. You will find out how + to do this later in this chapter. + + + + + Kernel Configuration + + 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. + + To find out if the kernel you are currently using supports + a serial interface, type: + + &prompt.root; dmesg | grep sioN + + Where N is the number of the + serial port, starting from zero. If you see output similar to + the following: + + sio2 at 0x3e8-0x3ef irq 5 on isa +sio2: type 16550A + + then the kernel supports the port. + + To find out if the kernel supports a parallel interface, + type: + + &prompt.root; dmesg | grep lptN + + Where N is the number of the + parallel port, starting from zero. If you see output similar + to the following lpt0 at 0x378-0x37f on isa + then the kernel supports the port. + + You might have to reconfigure your kernel in order for the + operating system to recognize and use the parallel or serial + port you are using for the printer. + + To add support for a serial port, see the section on + kernel configuration. To add support for a parallel port, see + that section and the section that + follows. + + + + + Adding <filename>/dev</filename> Entries for the + Ports + + 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 + /dev directory are for. + + To add a /dev entry for a + port: + + + + Become root with the &man.su.1; command. Enter the + root password when prompted. + + + + Change to the /dev + directory: + + &prompt.root; cd /dev + + + + Type: + + &prompt.root; ./MAKEDEV port + + Where port is the device + entry for the port you want to make. Use + lpt0 for the first parallel port, + lpt1 for the second, and so on; use + ttyd0 for the first serial port, + ttyd1 for the second, and so on. + + + + Type: + + &prompt.root; ls -l port + + to make sure the device entry got created. + + + - Setting the Communication Mode for the Parallel Port - + Setting the Communication Mode for the Parallel + Port + When you are using the parallel interface, you can choose whether FreeBSD should use interrupt-driven or polled communication with the printer. - + - The interrupt-driven method is the - default with the GENERIC kernel. With this method, the - operating system uses an IRQ line to determine when the - printer is ready for data. + The interrupt-driven method is + the default with the GENERIC kernel. With this method, + the operating system uses an IRQ line to determine when + the printer is ready for data. - + The polled 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. + operating system to repeatedly ask the printer if it is + ready for more data. When it responds ready, the kernel + sends more data. - - The interrupt-driven method is somewhat faster but uses up a - precious IRQ line. You should use whichever one works. - + + The interrupt-driven method is somewhat faster but uses up + a precious IRQ line. You should use whichever one + works. + You can set the communications mode in two ways: by configuring the kernel or by using the &man.lptcontrol.8; program. - - To set the communications mode by configuring the - kernel: - + + To set the communications mode by configuring + the kernel: + - Edit your kernel configuration file. Look for or add an - lpt0 entry. If you are setting up the - second parallel port, use lpt1 instead. - Use lpt2 for the third port, and so - on. - + Edit your kernel configuration file. Look for or add + an lpt0 entry. If you are setting up + the second parallel port, use lpt1 + instead. Use lpt2 for the third port, + and so on. + If you want interrupt-driven mode, add the irq specifier: - + device lpt0 at isa? port? tty irq N vector lptintr - Where N is the IRQ number - for your computer's parallel port. + Where N is the IRQ + number for your computer's parallel port. - + If you want polled mode, do not add the irq specifier: - + device lpt0 at isa? port? tty vector lptintr - + Save the file. Then configure, build, and install the - kernel, then reboot. See kernel - configuration for more details. + kernel, then reboot. See kernel configuration for + more details. - + To set the communications mode with - &man.lptcontrol.8;: - + &man.lptcontrol.8;: + Type: - + &prompt.root; lptcontrol -i -u N - + to set interrupt-driven mode for lptN. - + Type: - + &prompt.root; lptcontrol -p -u N - + to set polled-mode for lptN. - + You could put these commands in your - /etc/rc.local file to set the mode each time - your system boots. See &man.lptcontrol.8; for more + /etc/rc.local file to set the mode each + time your system boots. See &man.lptcontrol.8; for more information. Checking Printer Communications - - 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. - + + 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. + To test the printer, we will send some text to it. For printers that can immediately print characters sent to them, the program &man.lptest.1; is perfect: it generates all 96 printable ASCII characters in 96 lines. - - 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: + + 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: %!PS @@ -559,288 +560,302 @@ device lpt0 at isa? port? tty vector lptintr 310 310 moveto /Helvetica findfont 12 scalefont setfont (Is this thing working?) show showpage - + - 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. - - + When this document refers to a printer language, it is + 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. + + Checking a Parallel Printer - + This section tells you how to check if FreeBSD can - communicate with a printer connected to a parallel port. - + communicate with a printer connected to a parallel + port. + To test a printer on a parallel - port: - + port: + Become root with &man.su.1;. - + Send data to the printer. If the printer can print plain text, then use - &man.lptest.1;. Type: - + &man.lptest.1;. Type: + &prompt.root; lptest > /dev/lptN - - Where N is the number of - the parallel port, starting from zero. + + Where N is the number + of the parallel port, starting from zero. - + If the printer understands PostScript or other printer language, then send a small program to the printer. Type: - + &prompt.root; cat > /dev/lptN - + Then, line by line, type the program - carefully 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. - - Alternatively, you can put the program in a file and - type: - + carefully 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. + + Alternatively, you can put the program in a file + and type: + &prompt.root; cat file > /dev/lptN - - Where file is the name of - the file containing the program you want to send to the - printer. + + Where file is the + name of the file containing the program you want to + send to the printer. - - You should see something print. Do not worry if the text - does not look right; we will fix such things later. + + You should see something print. Do not worry if the + text does not look right; we will fix such things + later. - + Checking a Serial Printer - + This section tells you how to check if FreeBSD can communicate with a printer on a serial port. - + To test a printer on a serial - port: - + port: + Become root with &man.su.1;. - + - Edit the file /etc/remote. Add the - following entry: - + Edit the file /etc/remote. Add + the following entry: + printer:dv=/dev/port:br#bps-rate:pa=parity Where port is the device entry for the serial port (ttyd0, ttyd1, etc.), - bps-rate is the bits-per-second - rate at which the printer communicates, and - parity is the parity required by - the printer (either even, + bps-rate is the + bits-per-second rate at which the printer communicates, + and parity is the parity + required by the printer (either even, odd, none, or zero). - - Here is a sample entry for a printer connected via a - serial line to the third serial port at 19200 bps with no - parity: - + + Here is a sample entry for a printer connected via + a serial line to the third serial port at 19200 bps with + no parity: + printer:dv=/dev/ttyd2:br#19200:pa=none - + - Connect to the printer with &man.tip.1;. Type: - + Connect to the printer with &man.tip.1;. + Type: + &prompt.root; tip printer - + If this step does not work, edit the file /etc/remote again and try using /dev/cuaaN instead of /dev/ttydN. - + Send data to the printer. If the printer can print plain text, then use - &man.lptest.1;. Type: - + &man.lptest.1;. Type: + ~$lptest - + If the printer understands PostScript or other printer language, then send a small program to the - printer. Type the program, line by line, very - carefully as backspacing or other editing - keys may be significant to the printer. You may also - need to type a special end-of-file key for the printer - so it knows it received the whole program. For - PostScript printers, press CONTROL+D. - - Alternatively, you can put the program in a file and - type: - + printer. Type the program, line by line, + very carefully as backspacing + or other editing keys may be significant to the + printer. You may also need to type a special + end-of-file key for the printer so it knows it + received the whole program. For PostScript + printers, press CONTROL+D. + + Alternatively, you can put the program in a file + and type: + ~>file - - Where file is the name of - the file containing the program. After - &man.tip.1; sends the file, press any required + + Where file is the + name of the file containing the program. After + &man.tip.1; sends the file, press any required end-of-file key. - - You should see something print. Do not worry if the text - does not look right; we will fix that later. + + You should see something print. Do not worry if the + text does not look right; we will fix that later. - + Enabling the Spooler: The <filename>/etc/printcap</filename> File 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. - + 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. + You configure LPD by editing the file - /etc/printcap. The LPD spooling system reads - this file each time the spooler is used, so updates to the file take - immediate effect. - - The format of the &man.printcap.5; file is straightforward. Use - your favorite text editor to make changes to + /etc/printcap. The LPD spooling system + reads this file each time the spooler is used, so updates to the + file take immediate effect. + + The format of the &man.printcap.5; file is straightforward. + Use your favorite text editor to make changes to /etc/printcap. The format is identical to other capability files like /usr/share/misc/termcap and - /etc/remote. For complete information about - the format, see the &man.cgetent.3;. - + /etc/remote. For complete information + about the format, see the &man.cgetent.3;. + The simple spooler configuration consists of the following steps: - Pick a name (and a few convenient aliases) for the printer, - and put them in the /etc/printcap file; see - Naming the - Printer. + Pick a name (and a few convenient aliases) for the + printer, and put them in the + /etc/printcap file; see the + Naming the Printer + section for more information on naming. - + - Turn off header pages (which are on by default) by inserting - the sh capability; see Suppressing Header - Pages. + Turn off header pages (which are on by default) by + inserting the sh capability; see the + Suppressing Header + Pages section for more information. - + - Make a spooling directory, and specify its location with the - sd capability; see Making the Spooling - Directory. + Make a spooling directory, and specify its location with + the sd capability; see the Making the Spooling + Directory section for more information. - + Set the /dev entry to use for the - printer, and note it in /etc/printcap with - the lp capability; see Identifying the Printer - Device. Also, if the printer is on a serial port, set - up the communication parameters with the fs, - fc, xs, and - xc capabilities; see Configuring Spooler - Communications Parameters. + printer, and note it in /etc/printcap + with the lp capability; see the Identifying the Printer + Device for more information. Also, if the printer is + on a serial port, set up the communication parameters with + the fs, fc, + xs, and xc + capabilities; which is discussed in the Configuring Spooler + Communications Parameters section. - + - Install a plain text input filter; see Installing the Text - Filter + Install a plain text input filter; see the Installing the Text + Filter section for details. - + Test the setup by printing something with the - &man.lpr.1; command; see Trying It Out and Troubleshooting. + &man.lpr.1; command. More details are available in the + Trying It Out and + Troubleshooting + sections. - 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. + 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. - 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 and 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 Accommodating Plain Text - Jobs on PostScript Printers tells how to do this. - + 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 and + 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. The section entitled Accommodating Plain + Text Jobs on PostScript Printers tells how to do + this. + Naming the Printer - - 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. - + + 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. + At least one of the printers specified in the /etc/printcap should have the alias - lp. This is the default printer's name. If - users do not have the PRINTER environment variable - nor specify a printer name on the command line of any of the LPD - commands, then lp will be the default printer - they get to use. - + lp. This is the default printer's name. + If users do not have the PRINTER environment + variable nor specify a printer name on the command line of any + of the LPD commands, then lp will be the + default printer they get to use. + Also, it is common practice to make the last alias for a - printer be a full description of the printer, including make and - model. - - Once you have picked a name and some common aliases, put them - in the /etc/printcap file. The name of the - printer should start in the leftmost column. Separate each alias - with a vertical bar and put a colon after the last alias. - + printer be a full description of the printer, including make + and model. + + Once you have picked a name and some common aliases, put + them in the /etc/printcap file. The name + of the printer should start in the leftmost column. Separate + each alias with a vertical bar and put a colon after the last + alias. + In the following example, we start with a skeletal - /etc/printcap that defines two printers (a - Diablo 630 line printer and a Panasonic KX-P4455 PostScript laser - printer): + /etc/printcap that defines two printers + (a Diablo 630 line printer and a Panasonic KX-P4455 PostScript + laser printer): # @@ -849,14 +864,14 @@ printer:dv=/dev/ttyd2:br#19200:pa=none rattan|line|diablo|lp|Diablo 630 Line Printer: bamboo|ps|PS|S|panasonic|Panasonic KX-P4455 PostScript v51.4: - + In this example, the first printer is named rattan and has as aliases line, diablo, lp, and Diablo 630 Line - Printer. Since it has the alias - lp, it is also the default printer. The second - is named bamboo, and has as aliases + Printer. Since it has the alias + lp, it is also the default printer. The + second is named bamboo, and has as aliases ps, PS, S, panasonic, and Panasonic KX-P4455 PostScript v51.4. @@ -864,20 +879,21 @@ bamboo|ps|PS|S|panasonic|Panasonic KX-P4455 PostScript v51.4: Suppressing Header Pages - + The LPD spooling system will by default print a - header page for each job. The header page - contains the user name who requested the job, the host from which - the job came, and the name of the job, in nice large letters. - Unfortunately, all this extra text gets in the way of debugging - the simple printer setup, so we will suppress header pages. - + header page for each job. The header + page contains the user name who requested the job, the host + from which the job came, and the name of the job, in nice + large letters. Unfortunately, all this extra text gets in the + way of debugging the simple printer setup, so we will suppress + header pages. + To suppress header pages, add the sh capability to the entry for the printer in - /etc/printcap. Here is the example + /etc/printcap. Here is an example /etc/printcap with sh added: - + # # /etc/printcap for host rose - no header pages anywhere @@ -888,59 +904,61 @@ rattan|line|diablo|lp|Diablo 630 Line Printer:\ bamboo|ps|PS|S|panasonic|Panasonic KX-P4455 PostScript v51.4:\ :sh: - 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. + 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. Making the Spooling Directory - + The next step in the simple spooler setup is to make a - spooling directory, a directory where print - jobs reside until they are printed, and where a number of other - spooler support files live. - - Because of the variable nature of spooling directories, it is - customary to put these directories under - /var/spool. It is not necessary to backup - the contents of spooling directories, either. Recreating them is - as simple as running &man.mkdir.1;. - - It is also customary to make the directory with a name that is - identical to the name of the printer, as shown below: - + spooling directory, a directory where + print jobs reside until they are printed, and where a number + of other spooler support files live. + + Because of the variable nature of spooling directories, it + is customary to put these directories under + /var/spool. It is not necessary to + backup the contents of spooling directories, either. + Recreating them is as simple as running &man.mkdir.1;. + + It is also customary to make the directory with a name + that is identical to the name of the printer, as shown + below: + &prompt.root; mkdir /var/spool/printer-name - - 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 rattan and + + 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 + rattan and bamboo: - + &prompt.root; mkdir /var/spool/lpd &prompt.root; mkdir /var/spool/lpd/rattan &prompt.root; mkdir /var/spool/lpd/bamboo - + - 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: - + 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: + &prompt.root; chown daemon.daemon /var/spool/lpd/rattan &prompt.root; chown daemon.daemon /var/spool/lpd/bamboo &prompt.root; chmod 770 /var/spool/lpd/rattan &prompt.root; chmod 770 /var/spool/lpd/bamboo - - Finally, you need to tell LPD about these directories using - the /etc/printcap file. You specify the - pathname of the spooling directory with the sd - capability: + + Finally, you need to tell LPD about these directories + using the /etc/printcap file. You + specify the pathname of the spooling directory with the + sd capability: # @@ -952,35 +970,37 @@ rattan|line|diablo|lp|Diablo 630 Line Printer:\ bamboo|ps|PS|S|panasonic|Panasonic KX-P4455 PostScript v51.4:\ :sh:sd=/var/spool/lpd/bamboo: - 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. - + Note that the name of the printer starts in the first + column but all other entries describing the printer should be + indented with a tab and each line escaped with a + backslash. + If you do not specify a spooling directory with sd, the spooling system will use /var/spool/lpd as a default. - + Identifying the Printer Device - - In section Adding /dev - Entries for the Ports, we identified which entry in the + + In the Adding + /dev Entries for the Ports + section, we identified which entry in the /dev directory FreeBSD will use to - communicate with the printer. Now, we tell LPD that information. - When the spooling system has a job to print, it will open the - specified device on behalf of the filter program (which is - responsible for passing data to the printer). - + communicate with the printer. Now, we tell LPD that + information. When the spooling system has a job to print, it + will open the specified device on behalf of the filter program + (which is responsible for passing data to the printer). + List the /dev entry pathname in the /etc/printcap file using the lp capability. - + In our running example, let us assume that rattan is on the first parallel port, and - bamboo is on a sixth serial port; here are the - additions to /etc/printcap: - + bamboo is on a sixth serial port; here are + the additions to /etc/printcap: + # # /etc/printcap for host rose - identified what devices to use @@ -992,45 +1012,46 @@ rattan|line|diablo|lp|Diablo 630 Line Printer:\ bamboo|ps|PS|S|panasonic|Panasonic KX-P4455 PostScript v51.4:\ :sh:sd=/var/spool/lpd/bamboo:\ :lp=/dev/ttyd5: - - If you do not specify the lp capability for - a printer in your /etc/printcap file, LPD - uses /dev/lp as a default. + + If you do not specify the lp capability + for a printer in your /etc/printcap file, + LPD uses /dev/lp as a default. /dev/lp currently does not exist in FreeBSD. - - If the printer you are installing is connected to a parallel - port, skip to the section Installing the Text Filter. - Otherwise, be sure to follow the instructions in the next - section. + + If the printer you are installing is connected to a + parallel port, skip to the section entitled, Installing the Text + Filter. Otherwise, be sure to follow the instructions + in the next section. - + Configuring Spooler Communication Parameters - + 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 + parity, and other serial communication parameters on behalf of + the filter program that sends data to the printer. This is advantageous since: - + It lets you try different communication parameters by - simply editing the /etc/printcap file; - you do not have to recompile the filter program. + simply editing the /etc/printcap + file; you do not have to recompile the filter + program. - + It enables the spooling system to use the same filter - program for multiple printers which may have different serial - communication settings. + program for multiple printers which may have different + serial communication settings. - The following /etc/printcap capabilities - control serial communication parameters of the device listed in - the lp capability: + The following /etc/printcap + capabilities control serial communication parameters of the + device listed in the lp capability: @@ -1039,69 +1060,75 @@ bamboo|ps|PS|S|panasonic|Panasonic KX-P4455 PostScript v51.4:\ Sets the communications speed of the device to bps-rate, where - bps-rate can be 50, 75, 110, 134, - 150, 200, 300, 600, 1200, 1800, 2400, 4800, 9600, 19200, or - 38400 bits-per-second. + bps-rate can be 50, 75, 110, + 134, 150, 200, 300, 600, 1200, 1800, 2400, 4800, 9600, + 19200, or 38400 bits-per-second. - + fc#clear-bits - + Clears the flag bits clear-bits in the - sgttyb structure after opening - the device. + sgttyb structure after + opening the device. - + fs#set-bits - + - Sets the flag bits set-bits - in the sgttyb structure. + Sets the flag bits + set-bits in the + sgttyb structure. - + xc#clear-bits - + Clears local mode bits clear-bits after opening the device. - + xs#set-bits - + Sets local mode bits set-bits. - + For more information on the bits for the fc, fs, - xc, and xs capabilities, see - the file + xc, and xs capabilities, + see the file /usr/include/sys/ioctl_compat.h. - + When LPD opens the device specified by the - lp capability, it reads the flag bits in the - sgttyb structure; it clears any bits in the - fc capability, then sets bits in the + lp capability, it reads the flag bits in + the sgttyb structure; it clears any bits in + the fc capability, then sets bits in the fs capability, then applies the resultant - setting. It does the same for the local mode bits as well. - - 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: + setting. It does the same for the local mode bits as + well. + + 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: bamboo|ps|PS|S|panasonic|Panasonic KX-P4455 PostScript v51.4:\ @@ -1111,35 +1138,38 @@ bamboo|ps|PS|S|panasonic|Panasonic KX-P4455 PostScript v51.4:\ Installing the Text Filter - - We are now ready to tell LPD what text filter to use to send - jobs to the printer. A text filter, also - known as an input filter, is a program that - LPD runs when it has a job to print. When LPD runs the text - filter for a printer, it sets the filter's standard input to the - job to print, and its standard output to the printer device - specified with the lp 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 Filters. - - For our simple printer setup, the text filter can be a small - shell script that just executes /bin/cat to - send the job to the printer. FreeBSD comes with another filter - called lpf that handles backspacing and - underlining for printers that might not deal with such character - streams well. And, of course, you can use any other filter - program you want. The filter lpf is described - in detail in section lpf: a - Text Filter. - + + We are now ready to tell LPD what text filter to use to + send jobs to the printer. A text filter, + also known as an input filter, is a + program that LPD runs when it has a job to print. When LPD + runs the text filter for a printer, it sets the filter's + standard input to the job to print, and its standard output to + the printer device specified with the lp + 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 + the Filters + section. + + For our simple printer setup, the text filter can be a + small shell script that just executes + /bin/cat to send the job to the printer. + FreeBSD comes with another filter called + lpf that handles backspacing and + underlining for printers that might not deal with such + character streams well. And, of course, you can use any other + filter program you want. The filter lpf is + described in detail in section entitled lpf: a Text + Filter. + First, let us make the shell script - /usr/local/libexec/if-simple be a simple text - filter. Put the following text into that file with your favorite - text editor: - + /usr/local/libexec/if-simple be a simple + text filter. Put the following text into that file with your + favorite text editor: + #!/bin/sh # @@ -1150,17 +1180,17 @@ bamboo|ps|PS|S|panasonic|Panasonic KX-P4455 PostScript v51.4:\ /bin/cat && exit 0 exit 2 - + Make the file executable: - + &prompt.root; chmod 555 /usr/local/libexec/if-simple - + And then tell LPD to use it by specifying it with the if capability in /etc/printcap. We will add it to the two printers we have so far in the example /etc/printcap: - + # # /etc/printcap for host rose - added text filter @@ -1177,357 +1207,2346 @@ bamboo|ps|PS|S|panasonic|Panasonic KX-P4455 PostScript v51.4:\ Trying It Out - + 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 &man.lpr.1;, + 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 &man.lpr.1;, which submits a job for printing. - - You can combine &man.lpr.1; with the &man.lptest.1; program, - introduced in section Checking - Printer Communications to generate some test text. + + You can combine &man.lpr.1; with the &man.lptest.1; + program, introduced in section Checking Printer + Communications to generate some test text. To test the simple LPD setup: - + Type: - + &prompt.root; lptest 20 5 | lpr -Pprinter-name - Where printer-name is a the name of - a printer (or an alias) specified in - /etc/printcap. To test the default printer, - type &man.lpr.1; without any - argument. Again, if you are testing a printer - that expects PostScript, send a PostScript program in that - language instead of using &man.lptest.1;. You can do so by - putting the program in a file and typing lpr - file. + Where printer-name is a the + name of a printer (or an alias) specified in + /etc/printcap. To test the default + printer, type &man.lpr.1; without any + argument. Again, if you are testing a printer that expects + PostScript, send a PostScript program in that language instead + of using &man.lptest.1;. You can do so by putting the program + in a file and typing lpr + file. - For a PostScript printer, you should get the results of the - program. If you are using &man.lptest.1;, then your results - should look like the following: + For a PostScript printer, you should get the results of + the program. If you are using &man.lptest.1;, then your + results should look like the following: - + !"#$%&'()*+,-./01234 "#$%&'()*+,-./012345 #$%&'()*+,-./0123456 $%&'()*+,-./01234567 %&'()*+,-./012345678 - - To further test the printer, try downloading larger programs - (for language-based printers) or running &man.lptest.1; with - different arguments. For example, lptest 80 60 - will produce 60 lines of 80 characters each. - - If the printer did not work, see the next section, Troubleshooting. - - - Troubleshooting - - After performing the simple test with &man.lptest.1;, you - might have gotten one of the following results instead of the - correct printout: - - - - It worked, after awhile; or, it did not eject a full - sheet. - - - 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. - - 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. - - The following replacement for the shell script - /usr/local/libexec/if-simple prints a - form feed after it sends the job to the printer: + To further test the printer, try downloading larger + programs (for language-based printers) or running + &man.lptest.1; with different arguments. For example, + lptest 80 60 will produce 60 lines of 80 + characters each. - -#!/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 - - - - - It produced the “staircase effect.” - - - You got the following on paper: - - -!"#$%&'()*+,-./01234 - "#$%&'()*+,-./012345 - #$%&'()*+,-./0123456 - - You have become another victim of the - staircase effect, caused by conflicting - interpretations of what characters should indicate a - new-line. UNIX-style operating systems use a single - character: ASCII code 10, the line feed (LF). MS-DOS, OS/2, - and others uses a pair of characters, ASCII code 10 - and ASCII code 13 (the carriage return - or CR). Many printers use the MS-DOS convention for - representing new-lines. - - When you print with FreeBSD, your text used just the - line feed character. The printer, upon seeing a line feed - character, advanced the paper one line, but maintained the - same horizontal position on the page for the next character - to print. That is what the carriage return is for: to move - the location of the next character to print to the left edge - of the paper. - - Here is what FreeBSD wants your printer to do: - - - - - - Printer received CR - Printer prints CR - - - - Printer received LF - Printer prints CR + LF - - - - - - Here are some ways to achieve this: - - - - 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. - - - If you boot your system into other operating - systems besides FreeBSD, you may have to - reconfigure the printer to use a - an interpretation for CR and LF characters that those - other operating systems use. You might prefer one of - the other solutions, below. - - - - - Have FreeBSD's serial line driver automatically - convert LF to CR+LF. Of course, this works with - printers on serial ports only. To - enable this feature, set the CRMOD bit in - fs capability in the - /etc/printcap file for the - printer. - - - - Send an escape code to the - printer to have it temporarily treat LF characters - differently. Consult your printer's manual for escape - codes that your printer might support. When you find - the proper escape code, modify the text filter to send - the code first, then send the print job. - - 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. - - -#!/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. Ejects the page when done. - -printf "\033&k2G" && cat && printf "\033&l0H" && exit 0 -exit 2 - - Here is an example - /etc/printcap from a host called - orchid. It has a single printer attached to its first - parallel port, a Hewlett Packard LaserJet 3Si named - teak. It is using the above script as - its text filter: - - -# -# /etc/printcap for host orchid -# -teak|hp|laserjet|Hewlett Packard LaserJet 3Si:\ - :lp=/dev/lpt0:sh:sd=/var/spool/lpd/teak:mx#0:\ - :if=/usr/local/libexec/hpif: - - - - - - - It overprinted each line. - - - The printer never advanced a line. All of the lines of - text were printed on top of each other on one line. - - This problem is the “opposite” of the - staircase effect, described above, and is much rarer. - Somewhere, the LF characters that FreeBSD uses to end a line - are being treated as CR characters to return the print - location to the left edge of the paper, but not also down a - line. - - Use the printer's configuration switches or control - panel to enforce the following interpretation of LF and CR - characters: - - - - - - Printer receives - Printer prints - - - - - - CR - CR - - - - LF - CR + LF - - - - - - - - The printer lost characters. - - - 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. - - 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: - - - - If the printer supports XON/XOFF flow control, have - FreeBSD use it by specifying the TANDEM bit in the - fs capability. - - - - If the printer supports carrier flow control, - specify the MDMBUF bit in the fs - capability. Make sure the cable connecting the printer - to the computer is correctly wired for carrier flow - control. - - - - If the printer does not support any flow control, - use some combination of the NLDELAY, TBDELAY, CRDELAY, - VTDELAY, and BSDELAY bits in the fs - capability to add appropriate delays to the stream of - data sent to the printer. - - - - - - - It printed garbage. - - - The printer printed what appeared to be random garbage, - but not the desired text. - - This is usually another symptom of incorrect - communications parameters with a serial printer. - Double-check the bps rate in the br - capability, and the parity bits in the fs - and fc capabilities; make sure the - printer is using the same settings as specified in the - /etc/printcap file. - - - - - Nothing happened. - - - If nothing happened, the problem is probably within - FreeBSD and not the hardware. Add the log file - (lf) capability to the entry for the - printer you are debugging in the - /etc/printcap file. For example, here - is the entry for rattan, with the - lf capability: - - -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 - - Then, try printing again. Check the log file (in our - example, /var/log/rattan.log) to see - any error messages that might appear. Based on the messages - you see, try to correct the problem. - - If you do not specify a lf - capability, LPD uses /dev/console as a - default. - - - + If the printer did not work, see the Troubleshooting + section. + + Advanced Printer Setup + + This section describes filters for printing specially formatted + files, header pages, printing across networks, and restricting and + accounting for printer usage. + + + Filters + + Although LPD handles network protocols, queuing, access control, + and other aspects of printing, most of the real + work happens in the filters. Filters are + programs that communicate with the printer and handle its device + dependencies and special requirements. In the simple printer setup, + we installed a plain text filter—an extremely simple one that + should work with most printers (section Installing the Text + Filter). + + However, in order to take advantage of format conversion, printer + accounting, specific printer quirks, and so on, you should understand + how filters work. It will ultimately be the filter's responsibility + to handle these aspects. And the bad news is that most of the time + you have to provide filters yourself. The good + news is that many are generally available; when they are not, they are + usually easy to write. + + Also, FreeBSD comes with one, + /usr/libexec/lpr/lpf, that works with many + printers that can print plain text. (It handles backspacing and tabs + in the file, and does accounting, but that is about all it does.) + There are also several filters and filter components in the FreeBSD + ports collection. + + Here is what you will find in this section: + + + + Section 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. + + + + 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 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. + + + + PostScript is a popular output format for many programs. Even + some people (myself included) write PostScript code directly. But + PostScript printers are expensive. Section 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 + non-PostScript printer. I recommend reading + this section if you do not have a PostScript printer. + + + + Section 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 lpr -t to print troff data, or + lpr -d to print TeX DVI data, or lpr + -v to print raster image data, and so forth. I + recommend reading this section. + + + + Section Output + Filters tells all about a not often used feature of LPD: + output filters. Unless you are printing header pages (see Header Pages), + you can probably skip that section altogether. + + + + Section lpf: a Text + Filter describes lpf, a fairly + complete if simple text filter for line printers (and laser + printers that act like line printers) that comes with FreeBSD. If + you need a quick way to get printer accounting working for plain + text, or if you have a printer which emits smoke when it sees + backspace characters, you should definitely consider + lpf. + + + + + How Filters Work + + As mentioned before, a filter is an executable program started + by LPD to handle the device-dependent part of communicating with the + printer. + + When LPD wants to print a file in a job, it starts a filter + program. It sets the filter's standard input to the file to print, + its standard output to the printer, and its standard error to the + error logging file (specified in the lf + capability in /etc/printcap, or + /dev/console by default). + + Which filter LPD starts and the filter's arguments depend on + what is listed in the /etc/printcap file and + what arguments the user specified for the job on the + &man.lpr.1; command line. For example, if the user typed + lpr -t, LPD would start the troff filter, listed + in the tf capability for the destination printer. + If the user wanted to print plain text, it would start the + if filter (this is mostly true: see Output Filters for + details). + + There are three kinds of filters you can specify in + /etc/printcap: + + + + The text filter, confusingly called the + input filter in LPD documentation, handles + regular text printing. Think of it as the default filter. LPD + expects every printer to be able to print plain text by default, + and it 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: + + + filter-name + -c + -wwidth + -llength + -iindent + -n login + -h host + acct-file + + + where + + + + + + + appears if the job's submitted with lpr + -l + + + + + width + + + is the value from the pw (page + width) capability specified in + /etc/printcap, default 132 + + + + + length + + + is the value from the pl (page + length) capability, default 66 + + + + + indent + + + is the amount of the indentation from lpr + -i, default 0 + + + + + login + + + is the account name of the user printing the + file + + + + + host + + + is the host name from which the job was + submitted + + + + + acct-file + + + is the name of the accounting file from the + af capability. + + + + + + + + A conversion filter 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 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: + + + filter-name + -xpixel-width + -ypixel-height + -n login + -h host + acct-file + + + where pixel-width is the value + from the px capability (default 0) and + pixel-height is the value from the + py capability (default 0). + + + + The output filter is used only if there + is no text filter, or if header pages are enabled. In my + experience, output filters are rarely used. Section Output Filters describe + them. There are only two arguments to an output filter: + + + filter-name + -wwidth + -llength + + + which are identical to the text filters and + arguments. + + + + Filters should also exit with the + following exit status: + + + + exit 0 + + + If the filter printed the file successfully. + + + + + exit 1 + + + If the filter failed to print the file but wants LPD to + try to print the file again. LPD will restart a filter if it + exits with this status. + + + + + exit 2 + + + If the filter failed to print the file and does not want + LPD to try again. LPD will throw out the file. + + + + + The text filter that comes with the FreeBSD release, + /usr/libexec/lpr/lpf, takes advantage of the + page width and length arguments to determine when to send a form + feed and how to account for printer usage. It uses the login, host, + and accounting file arguments to make the accounting entries. + + If you 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. + + + + Accommodating Plain Text Jobs on PostScript Printers + + 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. + + 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 + %! (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. + + How do we do this? + + If you have got a serial printer, a great way to do it is to + install lprps. lprps is a + PostScript printer filter which performs two-way communication with + the printer. It updates the printer's status file with verbose + information from the printer, so users and administrators can see + exactly what the state of the printer is (such as toner + low or paper jam). But more + importantly, it includes a program called psif + which detects whether the incoming job is plain text and calls + textps (another program that comes with + lprps) to convert it to PostScript. It then uses + lprps to send the job to the printer. + + lprps is part of the FreeBSD ports collection + (see The Ports Collection). You can + fetch, build and install it yourself, of course. After installing + lprps, just specify the pathname to the + psif program that is part of + lprps. If you installed lprps + from the ports collection, use the following in the serial + PostScript printer's entry in + /etc/printcap: + + +:if=/usr/local/libexec/psif: + + You should also specify the rw capability; + that tells LPD to open the printer in read-write mode. + + If you have a parallel PostScript printer (and therefore cannot + use two-way communication with the printer, which + lprps needs), you can use the following shell + script as the text filter: + + +#!/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 + + In the above script, textps is a program we + installed separately to convert plain text to PostScript. You can + use any text-to-PostScript program you wish. The FreeBSD ports + collection (see The Ports Collection) + includes a full featured text-to-PostScript program called + a2ps that you might want to investigate. + + + + Simulating PostScript on Non-PostScript Printers + + PostScript is the de facto standard for + high quality typesetting and printing. PostScript is, however, an + expensive standard. Thankfully, Alladin + Enterprises has a free PostScript work-alike called + Ghostscript that runs with FreeBSD. + Ghostscript can read most PostScript files and can render their + pages onto a variety of devices, including many brands of + non-PostScript printers. By installing Ghostscript and using a + special text filter for your printer, you can make your + non-PostScript printer act like a real PostScript printer. + + Ghostscript should be in the FreeBSD ports collection, if you + would like to install it from there. You can fetch, build, and + install it quite easily yourself, as well. + + To simulate PostScript, we have the text filter detect if it 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. + + Here is an example: the following script is a text filter + for Hewlett Packard DeskJet 500 printers. For other printers, + substitute the argument to the + gs (Ghostscript) command. (Type gs + -h to get a list of devices the current installation of + Ghostscript supports.) + + +#!/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. + # + # Note that PostScript files are actually interpreted programs, + # and those programs are allowed to write to stdout, which will + # mess up the printed output. So, we redirect stdout to stderr + # and then make descriptor 3 go to stdout, and have Ghostscript + # write its output there. Exercise for the clever reader: + # capture the stderr output from Ghostscript and mail it back to + # the user originating the print job. + # + exec 3>&1 1>&2 + /usr/local/bin/gs -dSAFER -dNOPAUSE -q -sDEVICE=djet500 \ + -sOutputFile=/dev/fd/3 - && exit 0 + + # + /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 "\033&l0H" && +exit 0 +fi + +exit 2 + + Finally, you need to notify LPD of the filter via the + if capability: + + +:if=/usr/local/libexec/hpif: + + That is it. You can type lpr plain.text and + lpr whatever.ps and both should print + successfully. + + + + Conversion Filters + + After completing the simple setup described in 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). + + + Why Install Conversion Filters? + + 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: + + &prompt.user; dvips seaweed-analysis.dvi +&prompt.user; lpr seaweed-analysis.ps + + 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: + + &prompt.user; lpr -d seaweed-analysis.dvi + + We got LPD to do the DVI file conversion for us by specifying + the option. Section Formatting and Conversion + Options lists the conversion options. + + For each of the conversion options you want a printer to + support, install a conversion filter and + specify its pathname in /etc/printcap. A + conversion filter is like the text filter for the simple printer + setup (see section Installing + the Text Filter) except that instead of printing plain + text, the filter converts the file into a format the printer can + understand. + + + + Which Conversions Filters Should I Install? + + 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. + + The following table summarizes the filters that LPD works + with, their capability entries for the + /etc/printcap file, and how to invoke them + with the lpr command: + + + + + + File type + /etc/printcap capability + lpr option + + + + + + cifplot + cf + + + + + DVI + df + + + + + plot + gf + + + + + ditroff + nf + + + + + FORTRAN text + rf + + + + + troff + rf + + + + + raster + vf + + + + + plain text + if + none, , or + + + + + + + In our example, using lpr -d means the + printer needs a df capability in its entry in + /etc/printcap. + + Despite what others might contend, formats like FORTRAN text + and plot are probably obsolete. At your site, you can give new + meanings to these or any of the formatting options just by + installing custom filters. For example, suppose you 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 + gf capability and then educate your users that + lpr -g mean “print Printerleaf + files.” + + + + Installing Conversion Filters + + Since conversion filters are programs you install outside of + the base FreeBSD installation, they should probably go under + /usr/local. The directory + /usr/local/libexec is a popular location, + since they are specialized programs that only LPD will run; + regular users should not ever need to run them. + + To enable a conversion filter, specify its pathname under the + appropriate capability for the destination printer in + /etc/printcap. + + In our example, we will add the DVI conversion filter to the + entry for the printer named bamboo. Here is + the example /etc/printcap file again, with + the new df capability for the printer + bamboo. + + +# +# /etc/printcap for host rose - added df filter for bamboo +# +rattan|line|diablo|lp|Diablo 630 Line Printer:\ + :sh:sd=/var/spool/lpd/rattan:\ + :lp=/dev/lpt0:\ + :if=/usr/local/libexec/if-simple: + +bamboo|ps|PS|S|panasonic|Panasonic KX-P4455 PostScript v51.4:\ + :sh:sd=/var/spool/lpd/bamboo:\ + :lp=/dev/ttyd5:fs#0x82000e1:xs#0x820:rw:\ + :if=/usr/local/libexec/psif:\ + :df=/usr/local/libexec/psdf: + + The DVI filter is a shell script named + /usr/local/libexec/psdf. Here is that + script: + + +#!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 "$@" + + This script runs dvips in filter mode (the + argument) on standard input, which is the job + to print. It then starts the PostScript printer filter + lprps (see section Accommodating Plain + Text Jobs on PostScript Printers) with the arguments LPD + passed to this script. lprps will use those + arguments to account for the pages printed. + + + + More Conversion Filter Examples + + 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. + + This example script is a raster (well, GIF file, actually) + conversion filter for a Hewlett Packard LaserJet III-Si + printer: + + +#!/bin/sh +# +# hpvf - Convert GIF files into HP/PCL, then print +# Installed in /usr/local/libexec/hpvf + +PATH=/usr/X11R6/bin:$PATH; export PATH +giftopnm | ppmtopgm | pgmtopbm | pbmtolj -resolution 300 \ + && exit 0 \ + || exit 2 + + It works by converting the GIF file into a portable anymap, + converting that into a portable graymap, converting that into a + portable bitmap, and converting that into LaserJet/PCL-compatible + data. + + Here is the /etc/printcap file with an + entry for a printer using the above filter: + + +# +# /etc/printcap for host orchid +# +teak|hp|laserjet|Hewlett Packard LaserJet 3Si:\ + :lp=/dev/lpt0:sh:sd=/var/spool/lpd/teak:mx#0:\ + :if=/usr/local/libexec/hpif:\ + :vf=/usr/local/libexec/hpvf: + + The following script is a conversion filter for troff data + from the groff typesetting system for the PostScript printer named + bamboo: + + +#!/bin/sh +# +# pstf - Convert groff's troff data into PS, then print. +# Installed in /usr/local/libexec/pstf +# +exec grops | /usr/local/libexec/lprps "$@" + + The above script makes use of lprps again + to handle the communication with the printer. If the printer were + on a parallel port, we would use this script instead: + + +#!/bin/sh +# +# pstf - Convert groff's troff data into PS, then print. +# Installed in /usr/local/libexec/pstf +# +exec grops + + That is it. Here is the entry we need to add to + /etc/printcap to enable the filter: + + +:tf=/usr/local/libexec/pstf: + + 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 + teak: + + +#!/bin/sh +# +# hprf - FORTRAN text filter for LaserJet 3si: +# Installed in /usr/local/libexec/hprf +# + +printf "\033&k2G" && fpr && printf "\033&l0H" && + exit 0 +exit 2 + + And we will add this line to the + /etc/printcap for the printer + teak to enable this filter: + + +:rf=/usr/local/libexec/hprf: + + Here is one final, somewhat complex example. We will add a + DVI filter to the LaserJet printer teak + introduced earlier. First, the easy part: updating + /etc/printcap with the location of the DVI + filter: + + +:df=/usr/local/libexec/hpdf: + + Now, for the hard part: making the filter. For that, we need + a DVI-to-LaserJet/PCL conversion program. The FreeBSD ports + collection (see The Ports Collection) + has one: dvi2xx is the name of the package. + Installing this package gives us the program we need, + dvilj2p, which converts DVI into LaserJet IIp, + LaserJet III, and LaserJet 2000 compatible codes. + + dvilj2p makes the filter + hpdf quite complex since + dvilj2p cannot read from standard input. It + wants to work with a filename. What is worse, the filename has to + end in .dvi so using + /dev/fd/0 for standard input is problematic. + We can get around that problem by linking (symbolically) a + temporary file name (one that ends in .dvi) + to /dev/fd/0, thereby forcing + dvilj2p to read from standard input. + + The only other fly in the ointment is the fact that we cannot + use /tmp for the temporary link. Symbolic + links are owned by user and group bin. The + filter runs as user daemon. And the + /tmp 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. + + Instead, the filter will make the symbolic link in the current + working directory, which is the spooling directory (specified by + the sd capability in + /etc/printcap). 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 + /tmp. + + Here, finally, is the filter: + + +#!/bin/sh +# +# hpdf - Print DVI data on HP/PCL printer +# Installed in /usr/local/libexec/hpdf + +PATH=/usr/local/bin:$PATH; export PATH + +# +# Define a function to clean up our temporary files. These exist +# in the current directory, which will be the spooling directory +# for the printer. +# +cleanup() { + rm -f hpdf$$.dvi +} + +# +# Define a function to handle fatal errors: print the given message +# and exit 2. Exiting with 2 tells LPD to 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 + + + + Automated Conversion: An Alternative To Conversion + Filters + + All these conversion filters accomplish a lot for your + printing environment, but at the cost forcing the user to specify + (on the &man.lpr.1; 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. + + 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 + file can be of help here. Of course, it will + be hard to determine the differences between + some file types—and, of course, you can + still provide conversion filters just for them. + + The FreeBSD ports collection has a text filter that performs + automatic conversion called apsfilter. It can + detect plain text, PostScript, and DVI files, run the proper + conversions, and print. + + + + + Output Filters + + 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: + + + + LPD starts an output filter once for the entire job instead + of once for each file in the job. + + + + LPD does not make any provision to identify the start or the + end of files within the job for the output filter. + + + + 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: + + + filter-name + -wwidth + -llength + + + Where width is from the + pw capability and + length is from the + pl capability for the printer in + question. + + + + 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 will not work. Use a text filter (also + known as an input filter); see section Installing the Text Filter. + Furthermore, an output filter is actually more + complex in that it has to examine the byte stream being + sent to it for special flag characters and must send signals to + itself on behalf of LPD. + + However, an output filter is necessary if + you want header pages and need to send escape sequences or other + initialization strings to be able to print the header page. (But it + is also futile 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.) + + 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 Header Pages) + only. LPD then expects the output filter to stop + itself by sending two bytes to the filter: ASCII 031 + followed by ASCII 001. When an output filter sees these two bytes + (031, 001), it should stop by sending SIGSTOP to itself. When LPD's + done running other filters, it will restart the output filter by + sending SIGCONT to it. + + If there is an output filter but no text + filter and LPD is working on a plain text job, LPD uses the output + filter to do the job. As stated before, the output filter will + print each file of the job in sequence with no intervening form + feeds or other paper advancement, and this is probably + not what you want. In almost all cases, you + need a text filter. + + The program lpf, 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 lpf. You + can also wrap lpf in a shell script to handle any + initialization codes the printer might require. + + + + <command>lpf</command>: a Text Filter + + The program /usr/libexec/lpr/lpf that comes + with FreeBSD binary distribution is a text filter (input filter) + that can indent output (job submitted with lpr + -i), allow literal characters to pass (job submitted + with lpr -l), adjust the printing position for + backspaces and tabs in the job, and account for pages printed. It + can also act like an output filter. + + lpf 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 + lpf. + + In order for lpf to do page accounting + correctly, it needs correct values filled in for the + pw and pl capabilities in the + /etc/printcap file. It uses these values to + determine how much text can fit on a page and how many pages were in + a user's job. For more information on printer accounting, see Accounting for Printer + Usage. + + + + + Header Pages + + If you have lots of users, all of them using + various printers, then you probably want to consider header + pages as a necessary evil. + + Header pages, also known as banner or + burst pages 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.) + + The LPD system can provide header pages automatically for your + printouts if 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 Header Pages on + PostScript Printers. + + + Enabling Header Pages + + In the Simple Printer + Setup, we turned off header pages by specifying + sh (meaning “suppress header”) in the + /etc/printcap file. To enable header pages for + a printer, just remove the sh capability. + + Sounds too easy, right? + + You are right. You might 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: + + +#!/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 + + Specify the path to the output filter in the + of capability. See Output Filters for more + information. + + Here is an example /etc/printcap file for + the printer teak that we introduced earlier; we + enabled header pages and added the above output filter: + + +# +# /etc/printcap for host orchid +# +teak|hp|laserjet|Hewlett Packard LaserJet 3Si:\ + :lp=/dev/lpt0:sd=/var/spool/lpd/teak:mx#0:\ + :if=/usr/local/libexec/hpif:\ + :vf=/usr/local/libexec/hpvf:\ + :of=/usr/local/libexec/hpof: + + Now, when users print jobs to teak, they get + a header page with each job. If users want to spend time searching + for their printouts, they can suppress header pages by submitting + the job with lpr -h; see Header Page Options for + more &man.lpr.1; options. + + + 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 ff + capability in /etc/printcap. + + + + + Controlling Header Pages + + By enabling header pages, LPD will produce a long + header, 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): + + + 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 + + LPD appends a form feed after this text so the job starts on a + new page (unless you have sf (suppress form + feeds) in the destination printer's entry in + /etc/printcap). + + If you prefer, LPD can make a short header; + specify sb (short banner) in the + /etc/printcap file. The header page will look + like this: + + +rose:kelly Job: outline Date: Sun Sep 17 11:07:51 1995 + + Also by default, LPD prints the header page first, then the job. + To reverse that, specify hl (header last) in + /etc/printcap. + + + + Accounting for Header Pages + + Using LPD's built-in header pages enforces a particular paradigm + when it comes to printer accounting: header pages must be + free of charge. + + Why? + + Because the output filter is the only external program that will + have control when the header page is printed that could do + accounting, and it is not provided with any user or + host 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 lpr -h. + They could still be charged for header pages they did not print. + Basically, lpr -h will be the preferred option of + environmentally-minded users, but you cannot offer any incentive to + use it. + + It is still not enough to have each of the + filters generate their own header pages (thereby being able to + charge for them). If users wanted the option of suppressing the + header pages with lpr -h, they will still get + them and be charged for them since LPD does not pass any knowledge + of the option to any of the filters. + + So, what are your options? + + You can: + + + + Accept LPD's paradigm and make header pages free. + + + + Install an alternative to LPD, such as LPRng or PLP. Section + Alternatives to the + Standard Spooler tells more about other spooling + software you can substitute for LPD. + + + + Write a smart 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 af capability), but if you have a + well-known accounting file, you can hard-code that into the + output filter. To facilitate the parsing step, use the + sh (short header) capability in + /etc/printcap. Then again, all that might + be too much trouble, and users will certainly appreciate the + more generous system administrator who makes header pages + free. + + + + + + Header Pages on PostScript Printers + + 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. + + 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 lpr + -h. + + 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: + + +#!/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 + + 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: + + +#!/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 + + 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 How Filters + Work). + + As we have mentioned before, the above scheme, though fairly + simple, disables the “suppress header page” option (the + option) to lpr. 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. + + To allow users to shut off header pages on a per-job basis, you + will need to use the trick introduced in section 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 lpr -h, 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. + + If you have a PostScript printer on a serial line, you can make + use of lprps, which comes with an output filter, + psof, which does the above. Note that + psof does not charge for header pages. + + + + + Networked Printing + + FreeBSD supports networked printing: sending jobs to remote + printers. Networked printing generally refers to two different + things: + + + + 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 Printers Installed on + Remote Hosts tells how to do this. + + + + 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: + + + + 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 Printers + Installed on Remote Hosts to set up such a + printer. + + + + 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 Printers with + Networked Data Stream Interfaces gives some + suggestions on installing such printers. + + + + + + + Printers Installed on Remote Hosts + + The LPD spooling system has built-in support for sending jobs to + other hosts also running LPD (or are compatible with LPD). This + feature enables you to install a printer on one host and make it + accessible from other hosts. It also works with printers that have + network interfaces that understand the LPD protocol. + + To enable this kind of remote printing, first install a printer + on one host, the printer host, using the simple + printer setup described in Simple + Printer Setup. Do any advanced setup in 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. Also ensure that the + local host has authorization to use the LPD + service in the remote host (see Restricting Jobs + from Remote Printers). + + If you are using a printer with a network interface that is + compatible with LPD, then the printer host in + the discussion below is the printer itself, and the + printer name is the name you configured for the + printer. See the documentation that accompanied your printer and/or + printer-network interface. + + + If you are using a Hewlett Packard Laserjet then the printer + name text will automatically perform the LF to + CRLF conversion for you, so you will not require the + hpif script. + + + Then, on the other hosts you want to have access to the printer, + make an entry in their /etc/printcap files with + the following: + + + + Name the entry anything you want. For simplicity, though, + you probably want to use the same name and aliases as on the + printer host. + + + + Leave the lp capability blank, explicitly + (:lp=:). + + + + Make a spooling directory and specify its location in the + sd capability. LPD will store jobs here + before they get sent to the printer host. + + + + Place the name of the printer host in the + rm capability. + + + + Place the printer name on the printer + host in the rp + capability. + + + + That is it. You do not need to list conversion filters, page + dimensions, or anything else in the + /etc/printcap file. + + Here is an example. The host rose has two + printers, bamboo and rattan. + We will enable users on the host orchid to print to those printers. + Here is the /etc/printcap file for + orchid (back from section Enabling Header + Pages). It already had the entry for the printer + teak; we have added entries for the two printers + on the host rose: + + +# +# /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: + + Then, we just need to make spooling directories on + orchid: + + &prompt.root; mkdir -p /var/spool/lpd/rattan /var/spool/lpd/bamboo +&prompt.root; chmod 770 /var/spool/lpd/rattan /var/spool/lpd/bamboo +&prompt.root; chown daemon.daemon /var/spool/lpd/rattan /var/spool/lpd/bamboo + + Now, users on orchid can print to + rattan and bamboo. If, for + example, a user on orchid typed + + &prompt.user; lpr -P bamboo -d sushi-review.dvi + + the LPD system on orchid would copy the job to the spooling + directory /var/spool/lpd/bamboo and note that + it was a DVI job. As soon as the host rose has room in its + bamboo spooling directory, the two LPDs would + transfer the file to rose. The file would wait in rose's queue + until it was finally printed. It would be converted from DVI to + PostScript (since bamboo is a PostScript printer) on rose. + + + + Printers with Networked Data Stream Interfaces + + 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 Printers Installed on + Remote Hosts. + + The format of the /etc/printcap 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. + + 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 + netprint takes all data on standard input and + sends it to a network-attached printer. We specify the hostname of + the printer as the first argument and the port number to which to + connect as the second argument to netprint. Note + that this supports one-way communication only (FreeBSD to printer); + many network printers support two-way communication, and you might + want to take advantage of that (to get printer status, perform + accounting, etc.). + + +#!/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; + + 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: + + +#!/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 + + + + + Restricting Printer Usage + + 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. + + + Restricting Multiple Copies + + The LPD system makes it easy for users to print multiple copies + of a file. Users can print jobs with lpr -#5 + (for example) and get five copies of each file in the job. Whether + this is a good thing is up to you. + + If you feel multiple copies cause unnecessary wear and tear on + your printers, you can disable the option to + &man.lpr.1; by adding the sc capability to the + /etc/printcap file. When users submit jobs + with the option, they will see: + + lpr: multiple copies are not allowed + + + Note that if you have set up access to a printer remotely (see + section Printers + Installed on Remote Hosts), you need the + sc capability on the remote + /etc/printcap files as well, or else users will + still be able to submit multiple-copy jobs by using another + host. + + Here is an example. This is the + /etc/printcap file for the host + rose. The printer rattan is + quite hearty, so we will allow multiple copies, but the laser + printer bamboo's a bit more delicate, so we will + disable multiple copies by adding the sc + capability: + + +# +# /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: + + Now, we also need to add the sc capability on + the host orchid's + /etc/printcap (and while we are at it, let us + disable multiple copies for the printer + teak): + + +# +# /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: + + By using the sc capability, we prevent the + use of lpr -#, but that still does not prevent + users from running &man.lpr.1; + multiple times, or from submitting the same file multiple times in + one job like this: + + &prompt.user; lpr forsale.sign forsale.sign forsale.sign forsale.sign forsale.sign + + There are many ways to prevent this abuse (including ignoring + it) which you are free to explore. + + + + Restricting Access To Printers + + You can control who can print to what printers by using the UNIX + group mechanism and the rg capability in + /etc/printcap. Just place the users you want + to have access to a printer in a certain group, and then name that + group in the rg capability. + + Users outside the group (including root) will be greeted with + + lpr: Not a member of the restricted group + + if they try to print to the controlled printer. + + As with the sc (suppress multiple copies) + capability, you need to specify rg on remote + hosts that also have access to your printers, if you feel it is + appropriate (see section Printers Installed on + Remote Hosts). + + For example, we will let anyone access the printer + rattan, but only those in group + artists can use bamboo. Here + is the familiar /etc/printcap for host + rose: + + +# +# /etc/printcap for host rose - restricted group for bamboo +# +rattan|line|diablo|lp|Diablo 630 Line Printer:\ + :sh:sd=/var/spool/lpd/rattan:\ + :lp=/dev/lpt0:\ + :if=/usr/local/libexec/if-simple: + +bamboo|ps|PS|S|panasonic|Panasonic KX-P4455 PostScript v51.4:\ + :sh:sd=/var/spool/lpd/bamboo:sc:rg=artists:\ + :lp=/dev/ttyd5:fs#0x82000e1:xs#0x820:rw:\ + :if=/usr/local/libexec/psif:\ + :df=/usr/local/libexec/psdf: + + Let us leave the other example + /etc/printcap file (for the host + orchid) alone. Of course, anyone on + orchid can print to bamboo. It + might be the case that we only allow certain logins on + orchid anyway, and want them to have access to the + printer. Or not. + + + There can be only one restricted group per printer. + + + + + Controlling Sizes of Jobs Submitted + + 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. + + LPD enables you to limit the maximum byte size a file in a job + can be with the mx 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; however, if no + mx capability is specified, then a default limit + of 1000 blocks will be used. + + + The limit applies to files in a job, and + not the total job size. + + + 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. + + Let us add limits to our example printers + rattan and bamboo. 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: + + +# +# /etc/printcap for host rose +# + +# +# No limit on job size: +# +rattan|line|diablo|lp|Diablo 630 Line Printer:\ + :sh:mx#0:sd=/var/spool/lpd/rattan:\ + :lp=/dev/lpt0:\ + :if=/usr/local/libexec/if-simple: + +# +# Limit of five megabytes: +# +bamboo|ps|PS|S|panasonic|Panasonic KX-P4455 PostScript v51.4:\ + :sh:sd=/var/spool/lpd/bamboo:sc:rg=artists:mx#5000:\ + :lp=/dev/ttyd5:fs#0x82000e1:xs#0x820:rw:\ + :if=/usr/local/libexec/psif:\ + :df=/usr/local/libexec/psdf: + + Again, the limits apply to the local users only. If you have + set up access to your printers remotely, remote users will not get + those limits. You will need to specify the mx + capability in the remote /etc/printcap files as + well. See section Printers Installed on + Remote Hosts for more information on remote + printing. + + There is another specialized way to limit job sizes from remote + printers; see section Restricting Jobs + from Remote Printers. + + + + Restricting Jobs from Remote Printers + + The LPD spooling system provides several ways to restrict print + jobs submitted from remote hosts: + + + + Host restrictions + + + You can control from which remote hosts a local LPD + accepts requests with the files + /etc/hosts.equiv and + /etc/hosts.lpd. LPD checks to see if an + incoming request is from a host listed in either one of these + files. If not, LPD refuses the request. + + The format of these files is simple: one host name per + line. Note that the file + /etc/hosts.equiv is also used by the + &man.ruserok.3; protocol, and affects programs like + &man.rsh.1; and &man.rcp.1;, so be careful. + + For example, here is the + /etc/hosts.lpd file on the host + rose: + + +orchid +violet +madrigal.fishbaum.de + + This means rose will accept requests from + the hosts orchid, violet, + and madrigal.fishbaum.de. If any + other host tries to access rose's LPD, LPD + will refuse them. + + + + + Size restrictions + + + You can control how much free space there needs to remain + on the filesystem where a spooling directory resides. Make a + file called minfree in the spooling + directory for the local printer. Insert in that file a number + representing how many disk blocks (512 bytes) of free space + there has to be for a remote job to be accepted. + + This lets you insure that remote users 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 + minfree file. + + For example, let us add a minfree + file for the printer bamboo. We examine + /etc/printcap to find the spooling + directory for this printer; here is bamboo's + entry: + + +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: + + The spooling directory is the given in the + sd 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: + + &prompt.root; echo 6144 > /var/spool/lpd/bam +boo/minfree + + + + + User restrictions + + + You can control which remote users can print to local + printers by specifying the rs capability in + /etc/printcap. When + rs appears in the entry for a + locally-attached printer, LPD will accept jobs from remote + hosts if the user submitting the job also + has an account of the same login name on the local host. + Otherwise, LPD refuses the job. + + This capability is particularly useful in an environment + where there are (for example) different departments sharing a + network, and some users transcend departmental boundaries. By + giving them accounts on your systems, they can use your + printers from their own departmental systems. If you would + rather allow them to use only your + printers and not your compute resources, you can give them + “token” accounts, with no home directory and a + useless shell like /usr/bin/false. + + + + + + + + Accounting for Printer Usage + + 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? + + 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 + your requirements in charging for printer + usage. + + To implement accounting, you have to modify a printer's text + filter (to charge for plain text jobs) and the conversion filters (to + charge for other file formats), to count pages or query the printer + for pages printed. You cannot get away with using the simple output + filter, since it cannot do accounting. See section Filters. + + Generally, there are two ways to do accounting: + + + + Periodic accounting 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. + + + + Timely accounting 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. + + + + 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. + + + Quick and Dirty Printer Accounting + + FreeBSD comes with two programs that can get you set up with + simple periodic accounting right away. They are the text filter + lpf, described in section lpf: a Text Filter, and + &man.pac.8;, a program to gather and total + entries from printer accounting files. + + As mentioned in the section on filters (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 af capability in + /etc/printcap, and if not specified as an + absolute path, is relative to the spooling directory. + + LPD starts lpf with page width and length + arguments (from the pw and pl + capabilities). lpf uses these arguments to + determine how much paper will be used. After sending the file to + the printer, it then writes an accounting entry in the accounting + file. The entries look like this: + + +2.00 rose:andy +3.00 rose:kelly +3.00 orchid:mary +5.00 orchid:mary +2.00 orchid:zhang + + You should use a separate accounting file for each printer, as + lpf has no file locking logic built into it, and + two lpfs 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 + af=acct in /etc/printcap. + Then, each accounting file will be in the spooling directory for a + printer, in a file named acct. + + When you are ready to charge users for printouts, run the + &man.pac.8; program. Just change to the spooling directory for + the printer you want to collect on and type pac. + You will get a dollar-centric summary like the following: + + 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 + + These are the arguments &man.pac.8; expects: + + + + + + + Which printer to summarize. + This option works only if there is an absolute path in the + af capability in + /etc/printcap. + + + + + + + + Sort the output by cost instead of alphabetically by user + name. + + + + + + + + Ignore host name in the accounting files. With this + option, user smith on host + alpha is the same user + smith on host gamma. + Without, they are different users. + + + + + + + + Compute charges with price + dollars per page or per foot instead of the price from the + pc capability in + /etc/printcap, or two cents (the + default). You can specify price as + a floating point number. + + + + + + + + Reverse the sort order. + + + + + + + + Make an accounting summary file and truncate the + accounting file. + + + + + name + + + + Print accounting information for the given user + names only. + + + + + In the default summary that &man.pac.8; 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 pac -m, to produce the following + summary: + + 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 + + + To compute the dollar amount due, + &man.pac.8; uses the pc capability in the + /etc/printcap 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 &man.pac.8; with the + option. The units for the + option are in dollars, though, not hundredths of cents. For + example, + + &prompt.root; pac -p1.50 + + makes each page cost one dollar and fifty cents. You can really + rake in the profits by using this option. + + Finally, running pac -s will save the summary + information in a summary accounting file, which is named the same as + the printer's accounting file, but with _sum + appended to the name. It then truncates the accounting file. When + you run &man.pac.8; again, it rereads the + summary file to get starting totals, then adds information from the + regular accounting file. + + + + How Can You Count Pages Printed? + + In order to perform even remotely accurate accounting, you need + to be able to determine how much paper a job uses. This is the + essential problem of printer accounting. + + For plain text jobs, the problem's not that hard to solve: you + count how many lines are in a job and compare it to how many lines + per page your printer supports. 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. + + The text filter lpf (introduced in 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 lpf's source code. + + How do you handle other file formats, though? + + Well, for DVI-to-LaserJet or DVI-to-PostScript conversion, you + can have your filter parse the diagnostic output of + dvilj or dvips and look to see + how many pages were converted. You might be able to do similar + things with other file formats and conversion programs. + + But these methods suffer from the fact that the printer may not + actually print all those pages. For example, it could jam, run out + of toner, or explode—and the user would still get + charged. + + So, what can you do? + + There is only one sure way to do + accurate accounting. Get a printer that can + tell you how much paper it uses, and attach it via a serial line or + a network connection. Nearly all PostScript printers support this + notion. Other makes and models do as well (networked Imagen laser + printers, for example). Modify the filters for these printers to + get the page usage after they print each job and have them log + accounting information based on that value + only. There is no line counting nor + error-prone file examination required. + + Of course, you can always be generous and make all printouts + free. + + + + Using Printers @@ -2243,2289 +4262,6 @@ cfA013rose dequeued - - Advanced Printer Setup - - This section describes filters for printing specially formatted - files, header pages, printing across networks, and restricting and - accounting for printer usage. - - - Filters - - Although LPD handles network protocols, queuing, access control, - and other aspects of printing, most of the real - work happens in the filters. Filters are - programs that communicate with the printer and handle its device - dependencies and special requirements. In the simple printer setup, - we installed a plain text filter—an extremely simple one that - should work with most printers (section Installing the Text - Filter). - - However, in order to take advantage of format conversion, printer - accounting, specific printer quirks, and so on, you should understand - how filters work. It will ultimately be the filter's responsibility - to handle these aspects. And the bad news is that most of the time - you have to provide filters yourself. The good - news is that many are generally available; when they are not, they are - usually easy to write. - - Also, FreeBSD comes with one, - /usr/libexec/lpr/lpf, that works with many - printers that can print plain text. (It handles backspacing and tabs - in the file, and does accounting, but that is about all it does.) - There are also several filters and filter components in the FreeBSD - ports collection. - - Here is what you will find in this section: - - - - Section 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. - - - - 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 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. - - - - PostScript is a popular output format for many programs. Even - some people (myself included) write PostScript code directly. But - PostScript printers are expensive. Section 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 - non-PostScript printer. I recommend reading - this section if you do not have a PostScript printer. - - - - Section 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 lpr -t to print troff data, or - lpr -d to print TeX DVI data, or lpr - -v to print raster image data, and so forth. I - recommend reading this section. - - - - Section Output - Filters tells all about a not often used feature of LPD: - output filters. Unless you are printing header pages (see Header Pages), - you can probably skip that section altogether. - - - - Section lpf: a Text - Filter describes lpf, a fairly - complete if simple text filter for line printers (and laser - printers that act like line printers) that comes with FreeBSD. If - you need a quick way to get printer accounting working for plain - text, or if you have a printer which emits smoke when it sees - backspace characters, you should definitely consider - lpf. - - - - - How Filters Work - - As mentioned before, a filter is an executable program started - by LPD to handle the device-dependent part of communicating with the - printer. - - When LPD wants to print a file in a job, it starts a filter - program. It sets the filter's standard input to the file to print, - its standard output to the printer, and its standard error to the - error logging file (specified in the lf - capability in /etc/printcap, or - /dev/console by default). - - Which filter LPD starts and the filter's arguments depend on - what is listed in the /etc/printcap file and - what arguments the user specified for the job on the - &man.lpr.1; command line. For example, if the user typed - lpr -t, LPD would start the troff filter, listed - in the tf capability for the destination printer. - If the user wanted to print plain text, it would start the - if filter (this is mostly true: see Output Filters for - details). - - There are three kinds of filters you can specify in - /etc/printcap: - - - - The text filter, confusingly called the - input filter in LPD documentation, handles - regular text printing. Think of it as the default filter. LPD - expects every printer to be able to print plain text by default, - and it 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: - - - filter-name - -c - -wwidth - -llength - -iindent - -n login - -h host - acct-file - - - where - - - - - - - appears if the job's submitted with lpr - -l - - - - - width - - - is the value from the pw (page - width) capability specified in - /etc/printcap, default 132 - - - - - length - - - is the value from the pl (page - length) capability, default 66 - - - - - indent - - - is the amount of the indentation from lpr - -i, default 0 - - - - - login - - - is the account name of the user printing the - file - - - - - host - - - is the host name from which the job was - submitted - - - - - acct-file - - - is the name of the accounting file from the - af capability. - - - - - - - - A conversion filter 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 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: - - - filter-name - -xpixel-width - -ypixel-height - -n login - -h host - acct-file - - - where pixel-width is the value - from the px capability (default 0) and - pixel-height is the value from the - py capability (default 0). - - - - The output filter is used only if there - is no text filter, or if header pages are enabled. In my - experience, output filters are rarely used. Section Output Filters describe - them. There are only two arguments to an output filter: - - - filter-name - -wwidth - -llength - - - which are identical to the text filters and - arguments. - - - - Filters should also exit with the - following exit status: - - - - exit 0 - - - If the filter printed the file successfully. - - - - - exit 1 - - - If the filter failed to print the file but wants LPD to - try to print the file again. LPD will restart a filter if it - exits with this status. - - - - - exit 2 - - - If the filter failed to print the file and does not want - LPD to try again. LPD will throw out the file. - - - - - The text filter that comes with the FreeBSD release, - /usr/libexec/lpr/lpf, takes advantage of the - page width and length arguments to determine when to send a form - feed and how to account for printer usage. It uses the login, host, - and accounting file arguments to make the accounting entries. - - If you 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. - - - - Accommodating Plain Text Jobs on PostScript Printers - - 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. - - 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 - %! (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. - - How do we do this? - - If you have got a serial printer, a great way to do it is to - install lprps. lprps is a - PostScript printer filter which performs two-way communication with - the printer. It updates the printer's status file with verbose - information from the printer, so users and administrators can see - exactly what the state of the printer is (such as toner - low or paper jam). But more - importantly, it includes a program called psif - which detects whether the incoming job is plain text and calls - textps (another program that comes with - lprps) to convert it to PostScript. It then uses - lprps to send the job to the printer. - - lprps is part of the FreeBSD ports collection - (see The Ports Collection). You can - fetch, build and install it yourself, of course. After installing - lprps, just specify the pathname to the - psif program that is part of - lprps. If you installed lprps - from the ports collection, use the following in the serial - PostScript printer's entry in - /etc/printcap: - - -:if=/usr/local/libexec/psif: - - You should also specify the rw capability; - that tells LPD to open the printer in read-write mode. - - If you have a parallel PostScript printer (and therefore cannot - use two-way communication with the printer, which - lprps needs), you can use the following shell - script as the text filter: - - -#!/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 - - In the above script, textps is a program we - installed separately to convert plain text to PostScript. You can - use any text-to-PostScript program you wish. The FreeBSD ports - collection (see The Ports Collection) - includes a full featured text-to-PostScript program called - a2ps that you might want to investigate. - - - - Simulating PostScript on Non-PostScript Printers - - PostScript is the de facto standard for - high quality typesetting and printing. PostScript is, however, an - expensive standard. Thankfully, Alladin - Enterprises has a free PostScript work-alike called - Ghostscript that runs with FreeBSD. - Ghostscript can read most PostScript files and can render their - pages onto a variety of devices, including many brands of - non-PostScript printers. By installing Ghostscript and using a - special text filter for your printer, you can make your - non-PostScript printer act like a real PostScript printer. - - Ghostscript should be in the FreeBSD ports collection, if you - would like to install it from there. You can fetch, build, and - install it quite easily yourself, as well. - - To simulate PostScript, we have the text filter detect if it 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. - - Here is an example: the following script is a text filter - for Hewlett Packard DeskJet 500 printers. For other printers, - substitute the argument to the - gs (Ghostscript) command. (Type gs - -h to get a list of devices the current installation of - Ghostscript supports.) - - -#!/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. - # - # Note that PostScript files are actually interpreted programs, - # and those programs are allowed to write to stdout, which will - # mess up the printed output. So, we redirect stdout to stderr - # and then make descriptor 3 go to stdout, and have Ghostscript - # write its output there. Exercise for the clever reader: - # capture the stderr output from Ghostscript and mail it back to - # the user originating the print job. - # - exec 3>&1 1>&2 - /usr/local/bin/gs -dSAFER -dNOPAUSE -q -sDEVICE=djet500 \ - -sOutputFile=/dev/fd/3 - && exit 0 - - # - /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 "\033&l0H" && exit 0 -fi - -exit 2 - - Finally, you need to notify LPD of the filter via the - if capability: - - -:if=/usr/local/libexec/hpif: - - That is it. You can type lpr plain.text and - lpr whatever.ps and both should print - successfully. - - - - Conversion Filters - - After completing the simple setup described in 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). - - - Why Install Conversion Filters? - - 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: - - &prompt.user; dvips seaweed-analysis.dvi -&prompt.user; lpr seaweed-analysis.ps - - 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: - - &prompt.user; lpr -d seaweed-analysis.dvi - - We got LPD to do the DVI file conversion for us by specifying - the option. Section Formatting and Conversion - Options lists the conversion options. - - For each of the conversion options you want a printer to - support, install a conversion filter and - specify its pathname in /etc/printcap. A - conversion filter is like the text filter for the simple printer - setup (see section Installing - the Text Filter) except that instead of printing plain - text, the filter converts the file into a format the printer can - understand. - - - - Which Conversions Filters Should I Install? - - 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. - - The following table summarizes the filters that LPD works - with, their capability entries for the - /etc/printcap file, and how to invoke them - with the lpr command: - - - - - - File type - /etc/printcap capability - lpr option - - - - - - cifplot - cf - - - - - DVI - df - - - - - plot - gf - - - - - ditroff - nf - - - - - FORTRAN text - rf - - - - - troff - rf - - - - - raster - vf - - - - - plain text - if - none, , or - - - - - - - In our example, using lpr -d means the - printer needs a df capability in its entry in - /etc/printcap. - - Despite what others might contend, formats like FORTRAN text - and plot are probably obsolete. At your site, you can give new - meanings to these or any of the formatting options just by - installing custom filters. For example, suppose you 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 - gf capability and then educate your users that - lpr -g mean “print Printerleaf - files.” - - - - Installing Conversion Filters - - Since conversion filters are programs you install outside of - the base FreeBSD installation, they should probably go under - /usr/local. The directory - /usr/local/libexec is a popular location, - since they are specialized programs that only LPD will run; - regular users should not ever need to run them. - - To enable a conversion filter, specify its pathname under the - appropriate capability for the destination printer in - /etc/printcap. - - In our example, we will add the DVI conversion filter to the - entry for the printer named bamboo. Here is - the example /etc/printcap file again, with - the new df capability for the printer - bamboo. - - -# -# /etc/printcap for host rose - added df filter for bamboo -# -rattan|line|diablo|lp|Diablo 630 Line Printer:\ - :sh:sd=/var/spool/lpd/rattan:\ - :lp=/dev/lpt0:\ - :if=/usr/local/libexec/if-simple: - -bamboo|ps|PS|S|panasonic|Panasonic KX-P4455 PostScript v51.4:\ - :sh:sd=/var/spool/lpd/bamboo:\ - :lp=/dev/ttyd5:fs#0x82000e1:xs#0x820:rw:\ - :if=/usr/local/libexec/psif:\ - :df=/usr/local/libexec/psdf: - - The DVI filter is a shell script named - /usr/local/libexec/psdf. Here is that - script: - - -#!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 "$@" - - This script runs dvips in filter mode (the - argument) on standard input, which is the job - to print. It then starts the PostScript printer filter - lprps (see section Accommodating Plain - Text Jobs on PostScript Printers) with the arguments LPD - passed to this script. lprps will use those - arguments to account for the pages printed. - - - - More Conversion Filter Examples - - 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. - - This example script is a raster (well, GIF file, actually) - conversion filter for a Hewlett Packard LaserJet III-Si - printer: - - -#!/bin/sh -# -# hpvf - Convert GIF files into HP/PCL, then print -# Installed in /usr/local/libexec/hpvf - -PATH=/usr/X11R6/bin:$PATH; export PATH -giftopnm | ppmtopgm | pgmtopbm | pbmtolj -resolution 300 \ - && exit 0 \ - || exit 2 - - It works by converting the GIF file into a portable anymap, - converting that into a portable graymap, converting that into a - portable bitmap, and converting that into LaserJet/PCL-compatible - data. - - Here is the /etc/printcap file with an - entry for a printer using the above filter: - - -# -# /etc/printcap for host orchid -# -teak|hp|laserjet|Hewlett Packard LaserJet 3Si:\ - :lp=/dev/lpt0:sh:sd=/var/spool/lpd/teak:mx#0:\ - :if=/usr/local/libexec/hpif:\ - :vf=/usr/local/libexec/hpvf: - - The following script is a conversion filter for troff data - from the groff typesetting system for the PostScript printer named - bamboo: - - -#!/bin/sh -# -# pstf - Convert groff's troff data into PS, then print. -# Installed in /usr/local/libexec/pstf -# -exec grops | /usr/local/libexec/lprps "$@" - - The above script makes use of lprps again - to handle the communication with the printer. If the printer were - on a parallel port, we would use this script instead: - - -#!/bin/sh -# -# pstf - Convert groff's troff data into PS, then print. -# Installed in /usr/local/libexec/pstf -# -exec grops - - That is it. Here is the entry we need to add to - /etc/printcap to enable the filter: - - -:tf=/usr/local/libexec/pstf: - - 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 - teak: - - -#!/bin/sh -# -# hprf - FORTRAN text filter for LaserJet 3si: -# Installed in /usr/local/libexec/hprf -# - -printf "\033&k2G" && fpr && printf "\033&l0H" && exit 0 -exit 2 - - And we will add this line to the - /etc/printcap for the printer - teak to enable this filter: - - -:rf=/usr/local/libexec/hprf: - - Here is one final, somewhat complex example. We will add a - DVI filter to the LaserJet printer teak - introduced earlier. First, the easy part: updating - /etc/printcap with the location of the DVI - filter: - - -:df=/usr/local/libexec/hpdf: - - Now, for the hard part: making the filter. For that, we need - a DVI-to-LaserJet/PCL conversion program. The FreeBSD ports - collection (see The Ports Collection) - has one: dvi2xx is the name of the package. - Installing this package gives us the program we need, - dvilj2p, which converts DVI into LaserJet IIp, - LaserJet III, and LaserJet 2000 compatible codes. - - dvilj2p makes the filter - hpdf quite complex since - dvilj2p cannot read from standard input. It - wants to work with a filename. What is worse, the filename has to - end in .dvi so using - /dev/fd/0 for standard input is problematic. - We can get around that problem by linking (symbolically) a - temporary file name (one that ends in .dvi) - to /dev/fd/0, thereby forcing - dvilj2p to read from standard input. - - The only other fly in the ointment is the fact that we cannot - use /tmp for the temporary link. Symbolic - links are owned by user and group bin. The - filter runs as user daemon. And the - /tmp 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. - - Instead, the filter will make the symbolic link in the current - working directory, which is the spooling directory (specified by - the sd capability in - /etc/printcap). 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 - /tmp. - - Here, finally, is the filter: - - -#!/bin/sh -# -# hpdf - Print DVI data on HP/PCL printer -# Installed in /usr/local/libexec/hpdf - -PATH=/usr/local/bin:$PATH; export PATH - -# -# Define a function to clean up our temporary files. These exist -# in the current directory, which will be the spooling directory -# for the printer. -# -cleanup() { - rm -f hpdf$$.dvi -} - -# -# Define a function to handle fatal errors: print the given message -# and exit 2. Exiting with 2 tells LPD to 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 - - - - Automated Conversion: An Alternative To Conversion - Filters - - All these conversion filters accomplish a lot for your - printing environment, but at the cost forcing the user to specify - (on the &man.lpr.1; 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. - - 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 - file can be of help here. Of course, it will - be hard to determine the differences between - some file types—and, of course, you can - still provide conversion filters just for them. - - The FreeBSD ports collection has a text filter that performs - automatic conversion called apsfilter. It can - detect plain text, PostScript, and DVI files, run the proper - conversions, and print. - - - - - Output Filters - - 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: - - - - LPD starts an output filter once for the entire job instead - of once for each file in the job. - - - - LPD does not make any provision to identify the start or the - end of files within the job for the output filter. - - - - 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: - - - filter-name - -wwidth - -llength - - - Where width is from the - pw capability and - length is from the - pl capability for the printer in - question. - - - - 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 will not work. Use a text filter (also - known as an input filter); see section Installing the Text Filter. - Furthermore, an output filter is actually more - complex in that it has to examine the byte stream being - sent to it for special flag characters and must send signals to - itself on behalf of LPD. - - However, an output filter is necessary if - you want header pages and need to send escape sequences or other - initialization strings to be able to print the header page. (But it - is also futile 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.) - - 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 Header Pages) - only. LPD then expects the output filter to stop - itself by sending two bytes to the filter: ASCII 031 - followed by ASCII 001. When an output filter sees these two bytes - (031, 001), it should stop by sending SIGSTOP to itself. When LPD's - done running other filters, it will restart the output filter by - sending SIGCONT to it. - - If there is an output filter but no text - filter and LPD is working on a plain text job, LPD uses the output - filter to do the job. As stated before, the output filter will - print each file of the job in sequence with no intervening form - feeds or other paper advancement, and this is probably - not what you want. In almost all cases, you - need a text filter. - - The program lpf, 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 lpf. You - can also wrap lpf in a shell script to handle any - initialization codes the printer might require. - - - - <command>lpf</command>: a Text Filter - - The program /usr/libexec/lpr/lpf that comes - with FreeBSD binary distribution is a text filter (input filter) - that can indent output (job submitted with lpr - -i), allow literal characters to pass (job submitted - with lpr -l), adjust the printing position for - backspaces and tabs in the job, and account for pages printed. It - can also act like an output filter. - - lpf 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 - lpf. - - In order for lpf to do page accounting - correctly, it needs correct values filled in for the - pw and pl capabilities in the - /etc/printcap file. It uses these values to - determine how much text can fit on a page and how many pages were in - a user's job. For more information on printer accounting, see Accounting for Printer - Usage. - - - - - Header Pages - - If you have lots of users, all of them using - various printers, then you probably want to consider header - pages as a necessary evil. - - Header pages, also known as banner or - burst pages 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.) - - The LPD system can provide header pages automatically for your - printouts if 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 Header Pages on - PostScript Printers. - - - Enabling Header Pages - - In the Simple Printer - Setup, we turned off header pages by specifying - sh (meaning “suppress header”) in the - /etc/printcap file. To enable header pages for - a printer, just remove the sh capability. - - Sounds too easy, right? - - You are right. You might 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: - - -#!/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 - - Specify the path to the output filter in the - of capability. See Output Filters for more - information. - - Here is an example /etc/printcap file for - the printer teak that we introduced earlier; we - enabled header pages and added the above output filter: - - -# -# /etc/printcap for host orchid -# -teak|hp|laserjet|Hewlett Packard LaserJet 3Si:\ - :lp=/dev/lpt0:sd=/var/spool/lpd/teak:mx#0:\ - :if=/usr/local/libexec/hpif:\ - :vf=/usr/local/libexec/hpvf:\ - :of=/usr/local/libexec/hpof: - - Now, when users print jobs to teak, they get - a header page with each job. If users want to spend time searching - for their printouts, they can suppress header pages by submitting - the job with lpr -h; see Header Page Options for - more &man.lpr.1; options. - - - 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 ff - capability in /etc/printcap. - - - - - Controlling Header Pages - - By enabling header pages, LPD will produce a long - header, 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): - - - 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 - - LPD appends a form feed after this text so the job starts on a - new page (unless you have sf (suppress form - feeds) in the destination printer's entry in - /etc/printcap). - - If you prefer, LPD can make a short header; - specify sb (short banner) in the - /etc/printcap file. The header page will look - like this: - - -rose:kelly Job: outline Date: Sun Sep 17 11:07:51 1995 - - Also by default, LPD prints the header page first, then the job. - To reverse that, specify hl (header last) in - /etc/printcap. - - - - Accounting for Header Pages - - Using LPD's built-in header pages enforces a particular paradigm - when it comes to printer accounting: header pages must be - free of charge. - - Why? - - Because the output filter is the only external program that will - have control when the header page is printed that could do - accounting, and it is not provided with any user or - host 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 lpr -h. - They could still be charged for header pages they did not print. - Basically, lpr -h will be the preferred option of - environmentally-minded users, but you cannot offer any incentive to - use it. - - It is still not enough to have each of the - filters generate their own header pages (thereby being able to - charge for them). If users wanted the option of suppressing the - header pages with lpr -h, they will still get - them and be charged for them since LPD does not pass any knowledge - of the option to any of the filters. - - So, what are your options? - - You can: - - - - Accept LPD's paradigm and make header pages free. - - - - Install an alternative to LPD, such as LPRng or PLP. Section - Alternatives to the - Standard Spooler tells more about other spooling - software you can substitute for LPD. - - - - Write a smart 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 af capability), but if you have a - well-known accounting file, you can hard-code that into the - output filter. To facilitate the parsing step, use the - sh (short header) capability in - /etc/printcap. Then again, all that might - be too much trouble, and users will certainly appreciate the - more generous system administrator who makes header pages - free. - - - - - - Header Pages on PostScript Printers - - 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. - - 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 lpr - -h. - - 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: - - -#!/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 - - 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: - - -#!/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 - - 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 How Filters - Work). - - As we have mentioned before, the above scheme, though fairly - simple, disables the “suppress header page” option (the - option) to lpr. 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. - - To allow users to shut off header pages on a per-job basis, you - will need to use the trick introduced in section 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 lpr -h, 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. - - If you have a PostScript printer on a serial line, you can make - use of lprps, which comes with an output filter, - psof, which does the above. Note that - psof does not charge for header pages. - - - - - Networked Printing - - FreeBSD supports networked printing: sending jobs to remote - printers. Networked printing generally refers to two different - things: - - - - 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 Printers Installed on - Remote Hosts tells how to do this. - - - - 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: - - - - 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 Printers - Installed on Remote Hosts to set up such a - printer. - - - - 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 Printers with - Networked Data Stream Interfaces gives some - suggestions on installing such printers. - - - - - - - Printers Installed on Remote Hosts - - The LPD spooling system has built-in support for sending jobs to - other hosts also running LPD (or are compatible with LPD). This - feature enables you to install a printer on one host and make it - accessible from other hosts. It also works with printers that have - network interfaces that understand the LPD protocol. - - To enable this kind of remote printing, first install a printer - on one host, the printer host, using the simple - printer setup described in Simple - Printer Setup. Do any advanced setup in 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. Also ensure that the - local host has authorization to use the LPD - service in the remote host (see Restricting Jobs - from Remote Printers). - - If you are using a printer with a network interface that is - compatible with LPD, then the printer host in - the discussion below is the printer itself, and the - printer name is the name you configured for the - printer. See the documentation that accompanied your printer and/or - printer-network interface. - - - If you are using a Hewlett Packard Laserjet then the printer - name text will automatically perform the LF to - CRLF conversion for you, so you will not require the - hpif script. - - - Then, on the other hosts you want to have access to the printer, - make an entry in their /etc/printcap files with - the following: - - - - Name the entry anything you want. For simplicity, though, - you probably want to use the same name and aliases as on the - printer host. - - - - Leave the lp capability blank, explicitly - (:lp=:). - - - - Make a spooling directory and specify its location in the - sd capability. LPD will store jobs here - before they get sent to the printer host. - - - - Place the name of the printer host in the - rm capability. - - - - Place the printer name on the printer - host in the rp - capability. - - - - That is it. You do not need to list conversion filters, page - dimensions, or anything else in the - /etc/printcap file. - - Here is an example. The host rose has two - printers, bamboo and rattan. - We will enable users on the host orchid to print to those printers. - Here is the /etc/printcap file for - orchid (back from section Enabling Header - Pages). It already had the entry for the printer - teak; we have added entries for the two printers - on the host rose: - - -# -# /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: - - Then, we just need to make spooling directories on - orchid: - - &prompt.root; mkdir -p /var/spool/lpd/rattan /var/spool/lpd/bamboo -&prompt.root; chmod 770 /var/spool/lpd/rattan /var/spool/lpd/bamboo -&prompt.root; chown daemon.daemon /var/spool/lpd/rattan /var/spool/lpd/bamboo - - Now, users on orchid can print to - rattan and bamboo. If, for - example, a user on orchid typed - - &prompt.user; lpr -P bamboo -d sushi-review.dvi - - the LPD system on orchid would copy the job to the spooling - directory /var/spool/lpd/bamboo and note that - it was a DVI job. As soon as the host rose has room in its - bamboo spooling directory, the two LPDs would - transfer the file to rose. The file would wait in rose's queue - until it was finally printed. It would be converted from DVI to - PostScript (since bamboo is a PostScript printer) on rose. - - - - Printers with Networked Data Stream Interfaces - - 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 Printers Installed on - Remote Hosts. - - The format of the /etc/printcap 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. - - 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 - netprint takes all data on standard input and - sends it to a network-attached printer. We specify the hostname of - the printer as the first argument and the port number to which to - connect as the second argument to netprint. Note - that this supports one-way communication only (FreeBSD to printer); - many network printers support two-way communication, and you might - want to take advantage of that (to get printer status, perform - accounting, etc.). - - -#!/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; - - 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: - - -#!/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 - - - - - Restricting Printer Usage - - 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. - - - Restricting Multiple Copies - - The LPD system makes it easy for users to print multiple copies - of a file. Users can print jobs with lpr -#5 - (for example) and get five copies of each file in the job. Whether - this is a good thing is up to you. - - If you feel multiple copies cause unnecessary wear and tear on - your printers, you can disable the option to - &man.lpr.1; by adding the sc capability to the - /etc/printcap file. When users submit jobs - with the option, they will see: - - lpr: multiple copies are not allowed - - - Note that if you have set up access to a printer remotely (see - section Printers - Installed on Remote Hosts), you need the - sc capability on the remote - /etc/printcap files as well, or else users will - still be able to submit multiple-copy jobs by using another - host. - - Here is an example. This is the - /etc/printcap file for the host - rose. The printer rattan is - quite hearty, so we will allow multiple copies, but the laser - printer bamboo's a bit more delicate, so we will - disable multiple copies by adding the sc - capability: - - -# -# /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: - - Now, we also need to add the sc capability on - the host orchid's - /etc/printcap (and while we are at it, let us - disable multiple copies for the printer - teak): - - -# -# /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: - - By using the sc capability, we prevent the - use of lpr -#, but that still does not prevent - users from running &man.lpr.1; - multiple times, or from submitting the same file multiple times in - one job like this: - - &prompt.user; lpr forsale.sign forsale.sign forsale.sign forsale.sign forsale.sign - - There are many ways to prevent this abuse (including ignoring - it) which you are free to explore. - - - - Restricting Access To Printers - - You can control who can print to what printers by using the UNIX - group mechanism and the rg capability in - /etc/printcap. Just place the users you want - to have access to a printer in a certain group, and then name that - group in the rg capability. - - Users outside the group (including root) will be greeted with - - lpr: Not a member of the restricted group - - if they try to print to the controlled printer. - - As with the sc (suppress multiple copies) - capability, you need to specify rg on remote - hosts that also have access to your printers, if you feel it is - appropriate (see section Printers Installed on - Remote Hosts). - - For example, we will let anyone access the printer - rattan, but only those in group - artists can use bamboo. Here - is the familiar /etc/printcap for host - rose: - - -# -# /etc/printcap for host rose - restricted group for bamboo -# -rattan|line|diablo|lp|Diablo 630 Line Printer:\ - :sh:sd=/var/spool/lpd/rattan:\ - :lp=/dev/lpt0:\ - :if=/usr/local/libexec/if-simple: - -bamboo|ps|PS|S|panasonic|Panasonic KX-P4455 PostScript v51.4:\ - :sh:sd=/var/spool/lpd/bamboo:sc:rg=artists:\ - :lp=/dev/ttyd5:fs#0x82000e1:xs#0x820:rw:\ - :if=/usr/local/libexec/psif:\ - :df=/usr/local/libexec/psdf: - - Let us leave the other example - /etc/printcap file (for the host - orchid) alone. Of course, anyone on - orchid can print to bamboo. It - might be the case that we only allow certain logins on - orchid anyway, and want them to have access to the - printer. Or not. - - - There can be only one restricted group per printer. - - - - - Controlling Sizes of Jobs Submitted - - 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. - - LPD enables you to limit the maximum byte size a file in a job - can be with the mx 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; however, if no - mx capability is specified, then a default limit - of 1000 blocks will be used. - - - The limit applies to files in a job, and - not the total job size. - - - 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. - - Let us add limits to our example printers - rattan and bamboo. 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: - - -# -# /etc/printcap for host rose -# - -# -# No limit on job size: -# -rattan|line|diablo|lp|Diablo 630 Line Printer:\ - :sh:mx#0:sd=/var/spool/lpd/rattan:\ - :lp=/dev/lpt0:\ - :if=/usr/local/libexec/if-simple: - -# -# Limit of five megabytes: -# -bamboo|ps|PS|S|panasonic|Panasonic KX-P4455 PostScript v51.4:\ - :sh:sd=/var/spool/lpd/bamboo:sc:rg=artists:mx#5000:\ - :lp=/dev/ttyd5:fs#0x82000e1:xs#0x820:rw:\ - :if=/usr/local/libexec/psif:\ - :df=/usr/local/libexec/psdf: - - Again, the limits apply to the local users only. If you have - set up access to your printers remotely, remote users will not get - those limits. You will need to specify the mx - capability in the remote /etc/printcap files as - well. See section Printers Installed on - Remote Hosts for more information on remote - printing. - - There is another specialized way to limit job sizes from remote - printers; see section Restricting Jobs - from Remote Printers. - - - - Restricting Jobs from Remote Printers - - The LPD spooling system provides several ways to restrict print - jobs submitted from remote hosts: - - - - Host restrictions - - - You can control from which remote hosts a local LPD - accepts requests with the files - /etc/hosts.equiv and - /etc/hosts.lpd. LPD checks to see if an - incoming request is from a host listed in either one of these - files. If not, LPD refuses the request. - - The format of these files is simple: one host name per - line. Note that the file - /etc/hosts.equiv is also used by the - &man.ruserok.3; protocol, and affects programs like - &man.rsh.1; and &man.rcp.1;, so be careful. - - For example, here is the - /etc/hosts.lpd file on the host - rose: - - -orchid -violet -madrigal.fishbaum.de - - This means rose will accept requests from - the hosts orchid, violet, - and madrigal.fishbaum.de. If any - other host tries to access rose's LPD, LPD - will refuse them. - - - - - Size restrictions - - - You can control how much free space there needs to remain - on the filesystem where a spooling directory resides. Make a - file called minfree in the spooling - directory for the local printer. Insert in that file a number - representing how many disk blocks (512 bytes) of free space - there has to be for a remote job to be accepted. - - This lets you insure that remote users 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 - minfree file. - - For example, let us add a minfree - file for the printer bamboo. We examine - /etc/printcap to find the spooling - directory for this printer; here is bamboo's - entry: - - -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: - - The spooling directory is the given in the - sd 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: - - &prompt.root; echo 6144 > /var/spool/lpd/bamboo/minfree - - - - - User restrictions - - - You can control which remote users can print to local - printers by specifying the rs capability in - /etc/printcap. When - rs appears in the entry for a - locally-attached printer, LPD will accept jobs from remote - hosts if the user submitting the job also - has an account of the same login name on the local host. - Otherwise, LPD refuses the job. - - This capability is particularly useful in an environment - where there are (for example) different departments sharing a - network, and some users transcend departmental boundaries. By - giving them accounts on your systems, they can use your - printers from their own departmental systems. If you would - rather allow them to use only your - printers and not your compute resources, you can give them - “token” accounts, with no home directory and a - useless shell like /usr/bin/false. - - - - - - - - Accounting for Printer Usage - - 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? - - 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 - your requirements in charging for printer - usage. - - To implement accounting, you have to modify a printer's text - filter (to charge for plain text jobs) and the conversion filters (to - charge for other file formats), to count pages or query the printer - for pages printed. You cannot get away with using the simple output - filter, since it cannot do accounting. See section Filters. - - Generally, there are two ways to do accounting: - - - - Periodic accounting 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. - - - - Timely accounting 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. - - - - 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. - - - Quick and Dirty Printer Accounting - - FreeBSD comes with two programs that can get you set up with - simple periodic accounting right away. They are the text filter - lpf, described in section lpf: a Text Filter, and - &man.pac.8;, a program to gather and total - entries from printer accounting files. - - As mentioned in the section on filters (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 af capability in - /etc/printcap, and if not specified as an - absolute path, is relative to the spooling directory. - - LPD starts lpf with page width and length - arguments (from the pw and pl - capabilities). lpf uses these arguments to - determine how much paper will be used. After sending the file to - the printer, it then writes an accounting entry in the accounting - file. The entries look like this: - - -2.00 rose:andy -3.00 rose:kelly -3.00 orchid:mary -5.00 orchid:mary -2.00 orchid:zhang - - You should use a separate accounting file for each printer, as - lpf has no file locking logic built into it, and - two lpfs 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 - af=acct in /etc/printcap. - Then, each accounting file will be in the spooling directory for a - printer, in a file named acct. - - When you are ready to charge users for printouts, run the - &man.pac.8; program. Just change to the spooling directory for - the printer you want to collect on and type pac. - You will get a dollar-centric summary like the following: - - 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 - - These are the arguments &man.pac.8; expects: - - - - - - - Which printer to summarize. - This option works only if there is an absolute path in the - af capability in - /etc/printcap. - - - - - - - - Sort the output by cost instead of alphabetically by user - name. - - - - - - - - Ignore host name in the accounting files. With this - option, user smith on host - alpha is the same user - smith on host gamma. - Without, they are different users. - - - - - - - - Compute charges with price - dollars per page or per foot instead of the price from the - pc capability in - /etc/printcap, or two cents (the - default). You can specify price as - a floating point number. - - - - - - - - Reverse the sort order. - - - - - - - - Make an accounting summary file and truncate the - accounting file. - - - - - name - - - - Print accounting information for the given user - names only. - - - - - In the default summary that &man.pac.8; 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 pac -m, to produce the following - summary: - - 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 - - - To compute the dollar amount due, - &man.pac.8; uses the pc capability in the - /etc/printcap 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 &man.pac.8; with the - option. The units for the - option are in dollars, though, not hundredths of cents. For - example, - - &prompt.root; pac -p1.50 - - makes each page cost one dollar and fifty cents. You can really - rake in the profits by using this option. - - Finally, running pac -s will save the summary - information in a summary accounting file, which is named the same as - the printer's accounting file, but with _sum - appended to the name. It then truncates the accounting file. When - you run &man.pac.8; again, it rereads the - summary file to get starting totals, then adds information from the - regular accounting file. - - - - How Can You Count Pages Printed? - - In order to perform even remotely accurate accounting, you need - to be able to determine how much paper a job uses. This is the - essential problem of printer accounting. - - For plain text jobs, the problem's not that hard to solve: you - count how many lines are in a job and compare it to how many lines - per page your printer supports. 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. - - The text filter lpf (introduced in 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 lpf's source code. - - How do you handle other file formats, though? - - Well, for DVI-to-LaserJet or DVI-to-PostScript conversion, you - can have your filter parse the diagnostic output of - dvilj or dvips and look to see - how many pages were converted. You might be able to do similar - things with other file formats and conversion programs. - - But these methods suffer from the fact that the printer may not - actually print all those pages. For example, it could jam, run out - of toner, or explode—and the user would still get - charged. - - So, what can you do? - - There is only one sure way to do - accurate accounting. Get a printer that can - tell you how much paper it uses, and attach it via a serial line or - a network connection. Nearly all PostScript printers support this - notion. Other makes and models do as well (networked Imagen laser - printers, for example). Modify the filters for these printers to - get the page usage after they print each job and have them log - accounting information based on that value - only. There is no line counting nor - error-prone file examination required. - - Of course, you can always be generous and make all printouts - free. - - - - Alternatives to the Standard Spooler @@ -4597,61 +4333,297 @@ total 337.00 154 $ 6.74 - - - Acknowledgments - - I would like to thank the following people who have assisted in the - development of this document: + + + Troubleshooting + + After performing the simple test with &man.lptest.1;, you might + have gotten one of the following results instead of the correct + printout: - Daniel Eischen - deischen@iworks.interworks.org + It worked, after awhile; or, it did not eject a full + sheet. - For providing a plethora of HP filter programs for - perusal. - - - - - &a.jehamby; + 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. - - For the Ghostscript-to-HP filter. + 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. + + The following replacement for the shell script + /usr/local/libexec/if-simple prints a + form feed after it sends the job to the printer: + + +#!/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 - &a.jfieber; + It produced the “staircase effect.” - For debugging why printing from Windows 95 to a FreeBSD - system simulating a PostScript printer with Ghostscript didn't - produce correct output, and suggesting a fix, which is included - herein. + You got the following on paper: + + +!"#$%&'()*+,-./01234 + "#$%&'()*+,-./012345 + #$%&'()*+,-./0123456 + + You have become another victim of the staircase + effect, caused by conflicting interpretations of + what characters should indicate a new line. UNIX-style + operating systems use a single character: ASCII code 10, the + line feed (LF). MS-DOS, OS/2, and others uses a pair of + characters, ASCII code 10 and ASCII code + 13 (the carriage return or CR). Many printers use the MS-DOS + convention for representing new-lines. + + When you print with FreeBSD, your text used just the line + feed character. The printer, upon seeing a line feed + character, advanced the paper one line, but maintained the + same horizontal position on the page for the next character + to print. That is what the carriage return is for: to move + the location of the next character to print to the left edge + of the paper. + + Here is what FreeBSD wants your printer to do: + + + + + + Printer received CR + Printer prints CR + + + + Printer received LF + Printer prints CR + LF + + + + + + Here are some ways to achieve this: + + + + 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. + + + If you boot your system into other operating systems + besides FreeBSD, you may have to + reconfigure the printer to use a an + interpretation for CR and LF characters that those other + operating systems use. You might prefer one of the other + solutions, below. + + + + + Have FreeBSD's serial line driver automatically + convert LF to CR+LF. Of course, this works with printers + on serial ports only. To enable this + feature, set the CRMOD bit in fs + capability in the /etc/printcap file + for the printer. + + + + Send an escape code to the + printer to have it temporarily treat LF characters + differently. Consult your printer's manual for escape + codes that your printer might support. When you find the + proper escape code, modify the text filter to send the + code first, then send the print job. + + 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. + + +#!/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. Ejects the page when done. + +printf "\033&k2G" && cat && printf "\033&l0H" && exit 0 +exit 2 + + Here is an example /etc/printcap + from a host called orchid. It has a single printer + attached to its first parallel port, a Hewlett Packard + LaserJet 3Si named teak. It is using the + above script as its text filter: + + +# +# /etc/printcap for host orchid +# +teak|hp|laserjet|Hewlett Packard LaserJet 3Si:\ + :lp=/dev/lpt0:sh:sd=/var/spool/lpd/teak:mx#0:\ + :if=/usr/local/libexec/hpif: + + - Stephen Montgomery-Smith - stephen@math.missouri.edu + It overprinted each line. - For suggesting using "\033&l0H" instead of "\f" to eject - the last page on HP printers; the latter could eject an extra - blank page while the former never does. + The printer never advanced a line. All of the lines of + text were printed on top of each other on one line. + + This problem is the “opposite” of the + staircase effect, described above, and is much rarer. + Somewhere, the LF characters that FreeBSD uses to end a line + are being treated as CR characters to return the print + location to the left edge of the paper, but not also down a + line. + + Use the printer's configuration switches or control panel + to enforce the following interpretation of LF and CR + characters: + + + + + + Printer receives + Printer prints + + + + + + CR + CR + + + + LF + CR + LF + + + + - + - My wife, Mary Kelly - urquhart@argyre.colorado.edu + The printer lost characters. - For allowing me to spend more time with FreeBSD than - with her. + 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. + + 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: + + + + If the printer supports XON/XOFF flow control, have + FreeBSD use it by specifying the TANDEM bit in the + fs capability. + + + + If the printer supports carrier flow control, specify + the MDMBUF bit in the fs capability. + Make sure the cable connecting the printer to the computer + is correctly wired for carrier flow control. + + + + If the printer does not support any flow control, use + some combination of the NLDELAY, TBDELAY, CRDELAY, VTDELAY, + and BSDELAY bits in the fs capability + to add appropriate delays to the stream of data sent to + the printer. + + + + + + + It printed garbage. + + + The printer printed what appeared to be random garbage, + but not the desired text. + + This is usually another symptom of incorrect + communications parameters with a serial printer. Double-check + the bps rate in the br capability, and the + parity bits in the fs and + fc capabilities; make sure the printer is + using the same settings as specified in the + /etc/printcap file. + + + + + Nothing happened. + + + If nothing happened, the problem is probably within + FreeBSD and not the hardware. Add the log file + (lf) capability to the entry for the + printer you are debugging in the + /etc/printcap file. For example, here is + the entry for rattan, with the + lf capability: + + +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 + + Then, try printing again. Check the log file (in our + example, /var/log/rattan.log) to see any + error messages that might appear. Based on the messages you + see, try to correct the problem. + + If you do not specify a lf capability, + LPD uses /dev/console as a + default.