|
|
|
|
Network PrintingBy Matthew Gast & Todd RadermacherOctober 2000 0-596-00038-3, Order Number: 0383 312 pages, $34.95 |
Chapter 5
In this chapter:
The Next Generation Berkeley Spooler: LPRng
Compiling and Installing LPRng
Configuring LPRng
More Fun with Filters
AccountingIn spite of our great fondness for the Berkeley spooler, we must admit that its age clearly shows--the stock Berkeley spooler has been in use longer than many of its users have been working with computers. Recent developments have led to one potential successor: LPRng. LPRng began life as a PLP, a reimplementation of the Berkeley spooler free of the AT&T Unix license. In the early 1990s at San Diego State University in California, Patrick Powell redesigned and rewrote the PLP code base to build a print server package that could stand up to the rigors of an academic environment.[1] Due to the number of changes that were made, the package was renamed LPRng in honor of its venerable ancestor.
LPRng supports the LPD protocol as described in RFC 1179, but adds several nifty features. System V command emulation enables system administrators to replace System V spoolers with Berkeley spoolers while retaining compatibility with System V print commands. Several configuration file options make it easier to manage large sites or improve scalability.
Perhaps the main strength of LPRng, though, is that it can be used to provide a unified interface to the print spooler on several different operating systems. For administrators who are more familiar with the Berkeley spooler, it offers the opportunity to replace System V spoolers with Berkeley spoolers, but such an ambitious project should not be taken lightly.
Compiling and Installing LPRng
The first step in using any software package distributed in source form is compilation and installation. Several modern Linux distributions have, however, adopted LPRng as the standard print spooler.
Compiling Your Own Binaries
On other operating systems, especially those descended from System V, building from source is required. LPRng is freely available in source form under the GNU General Public License from ftp://ftp.astart.com/pub/LPRng. The latest stable distribution will be stored as LPRng-stable.tgz. Documentation is distributed from the same site in the file LPRng_DOC-latest.tgz. As this chapter was written, the latest version of LPRng was 3.6.12.[2]
Unpacking the source
The source is distributed as a compressed tar file. Uncompress and unpack it with tar and gzip, as shown here:
bastet:~/lprng$ gunzip LPRng-stable.tgzbastet:~/lprng$ tar -xf LPRng-stable.tarLPRng-3.6.12/LPRng-3.6.12/src/. . .etc. . .Configuring for your system
One of our favorite trends in free software for Unix systems is the use of the GNU autoconfiguration package. Software developers include a script that runs many small test programs to determine what library calls are available and where other software is installed. GNU autoconf reduces configuration to running the . /configure script in the top-level source directory. You will see a large number of tests. Here is the start of the procedure on a Sun running Solaris 7:
bastet:~/lprng$ cd LPRng-3.6.12bastet:~/lprng/LPRng-3.6.12$ ./configurecreating cache ./config.cachechecking host system type... sparc-sun-solaris2.7checking target system type... sparc-sun-solaris2.7checking build system type... sparc-sun-solaris2.7checking for mawk... nochecking for gawk... nochecking for nawk... nawkchecking for perl... /usr/bin/perl. . . other tests skipped . . .By default, LPRng will be installed in /usr/local, but the target can be set by supplying the -bindir option to the configure script, or by editing the Makefile after running the configure script.
Compiling the code
The next step is to run make to build the software. Minor confusion exists because GNU make and Berkeley make are slightly different.
With GNU make, run make clean all. For BSD make, specify the BSD Makefile instead by using the -f option on the command line: make -f Makefile.bsd clean all. Here is the beginning of the procedure for Solaris 7:[3]
bastet:~/lprng/LPRng-3.6.12$ gmake clean allgmake MAKETARGET=clean src man pogmake[1]: Entering directory `/export/home/gast/LPRng-3.6.12'gmake -C src cleangmake[2]: Entering directory `/export/home/gast/LPRng-3.6.12/src'rm -f *.o *.core *.a ? core lpc lpd lpq lpr lprm lpf lpraccnt pclbanner psbanner checkpc lp lpstat lpbanner monitor ../lpd.conf
sserver sclientgmake[2]: Leaving directory `/export/home/gast/LPRng-3.6.12/src'gmake -C man cleangmake[2]: Entering directory `/export/home/gast/LPRng-3.6.12/man'gmake[2]: Nothing to be done for `clean'.gmake[2]: Leaving directory `/export/home/gast/LPRng-3.6.12/man'gmake -C po cleangmake[2]: Entering directory `/export/home/gast/LPRng-3.6.12/po'gmake[2]: Nothing to be done for `clean'.gmake[2]: Leaving directory `/export/home/gast/LPRng-3.6.12/po'gmake[1]: Leaving directory `/export/home/gast/LPRng-3.6.12'gmake -C src allgmake[1]: Entering directory `/export/home/gast/LPRng-3.6.12/src'gcc -g -O2 -g -Wall -DHAVE_CONFIG_H -DLOCALEDIR=\"/usr/local/share/locale\" -DLPD_CONF_PATH=\"/usr/local/
etc/lpd.conf\" -DLPD_PERMS_PATH=\"/usr/local/etc/lpd.perms\" -DPRINTCAP_PATH=\"/usr/local/etc/printcap\" -DLPD_
PRINTCAP_PATH=\"/usr/local/etc/lpd_printcap\" -DFORCE_LOCALHOST=\"1\" -DREQUIRE_CONFIGFILES=\"1\" -I..
-I./include -c -o lpc.o ./common/lpc.c. . . lots of other stuff skipped. . .Installation
As root, run make again to install the binaries to the location specified in the Makefile. If your system uses a BSD derived version of make, use Makefile.bsd :
bastet:~/lprng/LPRng-3.6.12$ su -Password:Sun Microsystems Inc. SunOS 5.7 Generic October 1998# gmake installgmake MAKETARGET=install src man pogmake[1]: Entering directory `/export/home/gast/LPRng-3.6.12'gmake -C src installgmake[2]: Entering directory `/export/home/gast/LPRng-3.6.12/src'echo "SETUID_ROOT IS SUID_ROOT_PERMS, PERMS 04755 -o root";SETUID_ROOT IS SUID_ROOT_PERMS, PERMS 04755 -o rootfor i in /usr/local/bin /usr/local/sbin /usr/local/sbin /usr/local/libexec/filters; do \if [ ! -d $i ] ; then ./mkinstalldirs $i ; fi; \done;mkdir /usr/local/sbinmkdir /usr/local/libexec/filters.././install-sh -c -s -m 04755 -o root lpq /usr/local/bin.././install-sh -c -s -m 04755 -o root lprm /usr/local/bin.././install-sh -c -s -m 04755 -o root lpr /usr/local/bin.././install-sh -c -s -m 04755 -o root lpstat /usr/local/bin.././install-sh -c -s -m 04755 -o root lpc /usr/local/sbin. . . more skipped . . .Installation ends with the installation of skeleton lpd.perms and lpd.conf files in /usr/local/etc.
Replacing the Existing Spooler
When replacing an existing spooler, begin by removing your old spooler software.
Kill the old daemon
The spooler daemon on BSD systems is lpd:
# kill `ps -aux | grep lpd | grep -v grep | awk '{print $2}'`System V uses the lpsched daemon, and requires slightly different flags to ps:
# kill `ps -ef | grep lpsched | grep -v grep | awk '{print $2}'`Replace the vendor-provided printing programs with the LPRng programs
First, check your system's man pages to find the name of the programs that make up your print system. To search the disk for the lpr program, use the find command:
# find / -type file -name lpr -printAfter running the find command, rename the existing program lpr, and then link lpr to the LPRng lpr :
# mv /usr/bin/lpr /usr/bin/lpr.orig# ln -s /usr/local/bin/lpr /usr/bin/lprModify system startup scripts
System startup scripts launch the print spooler daemon on boot. On BSD systems, look for the command that starts lpd in /etc/rc and replace it with a line that runs the LPRng lpd instead. Alternatively, remove that line entirely and run the LPRng lpd in /etc/rc.local.
On System V, print services are frequently started at run level 3. Look for the script that starts lpsched and delete it (or at least rename it). You also need to track down and delete the S and K links to this script, which are probably in /etc/init.d/rc3.d. We'll replace this with a script that starts the LPRng lpd. The very basic script in Example 5-1 provides a jumping off point for further customization. For example, some administrators first check that the System V daemons are stopped before starting LPRng daemons.
Example 5-1: LPRng Startup Script for System V init #!/bin/shcase "$1" instart) echo "Starting lpd";/usr/local/sbin/lpd;;;stop) echo "Shutting down lpd";kill `ps -ef | grep lpd | grep -v grep | awk '{print $2}'`;;*) echo "Usage: lpd {start|stop}"exit 1;;esacAfter customizing the script, put it in /etc/init.d/lprng and create a link to the new LPRng startup script in /etc/init.d/rc3.d, such as /etc/init.d/rc3.d/S77lprng.[4]
Some System V based Unix flavors may also fire up a print daemon in /etc/inetd.conf. If a line such as the following exists in /etc/inetd.conf, remove it:[5]
printer stream tcp nowait root /usr/lib/print/in.lpd in.lpdReplace System V print services
If the LPRng programs are invoked with the System V name, they will act like the System V programs. Installing System V emulation allows system administrators to provide both BSD and System V interfaces to the printing system while only maintaining one software package.
If lpr is run as lp, it will use lp syntax. The same goes for lpq when run as lpstat, and for lprm when run as cancel. To enable System V emulation, make a set of symbolic links for the System V names, as shown in Example 5-2. (The LPRng installation will perform that step for you.) For completeness, create the System V names in the standard place, /usr/bin, as well as /usr/local/bin.
Example 5-2: Replacing System V Binary Names with LPRng Binaries # cd /usr/local/bin# ln -s lpr lp# ln -s lpq lpstat# ln -s lprm cancel# cd /usr/bin# mv lp lp.dist# ln -s /usr/local/bin/lp lp# mv lpstat lpstat.dist# ln -s /usr/local/bin/lpstat lpstat# mv cancel cancel.dist# ln -s /usr/local/bin/cancel cancelWhen replacing the System V binaries, update the documentation as well. Replace the vendor's lp, lpstat, and cancel man pages with the respective man pages from the LPRng distribution, as in Example 5-3.
Example 5-3: Replacing System V man Pages on Solaris 7 # cd /usr/share/man# cd man1# cp /usr/local/man/man1/lp.1 .# cp /usr/local/man/man1/lpstat.1 .# cp /usr/local/man/man1/cancel.1 .# cd ../cat1# mv lp.1 sysv-lp.1# mv lpstat.1 sysv-lpstat.1# mv cancel.1 sysv-cancel.1# cd ../sman1# mv lp.1 sysv-lp.1# mv lpstat.1 sysv-lpstat.1# mv cancel.1 sysv-cancel.1Solaris notes
On Solaris, remove /var/spool/cron/crontabs/lp to prevent it from running. To uninstall System V printing, run the commands in Example 5-4.
Example 5-4: Removing System V Spooling from Solaris 7 # /etc/init.d/lp stopPrint services stopped.# /usr/sbin/pkgrm -n SUNWpsuRemoval of <SUNWpsu> was successful.# /usr/sbin/pkgrm -n SUNWscplpRemoval of <SUNWscplp> was successful.# /usr/sbin/pkgrm -n SUNWpcuRemoval of <SUNWpcu> was successful.# /usr/sbin/pkgrm -n SUNWpsrRemoval of <SUNWpsr> was successful.# /usr/sbin/pkgrm -n SUNWpcrRemoval of <SUNWpcr> was successful.# /bin/rm -f /var/spool/cron/crontabs/lpOn Solaris, you must also create the /var/run directory for the LPRng lpd to store lock information.
Configuring LPRng
LPRng configuration is, for the most part, a superset of classic lpr configuration. LPRng uses standard printcap syntax extensively, but some of the additional options may be confusing at first.
Compatibility with the Berkeley Spooler
Configuration files used with the plain vanilla Berkeley spooler are almost completely compatible with LPRng. The only options from the stock Berkeley spooler software that cannot be used with LPRng are used for configuring serial ports for use with serial printers. Classic Berkeley printcap syntax uses the fc, fx, xc, and xs parameters to configure serial ports. These parameters describe a series of binary flags used to configure the serial-port. LPRng configures serial ports by using stty. In addition to being more friendly, stty is available on both System V and BSD, which allows the same printcap to be used with both System V and BSD. Conversion of BSD serial-port configurations to LPRng serial-port configurations is detailed in the LPRng documentation.
Much of the LPRng printcap syntax makes it incompatible with standard lpr syntax, though. LPRng does not require backslashes at the end of each printcap line to continue it onto the next line; it uses keywords that are sometimes more than two characters long; and it supports a variety of extended options that are not present on stock lpr. In our experience, there is no reason to go back to lpr after making use of some of the advanced options covered in the next few pages.
Printing Directly to Remote Printers
A major hassle with stock Berkeley LPR is that the lpr client program is dumb. It dimly follows orders, depositing jobs in spool directories and pestering lpd to do the hard part. Job routing is done by lpd, so any host providing or using print service must run lpd. Each host running lpd must be configured by providing an appropriate printcap.
LPRng's lpr is quite a bit smarter. It can send a job directly over a TCP connection to a remote lpd process, so there is no need to run lpd on every host, and no need to configure printcap files for every host. Eliminating printcap configuration for the print clients makes distributing printcap files much simpler because only servers need printcap files. LPRng lpr allows the user to specify the hostname and printer on the command line, as in the following examples:
$ lpr -Pprinter@server file$ lpr -Plaser@printhost words.txtSystem administrators can use the PRINTER environment variable to set defaults. For the simplest setup, assign a default value to the variable. More complex scripts could test the hostname and assign a default printer based on the hostname, IP address, or any other piece of system information.
LPRng allows a printcap file to use the printer@server extension as the
lpcapability, eliminating the need for the stock Berkeley LPRrpandrmcapabilities. Printing to a specified remote port is supported by using a%in thelpcapability. Because LPRng can print directly to a remote port, there is no need to fork a copy of netcat for the sole purpose of opening a TCP socket. Busy servers that handle lots of jobs may see substantial resource savings by using this option instead of forking netcat processes to achieve the same result. These extensions are illustrated here:# Classic Berkeley-styleremote-classic:\:rp=raw:rm=server:# LPRng extension identical to the aboveremote-lprng::lp=raw@server# Use % to go to a non-standard portremote-9100::lp=raw@server%9100In the previous examples, the LPRng lpr program will not need any help from lpd, so there is no need to run lpd on the client host.
Enhanced Banner Pages
In addition to the standard lpr attributes, LPRng adds some extended options for improved banner printing. As with lpr, the bl line describes the short banner line used for banner page generation. The default bl value is:
$-'C:$-'n Job: $-'J Date: $-'tWhen expanded by LPRng, a file named book.ps will be given the banner line:
gast:A Job: book.ps Date: Mon Sep 06 12:27:03 PST 1999To print a much more interesting banner, you can specify an external banner generation program in the LPRng printcap, which works like a filter. As input, the banner program takes the short banner line, as customized by bl,[6] and it will write its output to standard output, which goes directly to the printer, bypassing any filters. Because the output of the banner program is not filtered, it must generate output appropriate for the printer. Of course, if you prefer, you can specify the sb flag in printcap to only print the short banner.
External banner programs are specified with bp, bs, and be. bp specifies a specific banner program, while bs is used exclusively for start banners and be is used for ending banners. To print the banner at the end of a job, use the hl option as you would with lpr.
Filtering for Remote Queues: Bouncing a Job
One problem discussed in Chapter 4 is the difficulty of filtering a job before it is passed to a remote queue. Rather than use a double queuing strategy, LPRng allows the system administrator to run filters for remote printers without extra hassle.
Good: bounce queues
As explained previously, processing a job before forwarding it to a remote server requires two queues with the classic Berkeley software. Setting up two queues just to run a filter is something which would be good to eliminate. If you have a large number of queues, a typo in a printcap file or script may cause a large number of users to lose the ability to print.
LPRng introduced the bounce queue, which runs filters on the input and then sends the processed job to the bounce queue. To specify a bounce queue, use the
bqcapability. Jobs will first be processed by the queue in thelpcapability and filtered by the specified print filter. After filtering, the job will be sent to the queue specified bybq. In Example 5-5, the lj6 queue filters jobs locally and sends the results to the lp queue on the server named spooler. When using bounce queues, the host doing the processing must have a queue directory to hold temporary files, so thesdcapability must be set.
Example 5-5: Bounce Queue Configuration lj6::lp=lj6@localhost:bq=lp@spooler:sd=/var/spool/lpd/lj6:if=/usr/local/lib/filters/apsfilterBetter: bouncing with lpr
Configuring a queue in the style of Example 5-5 requires that lpd be run on the client host. Running lpd processes on every host that prints imposes administrative overhead that is not necessary with LPRng. The LPRng lpr program can apply the input filter before passing the job to a server if the lpr_bounce capability is specified in the printcap file, as in Example 5-6. If lpr_bounce is specified, no local spool directory or local lpd process is required.
Example 5-6: Bouncing with lpr lj6::lpr_bounce:lp=lp@spooler:if=/usr/local/lib/filters/apsfilterOmnibus printcap Files
Real administrative scalability comes from distributing one configuration widely. LPRng includes tools to allow a single printcap file to be distributed to many end hosts and parsed differently.
Separating client and server information
LPRng allows the printcap file to divide information into two classes: information for use by the lpd daemon, and information that is used by the LPRng clients, such as lpr. In the LPRng printcap file, the tag server indicates that the printcap entry is for use only by lpd and not by any of the clients. For example, the printcap file in Example 5-7 will result in the lpd server printing locally to /dev/lp0, while lpr will attempt to print to printer1 on printhost.
Example 5-7: Division of Client and Server Configuration with the server Tag printer1::lp=printer1@printhostprinter1::server:lp=/dev/lp0Sharing common attributes
If you have several printers with shared attributes, you can avoid extra typing by taking advantage of the tc tag, which allows you to define a common base configuration that can be further customized. Options specified in the tc sections will be overridden by any options in the printcap configuration. printcap entries starting with the period, underscore, or @ will be ignored by LPRng except for use by the tc tag. For example, if you would like to suppress the header page and remove the maximum job size limit for all printers, you can set up a common section with those commands and include them in other printcap definitions. Furthermore, you can specify multiple add-in sections with a single tc attribute. Example 5-8 also makes use of the LPRng extension %P, which is replaced by the name of the printer when the file is parsed.
Example 5-8: Sharing Common Attributes in the LPRng printcap .common::sh:mx=0:sd=/var/spool/lpd/%P.notsocommon:if=/usr/local/lib/filters/apsfilterprinter1::tc=.common:lp=/dev/lp0printer2::tc=.common,.notsocommon:lp=/dev/lp1When expanded by LPRng, the configuration file of Example 5-8 will be processed as if it were the configuration file shown in Example 5-9.
Example 5-9: After Processing printer1::sh:mx=0:sd=/var/spool/lpd/printer1:lp=/dev/lp0printer2::sh:mx=0:sd=/var/spool/lpd/printer2:if=/usr/local/lib/filters/apsfilter:lp=/dev/lp1Using entries on some hosts only
By using the oh option in the LPRng printcap, you can specify that a printcap entry is valid only on the hosts specified in the oh tag. If the host does not match the oh pattern, the entry will be ignored. The oh attribute can be set to an IP network, specified either by IP address and mask length (192.168.1.0/24 ) or by IP address and subnet mask (192.168.1.0/255.255.255.0 ). You may also use a wildcard pattern on the domain name (*.eng.fofz.com). Multiple specifications can be separated with commas.
One potential use of the oh option is to set the default printer based on the IP address or domain name of the client. In Example 5-10, the default printer for hardware engineering is plotter, while the default printer for the marketing department is psychedelic.
Example 5-10: Using the oh Tag to Set the Default Printer lp::oh=*.eng.fofz.com:lp=plotter@printers.fofz.comlp::oh=*.mkt.fofz.com:lp=psychedelic@printers.fofz.complotter::server:lp=raw@plotter.fofz.com%9100psychedelic|This one does colors, man!::server:lp=raw@psychedelic.fofz.com%9100A Logical Queue with Multiple Physical Devices
LPRng allows you to set up a logical main print-queue with several possible destinations, much as System V allows a class to have several component destinations. The printcap options used for this are ss and sv. The main queue is set up with the sv option, which lists the queues connected to actual physical printers. Service queues, which drain jobs from the main queue, use the ss option to indicate the main queue from which it takes jobs. Example 5-11 shows a printcap that exposes a queue named lasers to its clients, but the lasers queue distributes jobs to the printers lj-1 and lj-2.
Example 5-11: Logical Queue with Multiple Devices .common-base:sd=/usr/spool/%P:rw:mx=0:lf=/var/log/%P-log:if=/usr/local/lib/filters/apsfilter:ss=laserlasers:lp=lasers@printerslasers|lj:server:sv=lj-1,lj-2lj-1|LaserJet #1:server:tc=.common-base:lp=raw@lj-1%9100lj-2|LaserJet #2:server:tc=.common-base:lp=raw@lj-2%9100Distributing printcap Files
LPRng makes it significantly easier to distribute printer information to a network, especially because lpd must only be run on those hosts that communicate with printers. Print clients can just be pointed at the print servers with lp entries in the LPRng printcap. Clients will then spool jobs over TCP sockets to the servers. If necessary, you can configure clients to bounce filtered jobs to servers in the printcap file. One potential strategy for distributing printcap information is to write a single large printcap file (using the tc and oh options) and distribute it to all print clients on your network periodically using rdist or sdist.
If you have a network, though, why not use it? Rather than pushing out information to clients, let them fetch it from a central database.
NIS
First, set up NIS with the printcap information distributed as a map.[7] The first step in setting up NIS is to remove any printcap entries that use the lpr syntax of option#value because the databases used to store NIS maps will interpret # as the start of a comment and will truncate the rest of the line. If the line is truncated, no values will be stored in the NIS map. LPRng supports the use of option=value, which is far more readable.
Next, in lpd.conf, you need to specify the program to get printcap information from. LPRng defines a simple interface to the external program: on standard input, specify the name of the printer you would like printcap information for. The program must supply the printcap information for that print name on its standard output. NIS commands require several arguments, so a script is necessary to assemble the arguments into a complete command. Example 5-12 shows an NIS argument marshalling script.
Example 5-12: Getting printcap Entries from NIS #!/bin/sh# filename: /usr/local/lib/printcap-by-name# Get printcap info from NIS for first argumentread printerypmatch "$printer"printcap.bynameThen, in /etc/lpd.conf, configure LPRng to call this script to get a printcap entry:
printcap path |/usr/local/lib/printcap-by-nameLDAP
To distribute the printcap file via LDAP, take the same approach. After putting printcap information into a directory, revise printcap-by-name to assemble the printcap entry from data stored in the directory. We will return to this problem in more detail later.
More Fun with Filters
Included in the LPRng distribution is lpf, a simple filter which translates linefeeds to carriage return plus linefeed, exactly like the destaircaser Perl script in the filter chapter. A collection of LPRng compatible filters is maintained at ftp://ftp.astart.com/pub/LPRng/FILTERS.
Hewlett Packard Printers
The CTI-ifhp filter was originally developed at the Computer Technology Institute of Patras, Greece to support ASCII, PostScript, and PJL print jobs from their heterogeneous network. An additional challenge faced by the authors was the need to support the downloading of a variety of Greek fonts to printers. CTI-ifhp also has hooks into accounting packages.
PostScript Printers
The psfilter package is much like CTI-ifhp, but for PostScript printers. It supports the same accounting methods, so administrators need to learn only one package and develop one set of scripts.
APS Filter, Revisited
apsfilter_LPRng is a modified version of the APS Filter package described in the last chapter. To install it, though, you will need to get your own copies of a2ps, Ghostscript, and pnm. Setup is, for obvious reasons, similar to setting up APS Filter in Chapter 4.
When installed, apsfilter_LPRng takes advantage of some LPRng extensions to simplify the printcap file. APS Filter depends on the name of the print queue to determine what options to pass to subprograms and what subprograms to run. The force_queuename option and the qq option work in tandem to create front-end queues for APS Filter that tie into a single back-end queue. When used together, the name of the queue in force_queuename is recorded in the control file by the LPRng software. When APS Filter processes the job, the job appears to have come from the queue named by the force_queuename parameter even though all jobs are processed by one back-end queue.
By setting the queue name on a submitted job, you can supply APS Filter with the queue name it is expecting so it can do its magic, even though all jobs are actually submitted to the back-end queue, which leaves a natural place to do accounting. In Example 5-13, also note that the server option hides the back end queue from print clients.
Example 5-13: apsfilter_LPRng Configuration ascii|LJ6-ascii-mono:lp=backend@printserv:force_queuename=aps-LJ6-letter-ascii-monoraw|LJ6-raw:lp=backend@printserv:force_queuename=aps-LJ6-letter-rawauto|lp|LJ6-auto-mono:lp=backend@printserv:force_queuename=aps-LJ6-letter-auto-monobackend::lp=/dev/lp0:server:sd=/var/spool/backend:lf=log:af=acct:if=/usr/local/lib/filters/apsfilterAccounting
Printer accounting is a difficult task because the imposition of accounting serves as a motivation to subvert the accounting procedures. The accounting routines in LPRng were developed for an academic environment, which is the most demanding proving ground for code that collects small amounts of money. Accounting is frequently subject to diverse local requirements, so this section sketches out a basic outline of the accounting mechanisms built into LPRng.
How a Job Is Processed
LPRng accounting facilities are hooked into the processing of print jobs in several places. Understanding the accounting facilities requires a knowledge of the job processing procedure. Here's how LPRng processes jobs:
- Open the accounting file specified with the af option in printcap.
- Open the printer device. If the printer is specified as a remote printer, open a socket to the remote lpd. If it is a hardware device, lock the device and open it for writing.
- If an output filter is specified, run the filter. Send standard output of the output filter to the printer device. Save the file descriptor for the standard input of the output filter. For clarity, we refer to this as the output file descriptor because output from other filters is written to that descriptor.
- Print a banner page if one is set up in printcap. (Refer to "Enhanced Banner Pages" earlier in this chapter for details.) The banner page is written directly to the output file descriptor. It is not processed by the input filter, but is processed by the output filter.
- To process a data file, write a magic character sequence to the output filter to suspend it.[8] While the output filter is suspended, launch a copy of the input filter and feed the data for the print job to it. The input filter will process the data and write its output to the output file descriptor. lpd waits for the input filter to exit. If the input filter exits successfully, reactivate the output filter.
- Repeat the previous step for each additional data file.
- Print a trailing banner if specified.
- Close the output filter, mark the job as completed, and erase any temporary files from the spool directory.
Using Accounting Scripts
Accounting with CTI-ifhp or psfilter is straightforward. When the input and output filters start and end, information is written to a log file. LPRng includes a Perl script that can be called with the as and ae options in the printcap file to produce an accounting log. Each filter records its beginning and end in a file, along with the printer's page count. Each pair of lines looks like Example 5-14, which can easily be parsed by Perl, or sed and awk, or yet another text processing tool.
Example 5-14: Format of Log Lines in Accounting File start -ppagecount -Ff -kjob -uuser -hhost -R...end -ppages -qpagecount -Ff -kjob -uuser -hhost -R...At the beginning, the output filter will stamp the start of a job with -Fo and the input filter will record a pair for each file in the job with -Ff. At the very end of the job, the output filter will generate a final line for the log. A typical job might look something like Example 5-15.
Example 5-15: Typical Accounting File Entry
- start -p120 -Fo -kcfA017pauli -ugast -hpauli -R...
- start -p121 -Ff -kcfA017pauli -ugast -hpauli -R...
- end -p1 -q122 -Ff -kcfA017pauli -ugast -hpauli -R...
- start -p122 -Ff -kcfA017pauli -ugast -hpauli -R...
- end -p3 -q125 -Ff -kcfA017pauli -ugast -hpauli -R...
- end -p5 -q125 -Fo -kcfA017pauli -ugast -hpauli -R...
The log snippet of Example 5-15 describes a single job with two data files in it, most likely as the result of lpr file1 file2. To make sense of the output, you need to break it down line by line:
- The output filter is started for job 17 submitted to the server from user gast on host pauli. The initial printer page count is 120.
- An input filter is started for the first data file in the job. The printer page count is 121 because the banner page has been printed on page 121. Because the banner page does not get processed by the input filter, there is no -Ff pair for the banner page.
- The input filter for the first data file in job 17 ended normally after printing one page, leaving the printer page count at 122.
- A second input filter started for the second data file in the job. The printer page count is still 122 because nothing is printed in between files in a job.
- The second input filter terminated after printing three pages (123, 124, and 125).
- The output filter terminated after printing five pages.
If the output filter terminated unexpectedly, then we would have seen the next job start without ever seeing the end of job 17, as in Example 5-16.
Example 5-16: What Happens When Output Filters Die start -p120 -Fo -kcfA017pauli -ugast -hpauli -R...start -p121 -Ff -kcfA017pauli -ugast -hpauli -R...end -p1 -q122 -Ff -kcfA017pauli -ugast -hpauli -R...start -p122 -Ff -kcfA017pauli -ugast -hpauli -R...start -p125 -Fo -kcfA039laplace -utodd -hlaplace -R...start -p126 -Ff -kcfA039laplace -utodd -hlaplace -R...In the previous example, we can still assume that user gast printed five pages, but that he attempted to hang the printer to avoid paying for the last three. A program parsing the accounting log needs to handle all the cases of missing entries that may happen at your institution.
1. That was not a joke. No better test of accounting exists than to use it in an attempt to collect money from students who don't have any.
2. This is a clear illustration of the rapid evolution of open source software. It is no longer sufficient to speak of current versions as books are written because several revisions may appear during the course of composing a book.
3. When GNU make is installed on Solaris systems, it is often named gmake to distinguish it from the version of make shipped with the operating system.
4. The System V boot process is too complex to be explained here; for a detailed discussion, see Essential System Administration, by Æleen Frisch (O'Reilly).
5. The line is in fact an excerpt from inetd.conf on Solaris 7. In Chapter 4, Extending the Berkeley Spooler with Print Filters, we noted that Solaris has started using Berkeley-style spooling. What better demonstration than a spooling daemon with lpd in the name?
6. The LPRng version of printcap has several more variables than the generic BSD printcap. Check the man page for the LPRng printcap for a full description.
7. For help with NIS, we recommend Hal Stern's Managing NFS and NIS (O'Reilly, 1991).
8. Technically, output filters can only be suspended if the job is of type f (formatted text), l (leave control characters in the job), or p (print text like pr). However, most jobs are one of these types.
Back to: Network Printing
© 2001, O'Reilly & Associates, Inc.
webmaster@oreilly.com