Next Previous Contents

## 5. /etc/printcap Print Spool Database File

The heart of the LPRng system is the file `/etc/printcap`. This file contains a list of printer definitions. I'll describe a few simple configurations. I would advise you to read through all of them, as I will introduce several features gradually throughout this section.

For details about individual printcap items, see the `printcap(5)` man page from the LPRng distribution, or entries in the index section.

## 5.1 Index To All The Options

Option | Meaning
`ab` | always print banner, ignore lpr -h option
`achk` | query accounting server when connected
`ae` | accounting at end (see also af, la, ar, as)
`af` | name of accounting file (see also la, ar)
`ah` | automatically hold all jobs
`allow_duplicate_args` | Allow duplicate command line arguments (legacy requirement)
`allow_getenv` | Allow use of LPD_CONF
`allow_user_logging` | allow users to request logging info using lpr -mhost%port
`ar` | enable remote transfer accounting (if af is set)
`as` | accounting at start (see also af, la, ar)
`be` | Banner at End Generation Program
`bk` | Berkeley LPD job file format
`bk_filter_options` | Berkeley LPD filter options
`bk_of_filter_options` | Berkeley LPD OF filter options
`bkf` | backwards-compatible filters: use simple paramters
`bl` | short banner line sent to banner printer
`bp` | Banner Generation Program (see bs, be)
`bq` | Use filters on bounce queue jobs
`br` | Serial port bit rate (see ty)
`break_classname_priority_link` | Don't default priority from classname (legacy requirement)
`bs` | Banner at Start Generation Program
`cd` | control directory
`check_for_nonprintable` | LPR checks for nonprintable file
`check_idle` | program used to check for idle printer
`classname_length` | Maximum length of classname argument (legacy requirement)
`cm` | comment identifying printer (LPQ)
`co` | cost in dollars per thousand pages
`config_file` | configuration file
`connect_grace` | connection control for remote printers
`connect_interval` | connection control for remote printers
`connect_timeout` | connection control for remote printers
`connect_try` | connection control for remote printers
`control_filter` | control file filter
`db` | debug options for queue
`default_auth` | default authentication
`default_format` | default job format
`default_logger_port` | default port for logging info
`default_logger_protocol` | default protocol for logging info
`default_permission` | default permission for files
`default_printer` | default printer
`default_priority` | default job priority
`default_remote_host` | default remote host
`default_tmp_dir` | default directory for temp files
`destinations` | printers that a route filter may return and we should query
`direct_read` | filter input is direct from data file
`fc` | OBSOLETE, see sy
`fd` | forwarded jobs not accepted
`ff` | string to send for a form feed
`filter_ld_path` | filter LD_LIBRARY_PATH value
`filter_options` | filter options
`filter_path` | filter PATH environment variable
`fix_bad_job` | fix bad job files
`fo` | send form feed when device is opened
`force_fqdn_hostname` | force FQDN HOST value in control file
`force_localhost` | force clients to send all requests to localhost
`force_queuename` | force use of this queuename if none provided
`forward_auth` | do server to server authentication if authenticated by user
`fq` | send form feed when device is closed
`fs` | OBSOLETE (see sy)
`full_time` | use extended time format
`fx` | valid output filter formats
`generate_banner` | force a banner to be generated
`group` | Effective Group ID (EGID) for SUID ROOT programs
`hl` | Header (banner) last, at end of job
| Ignore control file and data file name format errors
`ignore_requested_user_priority` | Ignore requested user priority
`if` | default (f, l) filter program
`ipv6` | using IPV6 conventions
`kerberos_keytab` | kerberos keytab file location
`kerberos_life` | kerberos key lifetime
`kerberos_renew` | kerberos key renewal time
`kerberos_server_principle` | kerberos remote server principle name
`kerberos_service` | kerberos default service
`la` | enable local printer accounting (if af is set)
`ld` | leader string sent on printer open
`lf` | error log file for spool queue
`lk` | lock the IO device
`localhost` | localhost name for DNS queries
`lockfile` | lpd lock file
`logfile` | lpd log file
`logger_destination` | additional destination for logging information
`longnumber` | use long job number when a job is submitted
`lp` | printer device name or specification
`lpd_force_poll` | force lpd to poll idle printers
`lpd_poll_time` | interval between lpd printer polls
`lpd_port` | lpd listening port
`lpd_printcap_path` | lpd printcap path
`lpr_bounce` | lpr does filtering as in bounce queue

`mail_from` | mail user from user name
`mail_operator_on_error` | mail to this operator on error
`max_connect_interval` | maximum time between connection attempts
`max_log_file_size` | maximum size (in K) of spool queue log file
`max_servers_active` | maximum number of lpd queue servers that can be active
`max_status_line` | maximum length of status line
`max_status_size` | maximum size (in K) of status file
`mc` | maximum copies allowed
`mi` | minimum space (Kb) to be left in spool filesystem
`min_log_file_size` | minimum size (in K) of spool queue log file
`min_status_size` | minimum size to reduce status file to
`minfree` | minimum amount of free space needed
`ml` | minimum number of printable characters for printable check
`ms` | stty options for serial lines (ms is an alias for sy)
`ms_time_resolution` | millisecond time resolution
`mx` | maximum job size (1Kb blocks, 0 = unlimited)
`nb` | use nonblocking device open
`network_connect_grace` | pause between transferring jobs to remote printer
`nw` | spool dir is on an NFS file system
`of` | banner output filter
`of_filter_options` | OF filter options
`originate_port` | originate connections from these ports
`pass_env` | clients pass these environment variables to filters
`perms_path` | lpd.perms files
`pl` | page length (in lines)
`pr` | pr program for p format
`printcap_path` | /etc/printcap files
`ps` | printer status file name
`pw` | page width (in characters)
`px` | page width in pixels (horizontal)
`py` | page length in pixels (vertical)
`qq` | put queue name in control file
`remote_support` | operations allowed to remote host
`remote_user` | remote-queue machine (hostname) (with rm)
`report_server_as` | server name for status reports
`retry_econnrefused` | Retry on connect ECONNREFUSED errors
`retry_nolink` | Retry device open or connect failures
`return_short_status` | return short lpq status when request arrives from specified host
`reuse_addr` | set SO_REUSEADDR on outgoing ports
`reverse_lpq_format` | reverse lpq format when request arrives from specified host
`rg` | clients allow only users in this group access to printer
`rm` | remote machine (hostname) (with rp)
`router` | routing filter, returns destinations
`rp` | remote printer name (with rm)
`rt` | number of times to (re)try printing or transfer (0=infinite)
`rw` | open printer for reading and writing
`safe_chars` | additional safe characters in control file lines
`save_on_error` | save job when an error
`save_when_done` | save job when done
`sb` | short banner (one line only)
`sc` | suppress multiple copies
`sd` | spool directory pathname
`send_block_format` | send block of data, rather than individual files
`send_data_first` | send data files first in job transfer
`send_failure_action` | failure action to take after send_try attempts failed
`send_job_rw_timeout` | print job read/write timeout
`send_query_rw_timeout` | status query operation read/write timeout
`send_try` | (alias for rt)
`sendmail` | sendmail program
`server_auth_command` | server authenticate transfer program
`server_tmp_dir` | server temporary file directory
`server_user` | server user name for authentication
`sf` | suppress form feeds separating data files in job
`sh` | suppress header (banner) pages
`short_status_length` | short lpq status length in lines
`socket_linger` | set the SO_LINGER socket option
`spool_dir_perms` | spool directory permissions
`spool_file_perms` | spool file permissions
`spread_jobs` | amount to spread jobs to avoid collisions
`ss` | name of queue that server serves (with sv)
`stalled_time` | time after which to report active job stalled
`stop_on_abort` | stop processing queue on filter abort
`sv` | names of servers for queue (with ss)
`sy` | stty commands to set output line characteristictics
`syslog_device` | name of syslog device
`tr` | trailer string to send before closing printer
`translate_format` | translate data format in control file
`ty` | stty commands to set serial line characteristictics
`use_auth` | authentication type to use
`use_date` | force date in control file
`use_identifier` | force identifier in control file
`use_info_cache` | read and cache information
`use_queuename` | put queue name in control file (alias for qq)
`use_shorthost` | Use short hostname for lpr control and data file names
`user` | Effective User ID (EUID) for SUID ROOT programs
`user_auth_command` | client side authentication program
`user_lpc` | allow selected lpc commands on user files
`xc` | OBSOLETE (see sy)
`xs` | OBSOLETE (see ty)
`xt` | formats supported on printer
`xu` | additional permissions file for this queue

## 5.2 A very simple example

Options used:

- `cm=`comment for status
- `if=`default job file filter
- `lf=`log file
- `mx#`maximum job size
- `lp=`output device
- `sd=`spool directory file
- `sh` suppress headers (banners)
- `sf` suppress form feeds between files

The easiest configuration is this: a local printer directly connected to a printer port.

    # Local ASCII printer
    lp1|printer
      # alias is printer or lp
      |lp
      :lp=/dev/lp1
      :cm=Dumb printer
      :sd=/var/spool/lpd/lp1
      :lf=log:af=acct
      :if=/usr/local/sbin/lpf
      :mx#0:sh:sf

I'll use this simple example to explain the basics of the LPRng printcap format.

Lines starting with a `#` sign are comments, and all leading and trailing whitespace, i.e. - spaces, tabs, etc, are ignored. Empty lines are ignored as well.

Note that you are not required to use continuation backslashes (`\`) as would be needed for an BSD LPR style printcap file in the printcap entries. You are allowed to use them, however: this comes in handy if you happen to have a BSD LPR printcap file. The backslash will cause the next line to be appended to the current line; watch out for comments and ends of printcap entries if you use this.

A printer (printcap entry) definition starts with the printer name, followed by one or more aliases, followed by a list of options. The name for a printer will be used be in LPRng status output to identify the printer.

The colon (:) is used to start the definition of an option or flag values. The definition continues to the end of the line or until the next colon. If an option value contains a colon, then use `\:` to escape the value. Options take the form of a keyword/value pair. Options and values are case sensitive; for example `Ts` and `ts` refer to different options. Numerical values are indicated by a `#` separator, while a `=` indicates a string value. Boolean switches or flags are set TRUE if no value follows the keyword and FALSE by appending a `@`. For example `sh` will set the `sh` flag to TRUE and `sh@` to FALSE.

There may be several options on the same line, separated by colons. However, this does make the file less readable. The next tip was supplied by James H. Young <`jhy@gsu.edu`>:

> My personal preference for readability is to always put each option on its own line. Putting each option on its own line is worth the trouble even though it detracts from the usability of certain grepping techniques when trying to maintain these types of files.

Let's go over the options used in this example:

1. First of all, there's the `lp` entry. It specifies the file (or location) to which data is sent. Here, it is the device `/dev/lp1`. (This is system-dependent---check your vendor's manual for information on devices.) The absolute pathname indicates we have a local printer or file.
2. The `cm` field can be used to supply a comment to be used as a header in `lpq` output.
3. `sd` specifies the spool directory. This is where files are stored until they are printed.
4. The `lf` and `af` options specify the location for the log and accounting files, respectively. They are not strictly needed for the printer to function, but a log file is highly recommended, in case things go wrong. One special point to note: if these files don't exist, they will not be created, and no logging or accounting will be done. You will need to create them manually (e.g., by using `touch`) or by using the <tt>checkpc</tt> program. LPRng is very fussy about permissions - you should run checkpc to make sure that the log and status files have the correct ownership and permissions.
5. The if entry specifies a `filter' for the `text' format. The filter will be applied to any incoming job (of a certain format), even the ones coming from another host. Filters and print formats are discussed in section Filters. This particular filter would translate UNIX LF line endings to DOS CR/LF, to prevent the `staircase effect' and expand tabs to spaces. As this problem also occurs with other printing daemons, it is likely that your system has a similar utility.
6. `mx` indicates the maximum file size for a print job. Supplying 0 here means that there is no limit.
7. Finally, I have given the `sh` (suppress headers) flag. This will inhibit banner pages.

## 5.3 A serial printer queue

Options used:

- `br#`serial port bit rate
- `ms=`(alias for sy)
- `sy=`stty options for serial port configuration
- `ty=`(alias for sy)

When connecting to a serial printer, you need to set up the serial line so that it will pass data without any additional processing. This will allow binary files to be transferred safely. The `sy` printcap entry specifies a set of `stty(1)` flags and line speed that will be used to set up the serial line. (See Serial Printers for details) The `br` (bit rate) option can be used to specify the line speed as well. The following is a typical printcap for a serial printer.

    # Local Serial ASCII printer
    lp2
      :lp=/dev/ttya
      :cm=Serial printer
      :sd=/var/spool/lpd/lp2
      :sy=9600 -echo -crmod -raw -oddp -evenp pass8 cbreak ixon
      :if=/usr/local/sbin/lpf
      :mx#0:sh

## 5.4 A remote printer queue

Options used:

- `lp=`destination
- `rm=`remote host (machine)
- `rp=`remote printer (machine)

LPRng will allow you to print over a TCP/IP network, just like the BSD LPR software. The machine from which you are printing is called the local or client host. You run the `lpr` program on the client host to send print jobs to the `lpd` daemon or server process running on the remote server host. The `lpd` daemon accepts jobs for printing, puts them in its print queue, and processes them for printing on a printer.

This operation of having a user (client) program send requests or jobs to another (server) program which does the actual work is called the client/server model of computing. The `lpd` daemon process is the server, and the `lpr`, `lpq`, `lprm`, and `lpc` are client programs. The clients send either jobs or service requests to the server using the RFC1179 protocol.

One of the major ways that LPRng differs from the BSD LPD software is that the client programs are vastly more powerful and flexible. The BSD LPR software client programs transferred print jobs to spool (queue) directories on the client's host machine; the `lpd` server running on the client machine would then take these files and transfer them to the remote `lpd` server. This meant that every host was required to run an `lpd` daemon process and to have spool queues for every printer that the user could possibly use.

Imagine the problems that exist in a facility with literally thousands of printers, many of which are being added or removed from service on a daily basis. This would require the system administrators to create spool directories on each host. The LPRng software eliminates these problems by allowing client programs to directly transfer jobs to a remote `lpd` daemon or printer over a TCP/IP network connection. This eliminates both the need for a `lpd` daemon as well as the print spool directories on the local host.

To send a job to a printer or remote ``lpd`' daemon all you need to do is specify the printer name and server hostname or IP address. This can be done using:

    lpr -Ppr@server printfile

This will cause the lpr program to transfer the printfile to the lpd daemon running on the server host, and spool it for the pr printer. If you set the `PRINTER` environment variable, then you can simply do the following:

    PRINTER=pr@server; export PRINTER;
    lpr printfile

## 5.5 Network Printing With /etc/printcap

While the above method is the simplest way to use the LPRng software for network printing, some users discover that they need the full power of a lpd server running on their local host to support printing, or need more than the simple transfer and network capabilities of the client programs. Another problem is that they sometimes need to have aliases for their printer names, or want to be able to specify just the name of the printer and have the remote server for it supplied by the printing software.

This type of operation requires setting up an `/etc/printcap` file and using the printcap configuration information. Both the client programs (`lpr`, `lpc`, `lprm`, `lpq`) and the `lpd` daemon use the information in the `/etc/printcap` file to specify how they will process print jobs. The same printcap file is used by both client programs and the lpd daemon, but each will use different parts of the information.

There are several possibilities for specifying network printers. I'm showing some different syntaxes for the entries here. This is the information that clients will need to have to send a job to the network printer.

    # This is LPRng specific
    remote|Remote Printer
       :lp=raw@server
    # Convention from `old' BSD spooler
    remote:Old Format:\
        :rp=raw:rm=server
    # Sometimes you have to connect to a non-standard port
    special:lp=lp@server%2000

All the above printcap entries will make the lpr print client connect to the remote host `server` and send the file to the `raw` printer. You can specify the remote printer and remote host using the `:rp` and `:rm` entries, or the LPRng extension `lp=rp@rm`.

Note that we don't need a spool directory for this kind of printer, nor do we need to run `lpd` on the client host machine, as the job will be transferred directly to the remote host.

Many printers now come equipped with a network support card that has a built in LPD print spooler. If this is the case you can print directly to the printer and do not need to spool your print job to a server.

## 5.6 Spooling To Local Server

Options used:

- `force_localhost` force clients to send requests to localhost
- `localhost=`localhost name

Some users may not want to send a print job directly to a remote printer. The printer may need the more powerful management functions of a print spooler to handle problems such as paper feed errors, multiple users, etc, or needs to run special filters to process the print job. In this case, they want the print job sent to a `lpd` server on the local host, which in turn will spool the job and send it to the remote printer. This can be done in several ways.

    # Method 1: force client transfer to localhost
    #    have server send to real printer
    #    both client and server will see the following information
    remote|Spool to localhost
       :lp=lp@localhost
    # Note that only the server will see the following information
    lp:server:lp=lp@remote:sd=/usr/spool/lp
    # Method 2: force client transfer to localhost
    #    both client and server will see the following information
    remote|Spool to localhost
       :force_localhost
       :lp=lp@remote:sd=/usr/spool/lp
    # Method 3: force a bounce queue with no effect
    remote|Spool to localhost
       :lp=lp@localhost
       :bq=lp@remote:sd=/usr/spool/lp

In the first method, we have the clients send jobs to the lp printer on the localhost; localhost is the 'canonical' network name for the host on which the program is running. The lpd server on the localhost will get the print job, store it in the spool directory `/usr/spool/lp` and then forward the job to the lp printer on the remote host. The `server` tag indicates that a printcap entry is to be used only by the `lpd` daemon (server) process, and the information is ignored by the client. The `server` tag is discussed in detail in the Shared printcap files section.

One of the problems is finding the name of the local host. On some implementations which are not using a Domain Name Server, it is necessary to specify the local host name by using the `localhost` configuration variable.

The second method is slightly different. The `force_localhost` flag has meaning only for the client application programs, and forces them to send the job to the localhost. The server will then send the job to the remote host.

The third method is useful when you want the print job to be modified en passant as it passes through the spool queue. See the Filters discussion for details.

## 5.7 Shared printcap files

When both the client host and server host are the same machine, then the same /etc/printcap file will be used by both the lpr and lpd daemon programs. When LPRng programs read the /etc/printcap file, they accumulate information in the printcap file on individual printer entries. For example, the following printcap entries would result in the indicated information:

    #/etc/printcap file
    pr:lp=pr@host
    pr:lp=/dev/lp:sh
    #resulting printcap information:
    pr:lp=/dev/lp:sh

This allows us to split up the printcap information into different blocks, and has been used to manage complex printcap entries on large sites with many printers.

We can use the `server` tag to specify that specific printcap information is only for use by the lpd daemon. For example:

    #/etc/printcap file
    pr:lp=pr@host
    pr:server:lp=/dev/lp:sh
    #resulting printcap information for client
    pr:lp=pr@host
    #resulting printcap information for lpd daemon
    pr:lp=/dev/lp:sh

Many administrators at large sites will split up their printcap files so that the information needed to tell clients where the servers are for a printer is located at the start of the /etc/printcap file, and the actual information needed by the lpd daemon is at the end. Here is a sample:

    #/etc/printcap file
    pr1:lp=pr1@serverhost
    pr2:lp=pr2@serverhost
    pr1:server:lp=/dev/lp:tc=.common
    pr2:server:lp=/dev/lp:tc=.common
    .common:sd=/usr/local/lpd/%P
      :cm=Dumb printer %P
      :lf=log:af=acct
      :if=/usr/local/sbin/lpf
      :mx#0:sh

This printcap entry also shows the use of the `tc` option, which corresponds to the C Compiler Preprocessor (cpp) `#include` directive. Printcap entries starting with periods, underscores (`_`), or `@` signs are treated as dummy printcap information and can only be referenced by the `tc`.

When the printcap information is read, the LPRng code will substitute the cannonical printer name for any `%P` tokens that it finds in the printcap. After processing the information in the printcap entry, the clients and `lpd` daemon will see the following:

    # clients
    pr1:lp=pr1@serverhost
    pr2:lp=pr2@serverhost
    # server
    pr1:lp=/dev/lp
      :sd=/usr/local/lpd/pr1
      :cm=Dumb printer pr1
      :lf=log:af=acct
      :if=/usr/local/sbin/lpf
      :mx#0:sh
    pr2:server:lp=/dev/lp:
      :sd=/usr/local/lpd/pr2
      :cm=Dumb printer pr2
      :lf=log:af=acct
      :if=/usr/local/sbin/lpf
      :mx#0:sh

## 5.8 Master Printcap Files

One of the major problems faced by administrators of large sites is how to distribute printcap information. They would like to have a single printcap file either distributed by a file server (NFS) or by some other method such as rdist.

By using the `server` tag, information for the lpd daemons can be separated out from the information needed by the lpr print client. The `oh=pattern` specifies that this information is only to be used by a specified host. For example:

    #/etc/printcap file
    pr1:lp=pr1@serverhost1:oh=*.eng.site.com,130.191.12.0/24
    pr2:lp=pr1@serverhost1:oh=*.eng.site.com,130.191.12.0/24
    pr1:lp=pr2@serverhost2:oh=*.admin.site.com
    pr2:lp=pr2@serverhost2:oh=*.admin.site.com
    pr1:server:oh=serverhost1.eng.com:lp=/dev/lp:tc=.common
    pr2:server:oh=serverhost2.admin.com:lp=/dev/lp:tc=.common
    .common:sd=/usr/local/lpd/%P

The above example is a total abuse of the use of `oh` tag, but has some interesting effects. The `pattern` is used as a glob pattern and is applied to the fully qualified domain name (FQDN) of the host reading the printcap file. For example, `*.eng.site.com` would match host `h1.eng.site.com` but would not match `h1.admin.site.com`. Thus, the effects of the first couple of entries would be to specify that the `pr1` and `pr2` printers on the `eng` hosts would be `pr1@serverhost1`, and on the `admin` hosts would be `pr2@serverhost2`,

Also, the lpd daemons on `serverhost1` and `serverhost2` would only extract the additional information for `pr1` and `pr2` respectively.

You can also specify network addresses and subnet masks as well. In this case, if the host matches the network address then it will use the information.

## 5.9 Printcap options for lpr, lpq, lprm, and lpc

These programs are used by users to connect to the `lpd` server and send print jobs or a request. For details about the way that this is done, see LPRng and RFC1179 for details.

The following options and configuration variables are used by the various programs to control how they will generate jobs and send them to the server.

### lp, rm and rp

The `rm` (remote machine or host) and `rp` or `lp` printer printcap options are used to specify the remote host and printer to be used. These values can be extracted from a printcap entry, or supplied in the following manner.

1. If the user program is invoked with `-Pxxx` argument, then the `lp` option is assigned the value `xxx`.
2. If no explicit value is specified and the PRINTER environment variable has value `xxx`, then the `lp` option is assigned value `xxx`.
3. If `lp` has a value of the form `rp@rm` or `rp@rm%port`, then the `rp`, `rm`, and `lpd_port` options are assigned the indicated values.
4. If `rm` or `rp` does not have a value, then they are assigned the `default_host` (usually localhost) and `default_printer` (usually lp) option values.
5. A connection is made to `lpd_port` on host `rm` and the file transfer or command is sent as specified in RFC1179.

See the Opening Output Device section for additional details.

## 5.10 Bounce queues

Options used:

- `bq=`destination for processed jobs
- `generate_banner` do banner generation
- `translate_format` do banner generation

Normally, when using a remote queue, the print job is transmitted to the server computer without any modifications. When it gets there, it might be processed by one or more programs before being submitted to the printer.

Sometimes, you will want to make some modifications to a print job on the computer that sends the job, or even a computer that is acting as a relay for job processing. There are several reasons for doing this: the filter programs or some of the fonts it needs might not be available on the server, or you want to minimize the system load.

LPRng supports this capability by indicating that a printer is actually a bounce queue. The term comes from the notion that jobs will bounce through this print queue, getting processed by the various facilities. The output, rather than going to a physical device, will then be forwarded to final destination over the network for actual printing.

Again, you will modify the client printcap entry to declare this. In the next example, `host' is the name of the host which will do the processing, and `remote' is the target host with the printer.

    # Simple example of a bounce queue
    bounce
        :lp=bounce@bouncehost
        :bq=lp@remote
        :sd=/usr/spool/lpd/bounce
        :if=/usr/local/bin/lpf
        :vf=/usr/local/bin/lpf
        :translate_format=vl
        # uncomment if you want banner
        #:generate_banner

Some comments:

1. The `lp=bounce@host` entry specifies the queue and hostname where the filtering will be done. This information is used by the lpr program to determine where to send the print job.
2. After the lpd daemon on the bouncehost does the processing, the output is then transmitted to the queue and hostname specified by the `bq` option.
3. We need a spool directory (`sd`) on the lpd server host to hold the files and temporary output while they are processed.
4. Next, we need to indicate the filters to be used for different printer formats. Oops, I still didn't tell you anything about filters. Just a moment, it's on its way. See section Filters.
5. The `translate_format` specifies the way the data file formats will be renamed after filtering. It the value consists of pairs of letters, the original and renamed format. For example, `translate_format=vl` specifies that after filtering, format `v` files will be renamed to format `l` (literal or binary). You do not need to have a filter for a format to rename it. For example, `translate_format=vlxf` will rename format `x` files to `f` and there is no filter for format `x`. See translate_format for more details.
6. The `generate_banner` flag will force a banner to be added to the job. The banner generation is done as discussed in Banner Printing.

In this example, anything sent to the printer called `bounce` (on this host) will be filtered on the client host. After that, it will be transmitted to the queue `lp` on the server called remote.

## 5.11 LPR Filtering

Options used:

- `lpr_bounce` lpr does filtering

Some users would like to have all of the advantages of having the filtering and processing capabilities of a lpd daemon without needing to deal with actually running a lpd daemon on their system. By having the `lpr` program process the job by passing it through the various filters and then send the output of the filters as the print job you can get the desired effect.

    # Simple example of an lpr_bounce entry
    bounce
      :lpr_bounce
      :lp=lp@remote
      :if=/usr/local/bin/lpf

The `lpr_bounce` flag, if present in the printcap entry, will force `lpr` to process the job using the specified filters and send the outputs of the filters to the remote printer for further processing.

In order to do filtering, it may need to create some temporary files and run some programs. By default, the temporary files are created in the `/tmp` directory and the programs are run as user. Since no spool directory is used, the `sd` information is not needed.

## 5.12 Dynamic Routing

Options used:

- `destinations=`destinations for jobs
- `router=`router program

The LPD bounce queue functionality has been extended to allow a job to not only be passed through filters before sending to a remote destination, but also to reroute the job to one or more destinations in a dynamic manner. This is accomplished by having a `router` filter return a set of destinations. Here is a sample printcap to accomplish this:

    t2|Test Printer 2:sd=/var/spool/LPD/t2
        :lf=log
        :lp=t2@printserver
        :bq=t1@localhost
        :destinations=t1@localhost,t2@localhost
        :router=/usr/local/LPD/router

The lp entry is used to force all jobs to be sent to the bounce queue on host 'printserver'. Once they arrive, the 'router' filter is invoked with the standard filter options which include the user, host, and other information obtained from the control file. STDIN is connected to a temporary copy of the control file, and the CONTROL environment variable is set to the value of the actual control file itself.

The routing filter exit status is used as follows:

- 0 (JSUCC) - normal processing
- 37 (JHOLD) - job is held
- any other value - job is deleted from queue

The router filter returns one or more routing entries with the following format. Note that entry order is not important, but each entry must end with the 'end' tag.

    dest (destination queue)
    copies (number of copies to be made)
    priority (priority letter)
    X(controlfile modifications)
    end

Example of router output:

    dest t1@localhost
    copies 2
    CA
    priority B
    end
    dest t2@localhost
    CZ
    priority Z
    end

The above routing information will have copies of the job sent to the t1 and t2 spool queue servers. If no valid routing information is returned by the router filter the job will be sent to the default bounce queue destination.

LPQ will display job information in a slightly different format for multiple destination jobs. For example:

    Printer: t2@astart2 'Test Printer 2' (routed/bounce queue to 't1@astart2.astart.com')
      Queue: 1 printable jobs in queue
     Rank  Owner/ID        Class Job Files                           Size Time
    active  papowell@astart2+707 A 707  /tmp/hi                         3 10:04:49
     - actv papowell@astart2+707.1 A 707 ->t1@localhost <cpy 1/2>       3 10:04:49
     -      papowell@astart2+707.2 A 707 ->t2@localhost                 3 10:04:49

The routing information is displayed below the main job information. Each destination will have its transfer status displayed as it is transferred. By convention, the job identifier of the routed jobs will have a suffix of the form .N added; copies will have CN added as well. For example, papowell@astart2+707.1C2 will be the job sent to the first destination, copy two.

Routed jobs can be held, removed, etc., just as normal jobs. In addition, the individual destination jobs can be manipulated as well. The LPC functionality has been extended to recognize destination jobids as well as the main job id for control and/or selection operations.

The optional `destinations` entry specifies the possible set of destinations that the job can be sent to, and is for informational purposes only. In order for LPQ/LPRM to find the job once it has passed through LPD, LPQ/LPRM uses the list of printers in the `destinations`, and loop over all the names in the list looking for the "job" that you are interested in. If there is no `destinations` information, the `bq` information will be usued.

One of the more interesting use of the router filter is to actualy modify the control file before it is put into the spool queue. The routing filter has STDIN attached to the control file READ/WRITE, allowing the following interesting bit of Perl code to be used:

     # you need to get PERL to do a 'dup' call on FD 0
     open(CF, '+<0');
     # read the control file
     @cf_lines = <CF>;
     # TRUNCATE the control file
     truncate(CF,0);
     # mess about with the control file
     foreach $line (@cf_lines) {
        # or whatever you want
        print CF $line;
     }

This will read the control file, truncate it, and then write it out again.

## 5.13 Support for Network Print Servers

This section was supplied by Horst Fickenscher <`horst.fickenscher@it.erlm.siemens.de`> and updated by Patrick Powell <`papowell@astart.com`>.

A ``network print server'' is usually a box (external model) or card in a printer (internal model) which has a network connection to a TCP network and software to implement a LPD print server. If it is an external model, The parallel or serial port of the printer is connected to the box, and the print server may support multiple printers. If it is an internal model, the server is usually nothing more than a Network Interface Controller and a ROM containing software that the microprocessor in the printer uses.

The print server may support multiple printing protocols, such as RFC1179 (TCP/IP printing using the LPD print protocol), Novell Printer Protocols, SMB print protocols, and Appletalk protocols. One of the observed problems with Network Print servers is that while they can usually support one protocol and one user at a time quite well, when you try to use multiple protocols and/or multiple users try to transfer print jobs to the printer, the printer may behave in a very odd manner. Usually this results in a printer failing to finish a job currently being printed, and unable to accept new jobs.

Several of the newer models of print servers have Simple Network Management Protocol (SNMP) agents built into them, and can provide detailed information about their internal functions. By using a SNMP manager such as SunNetmanage or HP-Openview, you can monitor your network printers activities.

Although it's possible to connect to network printers as if they were remote printers, Patrick Powell advises differently:

> I recommend that you use only a single protocol to send jobs to the printer. If you can, I also recommend that you use a print spooler and have only a single host system send a job to the printer.

> My best advice on connecting to network printers is not to use the the built-in LPD server, but to use the direct TCP/IP connection to the print engine. Usually this is done to particular TCP/IP port on the printer. For the HP JetDirect and other HP products, this is usually 9100.

> Once you have the direct connection, you can now use various filters to preprocess the print job, insert PJL and PCL commands, or convert text to PostScript or PCL for better print quality.

Here is a sample printcap for an HP LaserJet 4 or above, attached via an HP JetDirect print server. It uses the CTI-ifhp filters:

         # printcap file for pr4
         # PostScript via JetDirect card, IP address pr4, port 9100.
         # Note: some PC's LPR packages use the v format for their jobs
         #
         pr4|network
             :rw:sh:lp=pr4%9100:sd=/usr/spool/lpd/pr4
             :af=acct: :lf=log: :ps=status
             # only allow the following formats
             :fx=flpv
             #filters
             :if=/usr/local/lib/CTI-Print/bin/ifhp
             :of=/usr/local/lib/CTI-Print/bin/ofhp
             :vf=/usr/local/lib/CTI-Print/bin/ifhp -c

The `lp=pr4%9100` means that LPRng is to make a TCP/IP connection to host `pr4` on its port 9100. The CTI-Print filters referenced in `if`, `of`, and `vf`, send PJL (and PCL) commands along with the print files to the printer. The CTI-Print filters are available separately from the LPRng distribution sites.

Filters are discussed in section Filters.

According to Richard S. Shuford <`s4r@ornl.gov`>, some DEC printers (e.g., the DEClaser 3500) use TCP port 10001.

## 5.14 Printer load balancing

In a large site, you could have several equivalent printers, which will be used by many people. The reason for this is, of course, to increase the printer output by enabling several jobs to be printed at once.

LPRng supplies mechanisms to define a `virtual' printer for such a set of real printers. If properly set up, print jobs will be distributed evenly over all printers.

I'll give two examples for this situation.

### Multi-server print queue

Options used:

- `ss=`queue served by printer
- `sv=`printers where jobs are sent (servers)

A multi-server print queue is one that feeds jobs to other queues. The main queue `sv=q1,q2,...` printcap entry specifies the names of the printers that will be sent jobs. These printers must have their spool queues on this LPD server.

Servers that are fed jobs have a `ss=`mainqueue printcap entry. This informs the `lpd` server that the queue operates under the control of the mainqueue print queue, and is fed jobs from it.

During normal operation, when the `lpd` server has a job to print in the mainqueue, it will check to see if there is an idle service queue. If there is, it will transfer the job to the service queue spooling directory and start the service queue printing activities.

Users can send jobs directly to the individual printers serving a queue.

The next example (and the comments underneath) was supplied by John Perkins <`john@cs.wisc.edu`> (slightly edited).

Here's how I've set up a bounce queue that feeds 6 LaserWriters:

    laser|pi|Room 1359 LaserWriters
        :lp=laser@server.com
    laser|pi|Room 1359 LaserWriters
        :server
        :lf=/usr/adm/laser-log
        :sv=laser1,laser2,laser3,laser4,laser5,laser6
        :sd=/usr/spool/laser
    @commonlaser
        :sd=/usr/spool/%P
        :rw:mx#0:sh
        :lf=/usr/adm/laser1-log
        :if=/s/lprng/lib/filters/cappsif
        :of=/s/lprng/depend/cap/bin/papof
        :ss=laser
        :fx=fdginpt
    laser1|pi1|Room 1359 LaserWriter #1
        :lp=laser1@server.com
    laser1|pi1|Room 1359 LaserWriter #1
        :server
        :lp=/dev/laser1
        :tc=@commonlaser
    laser2|pi2|Room 1359 LaserWriter #1
        :lp=laser2@server.com
    laser2|pi2|Room 1359 LaserWriter #2
        :server
        :lp=/dev/laser2
        :tc=@commonlaser

and so on for the other 4 `laser` N queues.

This will forward a job from `laser` to `laser` N, once one of those queues is available. It will hold jobs in the ```laser`'' queue until one of the other queues is empty.

Even though the queues are not meant for direct use, people can print directly to individual queues. This allows a specific load sharing printer to be used. If you wanted to hide the load sharing printers, i.e. - not allow direct spooling to them, then you would simply remove the non-server entries from the printcap.

### Checking Busy Status of Server Queues

Options used:

- `check_idle=`check for idle printer program

The previous section outlined how LPRng uses the `sv` and `ss` flags to indicate that the server spool queue has multiple destination queues. However, there is a problem when the actual printer being served by the destination queue is a remote device, and can be busy or offline.

The `check_idle` option specifies a program that is invoked by the `lpd` server to determine if the spool queue device is available.

The program is invoked with the standard filter options, STDIN and STDOUT connected to `/dev/null`, and STDERR to the error log.

The program should make a connection to the remote device or system and should determine that the remote device is available for use, and then exit with the following status.

    Key      Value   Meaning
    JSUCC    0       Successful - printer is idle
    JABORT   non-zero Printer is not accepting jobs

If the printer is accepting jobs but is temporarily busy, the program should poll the printer until it becomes free, only exiting when it is available for use. If the printer is not accepting jobs, the program should exit with a non-zero exit code.

The following is a sample printcap entry, showing how the `check_idle` facility can be used.

    pr:
      :lp=laserjet%9100
      :check_idle=/usr/local/filters/remote_check lp@laserjet
      :if=/usr/local/filters/ifhp

The following perl program shows how to generate a query to the remote printer by simulating an `lpq` query and checking for returned status.

    #!/usr/local/bin/perl
    # Usage:
    #  remote_check printer@host[%port] [-options]
    #   -Tflag[,flags]*
    #  flag
    #    debug  - turns debugging on
    #    long   - use long status format
    #
    # query the remote printer whose name is passed on the command line
    #
    # Note that -Txxx options are passed AFTER the printer
    use English;
    use IO::Socket;

    my $JSUCC = 0;
    my $JABORT = 33;
    my $JNOSPOOL = 38;
    my $JNOPRINT = 39;

    my $debug = 0;
    my $optind;

    # pull out the options
    my($key,$value,$opt,$long,$opt_c);

    $printer = $ARGV[0];

    for( $i = 1; $i < @ARGV; ++$i ){
        $opt = $ARGV[$i];
        print STDERR "XX opt= $opt\n" if $debug;
        if( $opt eq '-c' ){
            $opt_c = 1;
        } elsif( ($key, $value) = ($opt =~ /^-(.)(.*)/) ){
            if( $value eq "" ){
                $value = $ARGV[++$i];
            }
            ${"opt_$key"} = $value;
            print STDERR "XX opt_$key = " . ${"opt_$key"} . "\n" if $debug;
        } else {
            $optind = $i;
            last;
        }
        print STDERR "XX opt_P = $opt_P\n" if $debug;
    }

    $long = 0;  # short

    if( defined($opt_T) ){
        print STDERR "XX CHECK_REMOTE opt_T=$opt_T\n" if $debug;
        if( $opt_T =~ /debug/ ){
            $debug = 1;
        }
        if( $opt_T =~ /short/ ){
            $long = 1;
        }
        if( $opt_T =~ /long/ ){
            $long = 0;
        }
    }

    print STDERR "XX CHECK_REMOTE " . join(" ",@ARGV) . "\n" if $debug;

    if( !defined($printer) or $printer =~ /^-/ ){
        print STDERR "$0: no printer value\n";
        exit( $JABORT );
    }

    while( checkstatus( $printer, $long ) ){
        print STDERR "XX CHECK_REMOTE sleeping\n" if $debug;
        sleep(10);
    }

    exit $JSUCC;

    sub checkstatus {
        my ($printer,$long) = @_;
        my ($remote,$port);
        my ($count, $socket, $line);

        if( $long ){
            $long = 4;
        } else {
            $long = 3;
        }
        if( $printer =~ /@/ ){
            ($printer,$remote) = $printer =~ m/(.*)@(.*)/;
        }
        $remote="localhost" unless $remote;

        if( $remote =~ /%/ ){
            ($remote,$port) = $remote =~ m/(.*)%(.*)/;
        }
        $port = 515 unless $port;
        print STDERR "XX CHECK_REMOTE remote='$remote',"
            . " port='$port', pr='$printer', op='$long'\n" if $debug;

        $socket = getconnection( $remote, $port );

        $count = -1;
        # send the command
        printf $socket "%c%s\n", $long, $printer;

        while ( defined( $line = <$socket>) && $count < 0 ){
            chomp $line;
            print STDERR "XX CHECKREMOTE '$line'\n" if $debug;
            if( $line =~ /printing disa/ ){
                print STDERR "XX CHECKREMOTE printing disable\n" if $debug;
                exit $JNOPRINT;
            } elsif( $line =~ /spooling disa/ ){
                print STDERR "XX CHECKREMOTE printing disable\n" if $debug;
                exit $JNOSPOOL;
            } elsif( $line =~ /([0-9]*)\s+job.?$/ ){
                $count = $1;
                print STDERR "XX CHECKREMOTE $count jobs\n" if $debug;
            }
        }
        close $socket;
        if( $count < 0 ){
            print STDERR "CHECKREMOTE cannot decode status\n";
            exit $JABORT;
        }
        return $count;
    }

    sub getconnection {
        my ($remote,$port) = @_;
        my ($socket);
        print STDERR "XX CHECK_REMOTE remote='$remote', port=$port\n" if $debug;
        $socket = IO::Socket::INET->new(
            Proto => "tcp",
            PeerAddr => $remote,
            PeerPort => $port,
            );
        if( !$socket ){
            print STDERR "CHECK_REMOTE IO::Socket::INET failed - $!\n";
            exit $JABORT;
        }
        $socket->autoflush(1);
        $socket;
    }

The example of the previous section can be modified now so that it uses the `check_idle` facility. The master queue will send jobs only to the server queue queues which report idle status.

    laser1|pi1|Room 1359 LaserWriter #1
        :server:check_idle=/usr/local/lib/filters/remote_check pr@laser1
        :lp=laser1%9100
        :tc=@commonlaser
    laser2|pi2|Room 1359 LaserWriter #2
        :server:check_idle=/usr/local/lib/filters/remote_check pr@laser1
        :lp=laser2%9100
        :tc=@commonlaser

### Using a router filter

A router filter allows you to re-route jobs in a dynamic way. For details, see `routing.`

Lars Anderson <`lsa@business.auc.dk`> supplied this example (slightly edited):

This script will attempt to distribute print jobs evenly on 2 printers hpl5a and hpl5b when sending to hpl5bounce.

    hpl5bounce|for PLP/LPRng software - network based HP Jetdirect card:
            :lf=log.hpl5
            :lpr_bounce
            :lp=hpl5b@localhost
            :router=/usr/local/admscripts/bouncer.pl
    hpl5a|for PLP/LPRng software - network based HP Jetdirect card:
            :af=acc.hpl5a:
            :lp=hpl5a%9100:sd=/var/spool/lpd/hpl5a:
            :lf=log.hpl5a:
            :tc=@hplcommon
    hpl5b|for PLP/LPRng software - network based HP Jetdirect card:
            :af=acc.hpl5b:
            :lp=hpl5b%9100:sd=/var/spool/lpd/hpl5b:
            :lf=log.hpl5b:
            :tc=@hplcommon
    # Common settings
    @hplcommon:
            :rw:sh:ps=status:
            :fx=flp:
            :if=/usr/local/lib/filters/ifhp -Tbanner=on
            :of=/usr/local/lib/filters/ofhp -Tbanner=on

The perl script `bouncer.pl` looks like this:

    #!/usr/bin/perl
    #
    # Script for printjob loadsharing
    #
    #                                 29/5-97 Lars Anderson
    #
    # Printqueues to check
    $printer1="hpl5a\@localhost";
    $printer2="hpl5b\@localhost";
    # obtain number of jobs in each printqueue
    $lpq1=`/usr/local/bin/lpq -s -P$printer1`;
    $lpq2=`/usr/local/bin/lpq -s -P$printer2`;
    $lpq1=~ (/(\d+) jobs?/); $numjobs1=$1;
    $lpq2=~ (/(\d+) jobs?/); $numjobs2=$1;
    if ($numjobs1 == 0) {
        print "dest $printer1\nCA\nend\n";
        exit;
    }
    if ($numjobs1 > $numjobs2) {
        print "dest $printer2\nCA\nend\n";
        exit;
    }
    print "dest $printer1\nCA\nend\n";

## 5.15 The Missing Details

Options used:

- `printcap_path=`printcap file locations
- `lpd_printcap_path=`additional server printcap file locations
- `nw` NFS spool directory

The LPRng software uses a greatly simplified set of printcap conventions. This section discusses the details of the printcap database. LPRng can use vintage (i.e.- Berkeley LPR) format printcap files; use the checkpc program to make sure they are totally compatible with LPRng (see checkpc man page, README.install, DOC/Intro).

The client programs (LPR, LPRM, LPQ, LPC) do not need access to a printcap database, but will use it if available. The -Pprinter@host option or PRINTER environment variable specifies the printer and LPD host; the LPD server does all of the various spool queue activities. The client programs send requests and/or jobs to the LDP server which carries out all activity. If no printcap is available and the host is not specified, a default host value is provided.

If a printcap database is desired, then it is obtained as follows. First, the `printcap_path` and `lpd_printcap_path` configuration information (see lpd.conf(5)) specifies where client and server programs find printcap information. The client programs use `printcap_path`; `lpd` uses both `printcap_path` and `lpd_printcap_path`. All files are read and the printcap entries are extracted in order from the files. Later printcap information overrides previous information in the files.

The common defaults for the printcap locations are:

    printcap_path          /etc/printcap:/usr/etc/printcap:\
                                /var/spool/lpd/printcap.HOSTNAME
    lpd_printcap_path      /etc/lpd_printcap:/usr/etc/lpd_printcap

When the `lpd` server gets a printcap entry, if the printcap entry obtained has a spool directory and the spool directory has a `printcap` file in it, then this file is assumed to contain additional printcap information, and the server will read and append this information to the obtained printcap information. The `nw` (NFS mounted or network file system) flag will suppress this operation, as there is a security loophole when obtaining information from an NFS mounted system.

The most common method of printcap information distribution is to have a master printcap file shared or distributed to all system. This usually has only the printer name and lpd host specified in the printcap entries, as shown below.

        ----- /etc/printcap on clients and server -------
        #parallel attached DUMB printer
        pr1|dumb
            :lp=pr1@taco.astart.com
        # server information
        pr2|postscript
            :lp=pr2@taco.astart.com
        pr3|laserjet
            :lp=pr3@taco.astart.com
        @common|common code for printers
            :if=/bin/filter
            :of=/bin/filter
        @morecommon|show the configuration expansion
            :sd=/var/spool/lpd/%P

        realpr:tc=@common:tc=@morecommon

A careful study of the above example will discover the following features of the LPRng printcap structure.

1. Lines ending with a \ indicate continuation to the next line. In practice, the \ is replaced with space(s) when line joining is done.
2. Blank lines and lines whose first nonwhitespace character is a `#` are ignored, except if it follows a continuation line. (Which makes sense.)
3. All leading and trailing whitespace on a line are removed.
4. A printcap entry consists of a name, 0 or more aliases, and data entries.
   - name starts with an alphabetic character; dummy entries can start `_`, `@` or `.`
   - alias starts with a `|` followed by the alias
   - fields or data entry starts with `:` followed by the entry
5. Field or data entry
   name - main or cannonical name for printcap entry
   `|`name - alias name for printcap entry
   `:`key - set the key to ON (1)
   `:`key`@` - set the key to OFF (0)
   `:`key`#`nnn - set the key to nnn, where nnn follows C language conventions
   `:`key`=`string - set the key to the string value to end of line
6. Printcap entries whose cannonical name starts with `_`, `@`, or `.` (period) (eg.- `@`name) are treated like dummy entries. They can be referenced with `:tc=`entry`:`, but will be ignored otherwise.
7. The `tc=f1:tc=f2:...` acts similar to a file inclusion operator, but substitutes printcap entries. The specified tc entries are logically append to the end of the current printcap entry, and the appended information will override the previous information. Note that you can have multiple `:tc:` entries.
8. key`=`value.`%`X
   a selected set of `%`X values are expanded when the printcap entry is used by the client or server program. The following values are expanded:
   P - printcap cannonical or main name
   H - Fully Qualified Domain Name for host
   h - short name for host
   R - Fully Qualified Domain Name for remote host host
   r - short name for remote host host
9. The `oh` entry specifies that a particular printcap entry can only be used by a host with a matching host name or IP address. See Master Printcap Files for details.
10. The `server` entry specifies that a particular printcap entry can only be used by the lpd server, and is ignored by other programs. See Shared Printcap Files for details.

Printcap information is extracted in order from the printcap files, and later information for printcap entries overrides earlier ones.

The `%`X substitution is especially useful when most of the information for a set of printers is common or identical. This can be placed in a printcap entry and referenced with the `tc` operator. As shown in the example, by making the spool directory name depend on the cannonical printcap name, it simplifies management of the printer.

### Spool (Control) Directory Printcap File

You can put a printcap file in a spool queue directory. This file is only consulted by the LPD server when performing operations on a spool queue. It allows you to put information particular to a spool queue in well controlled location.

The `server` tag and `oh` options have rendered this facility obsolete, and it may be removed in later releases.

### Separate Printcap Files for LPD

Since only the LPD server uses the `/etc/lpd_printcap` or `/usr/etc/lpd_printcap` file, you can place server specific information there. This allows you to have a common printcap file for clients and an additional one for the lpd servers. You may have to modify the lpd.conf file `lpd_printcap_path` entry to specify the desired file.

The `server` and `oh` options have rendered this facility obsolete and it may be removed in future releases of LPRng.

### Printcap Entry all

The 'all' printcap entry is reserved to provide a list of all printers available for use by the spooling software. This was intended to be used with systems that did not have ways to provide a wildcard search of the printcap database. The 'all' printcap entry has the form:

    all:all=pr1,pr2,...

The LPRng software will use the individual entries of the printer list and request additional printcap information if necessary.

### More Example Printcap Entries

The following printcap entries show the formats, and have some additional comments about fields in the printcap file.

    #
    #  NOTE:
    #  Use the lpf filter (supplied with LPRng) or the of and if filter.
    #  Banners will be printed using the lpbanner
    #  program, supplied with LPRng.  You can also create your own banner
    #  program and specify it as the banner printer (printcap :bp: entry.)
    #  Put -$ at the start of a filter or program specification to suppress
    #  additional command line options. (see lpd.conf).
    #  Note: some PC's LPR packages use the v format instead of the l or f format
    #
    # This is the VINTAGE form of printcap,  with trailing \ to extend information
    # to next line.  Note the -$ to suppress adding options to command line
    # typical dump printer, no banner, parallel port
    pr1|dumb- no banner:\
        :sh:lp=/dev/lpr1:sd=/usr/spool/lpd/pr1:\
        :fx=flpv:\
        :af=acct:lf=log:\
        :if=/usr/local/bin/lpf:\
        :vf=-$ /bin/cat
    # dumb with banner - note that lprng will use the default banner program
    #  /usr/local/bin/lpbanner to generate full banner
    # Note: we use the standard LPRng printcap format
    pr1b|dumb- banner
        :lp=/dev/lpr1:sd=/usr/spool/lpd/pr1        #<- sh deleted
        :fx=flpv
        :af=acct:lf=log
        :of=/usr/local/bin/lpf
        :if=/usr/local/bin/lpf
        :vf=/usr/local/bin/lpf -c
    # common printer information:
    # we define a @common entry
    @filter|printcap filter information
        :of=/usr/local/bin/lpf
        :if=/usr/local/bin/lpf
        :vf=/usr/local/bin/lpf -c
    # dumb with user banner - bp specifies banner printer
    #  If we wanted the banner at the END of the job, we would use
    #  :hl: (header last) flag.
    #  We can also have headers at start and end, using the
    #  be={banner printer} and bs={banner printer} overrides
    #  Note: -$ suppresses adding command line options
    pr1b|dumb- user supplied banner
        :lp=/dev/lpr1:sd=/usr/spool/lpd/pr1
        :fx=flpv
        :af=acct:lf=log
        :bp=/usr/local/lib/my_banner_printer
        :tc=@filter
    #serial attached PostScript printer
    # Note that fields can have terminating colons (:)
    # You can put comments into this printcap with this form
    # Note that the of filter does accounting
    pr2|postscript - no banner
        :rw:sh:lp=/dev/ttya:sd=/usr/spool/lpd/pr2
        :sy=9600 -raw -parenb cs8 crtscts
        :af=acct:lf=log:ps=status
        # only allow the following formats
        :fx=flpv
        # filters
        :tc=@filter
    #serial attached PostScript printer with psof created banner
    pr2|postscript - psof will expand short banner
        # Note: sb is short banner format
        # psof filter recognizes this and produces a fancy banner
        # from the input
        :rw:sb:lp=/dev/ttya:sd=/usr/spool/lpd/pr2
        :sy=9600 -echo -crmod -raw -oddp -evenp pass8 cbreak ixon
        :af=acct:lf=log:ps=status
        # only allow the following formats
        :fx=flpv
        # filters
        :tc=@filter
    #serial attached PostScript printer with user created banner
    pr2|postscript - psof will expand short banner
        # Note: sb is short banner format
        # psof filter recognizes this and produces a fancy banner
        # from the input
        :rw:sb:lp=/dev/ttya:sd=/usr/spool/lpd/pr2
        :sy=9600 -echo -crmod -raw -oddp -evenp pass8 cbreak ixon
        :af=acct:lf=log:ps=status
        # only allow the following formats
        :fx=flpv
        # filters
        :tc=@filter
    # parallel attached Laser Jet
    # Note that fields do not need terminating colons
    #
    pr3|laserjet
        :rw:sh:lp=/dev/lp:sd=/usr/spool/lpd/pr3
        :af=acct:lf=log:ps=status
        # only allow the following formats
        :fx=flpv
        #filters
        :if=/usr/local/lib/CTI-Print/bin/ifhp -Tstatus=off
        :of=/usr/local/lib/CTI-Print/bin/ofhp -Tstatus=off
        :vf=/usr/local/lib/CTI-Print/bin/ifhp -c -Tstatus=off
    # printcap file for pr4
    # PostScript via JetDirect card, IP address pr4, port 9100.
    # Note: some PC's LPR packages use the v format for their jobs
    #
    pr4|network
        :rw:sh:lp=pr3%9100:sd=/usr/spool/lpd/pr4
        :af=acct: :lf=log: :ps=status
        # only allow the following formats
        :fx=flpv
        #filters
        :if=/usr/local/lib/CTI-Print/bin/ifhp
        :of=/usr/local/lib/CTI-Print/bin/ofhp
        :vf=/usr/local/lib/CTI-Print/bin/ifhp -c

### PC-NFS Print Spooler

If you are using PC-NFS to do print spooling you have several security loopholes exposed. You must modify the permissions on the spool directory to allow other users to access it and place jobs into the directory. Printcap and other control information by default is placed in the spool directory, and can be easily modified by malicious users. To reduce this risk, the `:cd:` (control directory) entry is used to specify a directory to hold sensitive control information. For example

    #/etc/lpd_printcap
    # PCNFS Spooler
    #
    pr7
        :lp=pr7@printserver
        :bq=pr1@printserver
        :sd=/usr/spool/pcnfs/pr7
        :cd=/usr/spool/lpd/pr7

This printcap entry will implement a simple 'bounce queue', in which jobs are stored temporarily and then transferred to another spool queue, and is the recommended way to support PC-NFS printing.

## 5.16 Management Strategy for Large Sites

One very effective way to organize print spooling is to have a small number of print servers running a `lpd` daemon, and to have all the other systems send their jobs directly to them. By using the above methods of specifying the printer and server host you eliminate the need for more complex management strategies.

However, you still need to inform users of the names and existence of these printers, and how to contact them. One method is to use a common `/etc/printcap` file which is periodically updated and transfered to all sites. Another method is to distribute the information using the NIS or some other database. LPRng has provided a very flexible method of obtaining and distributing database information: see Using Programs To Get Printcap Information for details.

## 5.17 Using Programs To Get Printcap Information

In the `lpd.conf` file you can specify:

    printcap_path=|program

This will cause the LPRng software to execute the specified program, which should then provide the printcap information. The program is invoked with the standard filter options, and has the name of the printcap entry provided on `STDIN`. The filter should supply the printcap information on `stdout` and exit with a 0 (success) error code. By convention, the printcap name 'all' requests a printcap entry that lists all printers.

This technique has been used to interface to the Sun Microsystem NIS and NIS+ databases with great success. By having the invoked program a simple shell script or front end to the `nismatch` or `ypmatch` programs, the complexity of incorporating vendor specific code is avoided.

### How to use NIS and LPRng

This note is based on material sent to the `lprng@iona.ie` mailing list by Paul Haldane `<paul@ucs.ed.ac.uk>`.

     # From: Paul Haldane <paul@ucs.ed.ac.uk>
     # To: lprng@iona.ie
     # Subject: Re: Problem using plp with NIS
     # Sender: majordomo-owner@iona.ie
     # Precedence: bulk
     # Reply-To: lprng@iona.ie
     # Status: RO
     #

We generally don't use NIS for printcap files (we've moved to hesiod) but I can show you what we've done in the past.

The input to NIS is a normal printcap file:

    # Classical printcap entry
    lp23a|lp23|lp|main printhost printer - KB, EUCS front Door:\
            :lp=lp23a@printhost:\
            :sd=/usr/spool/lpr/lp23a:

    #lprng printcap entry
    lplabel|lpl|TEST - Labels printer:
            :lp=:rm=printhost:rp=lplabel:
            :sd=/usr/spool/lpr/lplabel:
            :rg=lpadm:mx#1:

To build the NIS printcap.byname map we add the following to the NIS makefile (along the other bits and pieces that the makefile needs to know about a new map).

    PRINTCAP=$(DIR)/printcap
    #PRINTCAP=/etc/printcap
    # warning : [  ] is actualy [<space><tab>] in the script
    printcap.time: $(PRINTCAP) Makefile
      if [ -f $(PRINTCAP) ]; then \
        sed < $(PRINTCAP) \
          -e 's/[   ][  ]*$$//' -e '/\\$$/s/\\$$/ /' \
        | awk '$$1 ~ /^#/{next;} $$1 ~ /^[:|]/ {printf "%s", $$0; next;} \
            {printf "\n%s", $$0 }' \
        | sed -e 's/[   ]*:[  ]*:/:/g' -e 's/[  ]*|[  ]*/|/g' \
          -e '/^[   ]*$$/d' > .printcap.$$$$; \
        cat .printcap.$$$$; \
        if [ $$? = 0 -a -s .printcap.$$$$ ]; then \
          awk <.printcap.$$$$ '{ FS=":"; OFS="\t"; } { \
              n = split($$1, names, "|"); \
              for (i=1; i<=n; i++) \
                  if (length(names[i]) > 0 \
                  && names[i] !~ /[ \t]/) \
                      print names[i], $$0; \
          }' | $(MAKEDBM) - $(YPDBDIR)/$(DOM)/printcap.byname; \
          awk <.printcap.$$$$ '{ FS=":"; OFS="\t"; } { \
              n = split($$1, names, "|"); \
              if (n && length(names[1]) > 0 && names[1] !~ /[ \t]/) \
                  print names[1], $$0; \
          }' | $(MAKEDBM) - $(YPDBDIR)/$(DOM)/printcap.bykey; \
          rm -f .printcap.$$$$; \
          touch printcap.time; echo "updated printcap"; \
        fi \
      fi
      @if [ ! $(NOPUSH) -a -f $(PRINTCAP) ]; then \
          $(YPPUSH) printcap.byname; \
          $(YPPUSH) printcap.bykey; \
          touch printcap.time; echo "pushed printcap"; \
      fi

To specify that you want YP database rather than file access, use the following entry in your `/etc/lpd.conf` file:

    printcap_path |/usr/local/lib/pcfilter

Put the following shell script in /usr/local/lib/pcfilter

    #!/bin/sh
    #/usr/local/lib/pcfilter
    read key
    ypmatch "$key" printcap.byname

### How to use NIS and LPRng - Sven Rudolph

     Date: Wed, 11 Sep 1996 00:11:02 +0200
     From: Sven Rudolph <sr1@os.inf.tu-dresden.de>
     To: lprng@iona.ie
     Subject: Using :oh=server: with NIS

When I use a cluster-wide printcap, two entries for each printer will appear, e. g.:

    ---------- start of /etc/printcap snippet
    lp1
     :lp=lp1@server
    lp2
     :lp=lp2@server
    lp1
     :server:oh=servername
     :sd=/var/spool/lpd/lp1
     :lp=/dev/lp1
     :sh:mx#0
    ---------- end of /etc/printcap snippet

When I create a NIS map out of this, the printer name is used as a key and must be unique. So NIS' makedbm decides to drop all but the last entry for each printer. This makes the printer on the clients unavailable. I solved this by a hack where the second entry is called lp1.server and the NIS client script has to request the right entry.

1. Assumptions

   Perl is available at the YP server in /usr/bin/perl . A Bourne Shell is available at all clients in /bin/sh The printcap that is to be exported is in /etc/printcap . The printcap is written in the new format.

   In the examples the printer is called lp1 .

2. Add the following to your YP Makefile (/var/yp/Makefile) on the YP server :

       ---------- start of /var/yp/Makefile snippet
       PRINTCAP  = /etc/printcap
       printcap: $(PRINTCAP)
           @echo "Updating $@..."
           $(CAT) $(PRINTCAP) | \
               /usr/lib/yp/normalize_printcap | $(DBLOAD) -i $(PRINTCAP) \
               -o $(YPMAPDIR)/$@ - $@
           @if [ ! $(NOPUSH) ]; then $(YPPUSH) -d $(DOMAIN) $@; fi
           @if [ ! $(NOPUSH) ]; then echo "Pushed $@ map." ; fi
       ---------- end of /var/yp/Makefile snippet

   (These lines are for Debian GNU/Linux, other systems might require other modifications)

3. Install the programs `match_printcap` and `normalize_printcap` to `/usr/lib/yp`. normalize_printcap is only required on the YP server. The `normalize_printcap` processes only the LPRng printcap format.

       ---------- start of /usr/lib/yp/normalize_printcap
       #! /usr/bin/perl
       $debug = 0;
       $line = "";
       $new = "";
       while (<>) {
           chomp;
           next if ( /^\s*\#.*/ );
           s/^\s*$//;
           next if ( $_ eq '' );
           print "new: " . $_ . "\n" if $debug;;
           if (/^\s/) { # continuation line
               $line = $line.$_;
               print "continued: $line\n" if $debug;
               next;
           } else {
               $line =~ s/\s+\:/:/g;
               $line =~ s/\:\s+/:/g;
               $line =~ s/\:\s*\:/:/g;
               print "line: $line\n" if $debug;
               push(@lines, $line) if $line;
               $line = $_;
           }
       }
       $line =~ s/\s+\:/:/g;
       $line =~ s/\:\s+/:/g;
       $line =~ s/\:\s*\:/:/g;
       push(@lines,$line) if $line;
       @lines = sort(@lines);
       foreach $line (@lines) {
           ($printers) = split(/\:/,$line);
           @printers = split(/\|/,$printers);
           foreach $printer (@printers) {
             $num{$printer}++;
             push(@allprinters,$printer);
             print "allprinters: @allprinters\n" if $debug;
             print $printer."_".$num{$printer}."\t$line\n";
           }
       }
       @pr = keys %num;
       print "printers @pr\n" if $debug;
       if ($#allprinters >=0) {
           print "all_1\tall:all=".join(",",@pr)."\n";
       }
       ---------- end of /usr/lib/yp/normalize_printcap

   The result of processing the sample printcap file is:

       lp1_1 lp1:lp=lp1@server
       lp1_2 lp1:server:oh=servername:sd=/var/spool/lpd/lp1:lp=/dev/lp1:sh:mx#0
       lp2_1 lp2:lp=lp2@server
       all_1 all:all=lp1,lp2

   Observe that each of the real printer entries has a key consisting of the printer name with a numerical suffix. This leads to the following method of extracting the printcap information using `ypmatch`:

       ---------- start of /usr/lib/yp/match_printcap
       #!/bin/sh
       read p
       n=1
       while ypmatch "${p}_${n}" printcap 2>/dev/null; do
           n=`expr $n + 1`
       done
       ---------- end of /usr/lib/yp/match_printcap

4. Now test the YP arrangement:

       $ cd /var/yp; make # this should create the printcap map
       $ ypcat printcap # should provide the whole normalized printcap
       $ echo lp1 |/usr/lib/yp/match_printcap # yields lp1 printcap

5. Add the printcap_path entry to `/etc/lpd.conf`:

       printcap_path=|/usr/lib/yp/match_printcap

6. Test the use of the printcap path entry:

       $ lpq -Plp1 # shows the status of lp1

7. Restart the lpd server and check to see that it accesses the right printcap information. Use the same `lpq` command, and then try `lpc printcap lp1`.

## 5.18 The Record Queue Name qq and force_queuename flags

Options used:

- `qq` Insert queue name into control file
- `use_queuename` (alias for qq)
- `force_queuename=` Queuename to be used

The printcap information consists of the printer name and aliases; when a job is spooled to a printer alias, it is actualy spooled to the main printer entry.

The `qq` use queuename option or its alias `use_queuename` tells LPRng to record the queue name that a job was queued to, and make it available to other software for processing. The `force_queuename=...` entry forces this name to be used. This capability has some interesting possibilities, as shown below.

    pr1_landscape|pr1_portrait|pr_raw:lp=pr@host:qq

If a job is printed using `lpr -Ppr1_landscape`, then `pr1_landscape` will be recorded as the spool queue name by the LPRng software.

Later, when the job is processed by a filter, the filter will be invoked with a `-Qpr1_landscape` command line option. The filter can use the name of the queue to enable say, landscape, portrait, or raw orientations.

    john|tom|frank:lp=pr@host:force_queuename=office

This printcap entry forces the queuename to be `office`; this information could be used by a central routing facility to process the information is a suitable manner.

## 5.19 Using the check_for_nonprintable Flag

Options used:

- `check_for_nonprintable` LPR checks for non-printable file
- `ml#` minimum number of printable characters
- `xt` (alias for check_for_nonprintable)

Normally, `lpr` checks an `f` format file for non-printable characters (i.e., escape characters) at the start of the print file. Disabling this check allows you to print executable files, etc., which can cause extreme abuse of your printer.

Disabling can be done on a single printcap basis, or you can do this on a global basis by modifying the configuration information (see lpd.conf).

The `ml` value specifies the number of characters that are to be checked. Clearly, if it is 0, none will be checked.

## 5.20 The fd Forwarding Off Option

Options used:

- `fd` Forwarding off

When the `fd` option is on (default is OFF), the `lpd` server will not accept jobs whose host name in the control file is not the same as one of the hostnames for the host which originates the connection.

This was a wimpy attempt to prevent job spoofing.

## 5.21 The rg Restrict Use to Group Members Option

Options used:

- `rg=`Restricted group list

The `rg` value specifies a list of groups. If this value is present use of a printer or operation is restricted to only users in a particular group.

This was a wimpy attempt to do restrictions on print facilities. The -Ppr@host option overrides this check, unless the `rg` value is put in the LPRng defaults.

However, it does provide a simple tool to have clients do some form of permissions checking that only the `lpd` server could normally do.

## 5.22 The fx Allowed Formats Option

Options used:

- `fx=`supported formats for printing

The `fx` option specifies which formats are supported by a spool queue. The `lpr` program uses these to check if a requested format is supported. The default formats are `fx=flp`, i.e. - the default (normal), binary, and `pr` formats.

If the `lpr -Fx` option is used, the allowed formats are not checked.

## 5.23 Fixing Bad Control Files and Metacharacters

RFC1179 defines a simple protocol and standard for print jobs to be interchanged between print spooling systems. Unfortunately, there were some major mistakes in not specifying the exact form that text would take when placed in the control file.

In addition, there are some simple coding errors that have been made, but due to their wide distribution in major vendors software, need to be accommodated. See reverse_lpq_format for an example.

### Defective RFC1179 Implementations

Options used:

- `fix_bad_job` fix bad job
- `safe_chars=`additional safe characters for control file

Most printer (or print server box) manufacturers totally ignore the details of the RFC1179 protocol and simply accept the data files for printing, disregarding the control file until they need to print a banner or provide status information.

At this point, you suddenly discover that all sorts of little details will cause horrible problems. For example, the use of non-ASCII characters (i.e. - values are 128-255) in the J (job) line of a control file has been known to crash one network interface card in such a manner that a power-up is needed to restart the printer.

Also, as an exercise for the reader, here is another little gem. If you send one particular RFC1179 compatible print spooler a control file with a character whose value is 255 (i.e. 0xFF), the job will never get printed, and there is a mysterious diagnostic on the console:

    unexpected end of input

This is due to the fact that the 0xFF eight bit value is getting sign extended to a 16 bit value 0xFFFF, which just turns out to be -1, or the error indication from a read.

### OS/2

For various reasons, some versions of the OS/2 `lpd` print spooler have decided to make the control file and data file names have different formats. This can cause `LPRng` to suspect that somebody is trying to clobber other users jobs, and it will normally reject such jobs.

In addition, the OS/2 spooler does not follow RFC1179 correctly, and truncates the data and job file protocol exchange.

### Serious Security Loophole

Finally, there is the subtle and nasty problem with some print filters that are not meta-char-escape proof. For example, suppose that a user decided to spool a job as follows:

    lpr '-J; rm -rf /*;' /tmp/a

This would create a job file with the line:

    J `rm /etc/passwd; echo Job;`

The job would get printed on a printer with the following printcap:

    pr:sd=/...
      :if=/usr/local/hack

And of course we have `/usr/local/hack` (yes, this is a BAD example, so we won't start pointing out all the things):

    #!/bin/sh
    while [ -n "$1" ] ; do
            case "$1" in
            -J  )  shift; args="$args -M$1";;
            esac;
            shift;
    done;
    # reformat the command line
    eval /usr/local/realfilter $args

The observant reader will notice that the above line gets expanded to:

    eval /usr/local/realfilter -M`rm /etc/passwd; echo Job;`

The interesting thing to observe is that the `realfilter` will probably execute correctly, while the password file will magically vanish.

### Using the fix_bad_job Option

Several microprocessor operating systems have decided to use extended fonts for information in the control file. While this is obnoxious, it is not serious. It will cause problems when trying to print messages on consoles, etc.

In order to prevent such problems, LPRng ruthlessly purges all characters but upper and lower case letters, spaces, tabs, and `-_.@/:()=,+-%` from the control file, replacing suspicious characters with '_'.

However desirable it may to detect when such obnoxious behavior is taking place, it is usually more desirable to replace suspicious characters with safe ones and proceed with processing the job. If the `fix_bad_job` configuration or printcap option is 0 (false) then when a suspicious character is spotted the job processing is aborted. If it is 1 (true), then the characters are silently purged and job processing continues. In addition, if the names used for control and data files are bogus or poorly formed, then they are renamed to something sensible.

For some installations, the default set of safe characters may be overly restrictive. For example, vintage software may generate files with `#` characters in the `J` line of the control file. The replacement of this character may cause other things to stop working.

The `safe_chars` option allows the user to specify an additional set of safe characters in the `lpd.conf` configuration file(s). For example, `safe_chars=#"` would allow the `#` and `"` characters to appear in the control file.

### Using the bk Option and Control File Filters

Options:

- `bk` Berkeley compatible control file
- `control_filter=`Control file filter

One of the more serious problems is when a print spooler (LPR) program does not generate print jobs in a manner compatible with a remote system.

While LPRng performs checks for improper implementations of RFC1179, it will try to accept a job, even under the most severe abuse of the protocol. However, other spoolers are not so forgiving.

Some spoolers require that the contents of the control file be in exactly the order that the original 1988 BSD LPR software generated them. While some entries can be missing, all the entries present in the file must be in an explicit order.

The `bk` (Berkeley LPD compatible control file) option causes LPR and LPD to reformat the control file, removing objectionable entries. The control file of a job being sent to a remote printer will have its control file entries restricted to letters in (and the same order) as HPJCLIMWT1234.

However, there are some very odd commercial implementations that require more information than is present. To assist with this, the `control_filter` option can be used. This specifies a program that will process the control file before it is sent to a remote destination. See Filters for details on filter operation, and Control Filters for more information.

The `control_filter` program is run with the standard set of filter options. STDIN is attached (read/write) to the control file and the filter STDOUT will be used as the control file value sent to the remote host.

The `control_filter` can rewrite the control file, modify the names and formats of the data files, or perform other changes. Here is a small snip of PERL code that shows how to rewrite the control file:

    # you need to get PERL to do a 'dup' call on FD 0
    $status = 0;
    @cf_lines = <STDIN>;
    # mess about with the control file
    foreach $line (@cf_lines) {
       # or whatever you want
       print STDOUT $line;
    }
    exit $status;

The exit code of the `control_filter` is used to determine whether to proceed in processing. See Errorcodes for details.

Also, see Control Filters for more information.

## 5.24 Maximum Copies

Options used:

- `mc#`maximum copies
- `sc` suppress multiple copies

The `mc` value specifies the maximum number of copies of a job that can be printed on a printer using the `lpr -Knn` or `lpr -#nn` option.

The `sc` boolean cause LPR to reject requests to print multiple copies of a file.

## 5.25 The mi Minimum Spool Queue Space Option

Options used:

- `mi#`minimum spool queue space (Kbytes)
- `minfree#`alias for mi

If this value is non-zero, then the `lpd` server checks to see that there is the specified number of bytes of file space available before transferring a job.

## 5.26 Debugging

Options used:

- `debugging=`debugging options
- `full_time` full or extended time format
- `ms_time_resolution` millisecond time resolution
- `syslog_device=`syslog alternative device
- `use_date` put date information in control file
- `use_info_cache` cache printcap and other information

The LPRng software has a very powerful debugging capability. Since most printing problems occur on remote systems where it is impossible to run debuggers, and since most systems do not do core dumps of SETUID ROOT programs, the LPRng software provides a very verbose set of log file trace messages.

First, serious errors or other information are logged using the syslog() facilities. If these are not present on a system, then the messages are logged to the device specified by `syslog_device`.

For client programs, the debugging options are specified on the command line and output is directed to STDERR. For the `lpd` server, debugging commands can be specified on the command line OR as the `db=options` printcap value. Output is directed to the log file (`lf` option value, default log).

A typical debug entry has the format `2,network+1,database`. This sets the general debugging level to 2, network debugging to 1 and the database debugging level to the default. The following debugging options and levels are supported.

- nnn - general purpose debugging level
- network - network debugging
- database - database debugging
- receive - job or command reception debugging
- print - detailed job printing debugging

The `full_time` flag forces the logging and other information which has timestamps to have a full (year, month, day, etc.) timestamp. The `ms_time_resolution` flag forces millisecond time resolution in the time stamp. The `use_date` flag forces a date value to be placed in a control file if there is none.

The `use_info_cache` (default ON) causes `lpd` to cache printcap and configuration information. This is desirable except when trying to change values in printcap files and test the results. By using `use_info_cache@` in the configuration information, you can get immediate responses. Also, see lpc reread for another method.

## 5.27 LPD Specific

Options used:

- `ipv6` use IPV6 Network facilities
- `lockfile=`lpd server lock file
- `logfile=`lpd server log file
- `report_server_as=`server name for status reports
- `spool_dir_perms#`spool directory permissions
- `spool_file_perms#`spool file permissions
- `spread_jobs#`job number spread

These options are usually LPD specific. For example, the `ipv6` specifies that the IPV6 protocol, rather than IPV4 will be used. In future versions, this may not be necessary.

The `lockfile` and `logfile` specify the location of the lock file and the log file used by the `lpd` server.

The `spool_dir_perms` and `spool_file_perms` (default 0700 and 0600 respectively) values are the (numeric) permissions for the spool directory and spool files.

The `spread_jobs` option is obsolete. The `spread_jobs` option was a desperation fix to handle difficulties with the arrival of a large number of jobs with the same or close job number. The LPD server would fork children, each of whom tried to lock the job files. The spread value randomly chose a new number in the range about the original job number. However, it is still preserved for legacy systems which still have problems with file locking.

The `report_server_as` option allows an administrator to masquerade a server with another name. This could be useful if various load sharing activities are being carried out, or if there are problems reconfiguring DNS to cause the correct server name to be reported.

## 5.28 Legacy Compatibility

The following arguments have been provided for compatibility with legacy systems.

### The allow_duplicate_args Option

Options used:

- `allow_duplicate_args` allow lpr to have duplicate arguments

Some users would like duplicate LPR and LPRM command line arguments to override earlier ones, i.e. - `lpr -a x -a y` should be equivalent to `lpr -a y`

The `allow_duplicate_args` option allows the various client programs to have duplicate arguments. The last specified argument on the command line will override previous values.

### The break_classname_priority_link Option

Options used:

- `break_classname_priority_link` classname and priority can differ
- `classname_length#` maximum length of classname in control file

By default the class name and the job priority are identical. The `break_classname_priority_link` flag breaks this link, and the class can be specified separately from the priority.

Also, the maximum classname size specified by RFC1179 is 32 characters; the `classname_length#nnn` (default 31) allows a longer classname (up to 127 characters) to be used.

### The reverse_lpq_format Option

Options used:

- `reverse_lpq_format=` reverse LPQ status format for specified remote systems

Various Solaris and other System V implementations support an RFC1179 interface to remote printers. Unfortunately, there is a problem in that when they send a status request, the status format is reversed. That is, when LONG status format is wanted, they send SHORT, and vice versa.

The `reverse_lpq_format=` specifies a list of printers or IP addresses for which the `lpd` server will return LONG status when SHORT is requested, and vice versa. For example:

    reverse_lpq_format=*.eng.com,130.192.0.0/16

will cause hosts whose Fully Qualified Domain Name (FQDN) ends in `eng.com` or from subnet `130.192.0.0` to have reversed status returned.

### The return_short_status and short_status_length Options

Options used:

- `return_short_status=` return short LPQ status for specified remote systems
- `short_status_length#` short LPQ status length in lines

In order to be compatible with non-LPRng printers, some administrators would like `lpd` to return a short or brief status to normal status queries.

The `return_short_status=` specifies a list of printers or IP addresses for which the `lpd` server will return an abbreviated status when LONG status is requested. For example:

    return_short_status=*.eng.com,130.192.0.0/16
    short_status_length#3

will cause hosts whose Fully Qualified Domain Name (FQDN) ends in `eng.com` or from subnet `130.192.0.0` to get only 3 lines of detailed status returned.

### The ignore_requested_user_priority and force_fqdn_host Options

Options used:

- `ignore_requested_user_priority` prevent users from queue jumping
- `force_fqdn_hostname` force FQDN hostname in control file

Some students... um... users... will request a high priority for their job in order to jump the queue of waiting jobs. This option will cause the `lpd` server to ignore the requested user priority. However, the `topq` operation will still be effective.

Similarly, some print spoolers do not put a FQDN host name in their control file. The `force_fqdn_hostname` flag will cause `lpd` to put a FQDN host name in.

## 5.29 Unused Legacy Printcap Options

Options used:

- `co` Cost - passed to filters.

The above option is retained only for compatibility with legacy filter operation. See Filter Command Line Flags for details.

## 5.30 Compatibility with BSD printcap

If you previously had a BSD-style printer spooler, you might be lucky: your printcap will be directly usable by LPRng in many cases, i.e. - LPRng is almost totally backwards compatible with the old BSD printcaps. However, a lot of people have found out the hard way that LPRng is not completely compatible with BSD LPR.

For example, the `fc/fs/xc/xs` flag fields were used to specify serial line options and are no longer supported. The flag fields and their meanings are version and OS dependent and were not portable. We now use an `stty` commmand compatible `ty` or `sy` entry. Both options are synonyms, and the value is a set of stty(1) options. See Converting BSD fc,fs,xc,xs To LPRng sy for details.

There are other items, such as the fact that the keywords used by LPRng can be variable length, not just two letters, and other commenting and formatting conventions which are not supported by the older BSD servers.

Next Previous Contents