LPRng-HOWTO: Filters

Next Previous Contents

## 13. Filters

This section gives an overview of how LPRng uses filter programs, and gives a detailed discussion of how the printcap options and filters interact.

## 13.1 What are filters?

Print filters are one of the most powerful tools in BSD-style printer systems.

In general UNIX terms, a filter is a program that takes its input file(s), does something with it, and sends the result to its standard output. Most UNIX utilities are designed as filters. (But since you are a system manager, you should already know that :))

In the context of a BSD-style print spooler (and also LPRng), the term filter refers to a program that processes file while it is being transferred to a printer.

The filter is executed with STDIN reading from the file to be printed STDOUT to the printer device or a temporary file. STDERR (file handle 2) is redirected to the status file, and file handle 3 to an accounting file or program.

A filter can be as simple as a `LF` to `CR/LF` translator, or it can incorporate a complete accounting system, automatic file type translations, or even redirect the job to another printing system.

As part of the LPRng project, the following filters are supported. The are many others available for use, but are currently not supported.

- lpf a very simple CR/LF or passthrough filter.
- ifhp HP PCL and PJL printer filters

The supported filters and other facilities are available from ftp://ftp.astart.com/pub/LPRng

## 13.2 What are print formats?

Options used:

- `if`, `cf`, `df`, `gf`, `nf`, `of`, `rf`, `tf`, `vf`, X`f`, Filter programs

LPRng has inherited a set of so-called `print formats' from its BSD ancestor. The format was used to specify the type of file that was being printed. The `lpd` server used the print format to select the filter for processing the file. The default format is `f`.

The user can specify the format (i.e., the file type) by giving the appropriate option to `lpr`:

- `-b` or `-l`: Binary (literal) file. No processing should be done. The `l` format is recorded as the file format.
- `-c`: cifplot(1) output.
- `-d`: TeX DVI file.
- `-g`: Output from the plot(3X) routines.
- `-n` or `-t`: (di)troff output.
- `-p`: Text file that should be pre-processed by the `pr` command, and then by the standard text filter.
- `-v`: Benson Varian raster image.

Alternatively, one can also use `-Fx`, where `x` is the format specifier. (E.g., `-Fc` instead of `-c`.) This last form also allows you to use other (non-standard) format specifiers.

The filter for format `X` is the value for the `Xf` printcap option, with some minor exceptions. The following `Xf` options have a pre-defined meaning.

- `if` The `f` format filter, i.e. - for the default `f` format. All print jobs are passed through this one, unless another format is selected.
- `cf` Cifplot data filter (for `-c` format).
- `df` Filter for DVI files (`-d`).
- `gf` Graph data filter (`-g`).
- `nf` Ditroff data filter (`-n`).
- `of` This filter is used for processing the (optional) banner at the start and/or end of the print job, and also for the interjob separators. See of filter for details.
- `rf` Filter for Fortran style files (`-r`).
- `tf` Troff filter (`-t`).
- `vf` (Versatek) raster image filter (`-v`).

## 13.3 OF Filter

The `of` filter is used to process banners and job separators. The `of` filter is responsible for performing appropriate processing of this information and sending to the printer for action.

While the various file filters are invoked on a once per print file basis, the `of` filter is invoked on a once per print job basis.

This filter is the first one to be started, and should perform whatever specialized device initialization is needed. It should also do whatever accounting procedure is desired for start of job accounting.

The `of` filter will be given any banner printing or job separation information for a job. As part of its operation, it can detect a specific string, corresponding to a banner print request, and generate a banner. (See the Job Processing Steps and Printcap Options for details.)

During operation, the `lpd` server will send the special stop sequence of `\031\001` to the `of` filter. The filter must then suspend itself using a `kill -STOP` operation. The `lpd` server will detect that the `of` filter has suspended itself and then will perform other printing operations.

After the other printing operations have been completed, the `of` will then be sent a `kill -CONT` signal.

This sequence will continue until all information has been printed, and then the `of` filter's STDIN will be closed. The filter will then perform whatever cleanup operations are needed, update accounting or other information, and exit.

## 13.4 LPR -p format

Options used:

- `pr=`pr program for p format

The `-p` format is requires filtering the the input files by the `pr` utility and then passing the result through the `if` filter.

This is widely regarded as a kludge and may not be supported on your print spooler.

## 13.5 LPR binary (-l) format

The binary (or literal) format is `-l`. The `if` filter is used to process the file, and is invoked with the `-c` (`c`ancel processing?) flag.

The filter will not modify the file when sending it to the printer, but may apply various setups to the printer.

## 13.6 Filter Command Line Flags

Options used:

- `bk_filter_options=`Backwards Compatible Filter options
- `bk_of_filter_options=`Backwards Compatible OF Filter options
- `bkf` Backwards Compatible Filters
- `filter_ld_path=`Filter LD_LIBRARY_PATH environment
- `filter_options=`Filter options
- `filter_path=`Filter PATH environment
- `of_filter_options=`OF Filter options
- `pass_env=`Environment variables to copy to Filter environment
- `pl#`line count for page
- `pw#`column count for page
- `px#`pixel width for page
- `py#`pixel length for page

A filter (or program) specification in the LPRng printcap database usually has the form:

> `

>     :option=| [flags] /path [argument | "argument" | 'argument' ]*
>     :option=[flags]   /path [argument | "argument" | 'argument' ]*

> `

The first case is used where the option value can be a string or filter, and the second where a program is always expected. The following procedure is used to run a filter program. Arguments in single or double quotes are passed as a single value, as for a shell. No escape (backslash) support is provided.

The sequence of operations to run a filter is as follows:

1. The program must be specified with an absolute path name.
2. By default, the program is run as the user if invoked from a client program such as `lpr`, `lpc`, etc. If invoked from `lpd`, it is run as the `server_user` user (default `daemon`) configuration entry.
3. The flags control how the program is to be run. The following flags are supported:
   - ROOT This opens a horrible security loophole, as it will run the program as ROOT. To enable this option, you must set various compilation flags, and perform other arcane operations. This is deliberately done to make administrators read the warnings and admonitions.

     The alternative to ROOT is to have a setuid ROOT executable. Under NO circumstances should you run a shell script setuid ROOT, with general execute permissions on it.

   - -$ This very odd looking flag is used to suppress the addition of additional command line arguments specified by the value of `filter_options` to the program command line.
4. If the -$ flag is not specified, the arguments determined by the value of the `bkf` (Berkeley LPD filter compatible flag) flag are added to the filter command line. If `bkf` is false the `filter_options` are added for OF filters and `of_filter_options` are added for non-OF filters; if it is true, then the `bk_filter_options` and `bk_of_filter_options` are added for OF and non-OF filters respectively.

   Option | DefaultValue
   `filter_options` | $C $F $H $J $L $P $Q $R $Z $a $c $d $e $f $h $i $j $k $l $n $p$r $s $w $x $y $-a
   `of_filter_options` | (same as `filter_options`)
   `bk_filter_options` | $P $w $l $x $y $F $c $L $i $J $C $0n $0h $-a
   `bk_of_filter_options` | $w $l $x $y

5. By default, for programs that are not being invoked as print job file filters, the `filter_options` arguments are added. For print job filters, if the `bkf` flag is set, then the `bk_filter_options` and `bk_of_filter_options` entries are used. The default `bk` filter options are the same as originally used with the BSD LPR filters. For the `of` filter, either the `of_filter_options` or `bk_of_filter_options` arguments will be added.
6. The program arguments will then be scanned and interpreted. Arguments of the form `$`letter will be translated into values from the print job control file and/or printcap entry. The letters have the following meaning:

   Letter | TranslatedValue
   `a` | printcap `af` (accounting file name)
   `b` | job size (in K bytes)
   `c` | binary file (`l` format for print file)
   `d` | printcap `cd` or `sd` entry
   `e` | print job data file name (currently being processed)
   `f` | print job original name when spooled for printing (N info from control file)
   `h` | print job originating host (H info from control file)
   `i` | indent request (I info from control file)
   `j` | job number in spool queue
   `k` | print job control file name
   `l` | printcap `pl` (page length)
   `m` | printcap `co`
   `n` | user name (L info from control file)
   `p` | remote printer (when processing for bounce queue)
   `r` | remote host (when processing for bounce queue)
   `s` | printcap `sf` (status file)
   `t` | time in common UNIX format
   `w` | printcap `pw` (page width)
   `x` | printcap `px` (page x dimension)
   `y` | printcap `py` (page y dimension)
   `F` | print file format
   `P` | printer name
   `S` | printcap `cm` (comment field)
   Capital letter | Corresponding line from control file
   {key} | printcap value for `key`

7. If there is no value for the specified argument, then the argument is removed from the list. If there is a value, the actual form of the substitution is controlled by additional flags as follows.

   Form | TranslatedValue
   `$x` | `'-xvalue'`
   `$-x` | `'value'`
   `$0x` | `-x 'value'`
   `$'x` | `-x value`

   Each entry in quotes is treated as a single value, as in /bin/sh. The `$'x` does not quote the value. Combinations of the various flags are allowed. For example, `$-x` would simply substitute the value for `x`, and then pass the whitespace separated components as individual arguments. This last form is useful for adding in additional flags on the command line.

8. The command line is parsed, metacharacters are ruthlessly stripped from all arguments and pathnames and replaced by `_` (underscores), and an argument list suitable for the `execve` system call is formed.
9. A sanitized environment is set up for the program execution, with the following environment variables.

   `USER` | User name (client only)
   `LOGNAME` | L control file info
   `HOME` | Home directory (client only)
   `LOGDIR` | Home directory (client only)
   `PATH` | `filter_path` configuration information
   `LD_LIBRARY_PATH` | `filter_ld_path` configuration information
   `SHELL` | `/bin/sh`
   `IFS` | `" \t"`
   `TZ` | Time zone
   `SPOOL_DIR` | `sd` printcap info
   `CONTROL_DIR` | `cd` printcap info
   `PRINTCAP_ENTRY` | printcap info
   `CONTROL` | control file

10. If the filter is to be run by a client program such as `lpr`, then the environment variables specified by the `pass_env` configuration or printcap option will be extracted from the environment, have any metacharacters removed, and then placed in the environment variable list. Commonly, the `PGPPASS`, `PGPPASSFD`, and `PGPPATH` are specified.
11. The program is started, with STDIN, STDOUT, and STDERR attached to the appropriate files or file descriptors. If none is specified, then they are attached to `/dev/null`.

## 13.7 LPRng Supported Filters

There already exists a large library of ready-to-use filters. Some of them have LPRng-specific versions, which can be found at the LPRng ftp mirror sites.

### Filter Distribution Conventions

By convention, most filters are either totally standalone (very rare), or require a set of support files. There are two types of support files: per print queue configuration information and global support information.

Since a print filter will execute with the current directory set to the spool queue directory, most filters expect that per print queue configuration information should be kept in the spool directory. Most vintage filters insist on having these files hidden with names such as `.setup`. This can make it difficult for administrators to determine where the configuration files are.

It is strongly recommended that filters and information be placed in commonly accessible directories such as `/usr/local/libexec/filters`, and the executables in subdirectories. This allows the LPRng administrator to set the privileges on these directories such that only the `lpd` process can access them.

Most of the LPRng supported filters can either be used as a `if` or `of` filter. The filter will examine the format type passed by the `-FX` command line argument, and if it is `o` it will perform as an `of` filter.

Alternatively, the filter will check the filename in the pathname by which is was invoked. If the name has the substring `of` in the filename, then it assumes it is to act as an `of` filter. This allows symbolic links to be made to a common filter executable, each of which corresponds to the filter name by which it is to be invoked.

When a filter is invoked, it is passed a large number of options, many of which are totally ignored in filter operation. However, for many purposes it is necessary to provide options to the filters to tailor their operation to the particular spool queue needs.

By convention, all LPRng supported filters use the

> `

>     -Tkey=value[,key=value]

> `

convention for specifying filter configuration option values.

## 13.8 lpf

Source code: LPRng Distribution

This filter is distributed as part of the LPRng source code, and has a very limited functionality. By default, it only translates `\n` to `\r\n` sequences, and detects the OF Filter Stop sequence when invoked as an OF filter.

- Options:
  `-Tcrlf` - suppress `\n` to `\r\n` translation

## 13.9 IFHP Filter

Source code: LPRng Distribution, ifhp-<em>version</em>.tgz

This filter supports a wide variety of smart printers, or to be more specific, printers which support PostScript, PCL or PJL languages.

As explained in Setting Up Your Printer, you can have a parallel (unidirectional), serial (bidirectional), or network (bidirectional) connection. When using a bidirectional connection, you can sometime obtain or gratuitously receive error and/or status information from the printer.

Some printers will spontaneously generate error messages when printing a job on a bidirectional interface. Usually, though, it it necessary to force the printer to provide status in a reasonable format.

Some printers have the capability of printing either PCL or PostScript; some require special setup commands and some will autosense which type of job is being printed.

If you are printing text, and not using a Page Description Language like PostScript or PCL, then you may want to download a font to the printer. This is especially the case when you are trying to print text files in a non-English font.

Some printers will provide a hardware page counter value when requested; however, the means of requesting differ from model to model.

Sometimes you want to generate a special banner for a particular printer, and need to put in some dynamic information. While this can be done by the `lpd` server using the `bp` program specification, it turns out that non-LPRng systems which want to use the `ifhp` want to have the same facilities. Thus, you need to have some way to get the same effect as the `bp` option, but at the filter level.

Having done `lpd` banner generation and printing, why not have the filter run an accounting script as well?

At this point, I suspect that the reader is beginning to suspect that making a general purpose filter to support all of these possibilities is difficult. That is incorrect. It is extremely difficult.

However, the `ifhp` filter greatly simplifies this, as it uses a simple database together with some printer configuration options. For details, see the `ifhp` documentation for details on using the filter. For the terminally impatient, the following is a quick cookbook:

> `

>     # network connection to jet direct box,
>     #   no banners, HP compatible
>     lp
>       :lp=ipaddr%9100
>       :/usr/local/libexec/filters/ifhp
>       :sh:sf
>     #
>     # banner added
>     #
>     lp
>       :bp=/usr/local/libexec/filters/pclbanner
>       :of=/usr/local/libexec/filters/ifhp
>       :if=/usr/local/libexec/filters/ifhp
>       :sf
>     #
>     # for a parallel port printer or when you want VERY fast
>     #  throughput, no pagecounts, error messages, etc.  The
>     #
>     lp
>       :ifhp=status@
>       :/usr/local/libexec/filters/ifhp
>       :sh:sf

> `

## 13.10 Using your own filters

If you already have a working setup, with its own specific filter programs, you might want to keep them. Or, you might want to write a set of your own.

See the source code in the LPRng Distribution, FILTERS_LPRng-<version>.tgz files for examples.

Next Previous Contents