In the previous section we set up a simple filter and looked at what command line options and environment variables were passed to the filter. The command line options are discussed in detail in Filter Command Line Options and Environment Variables. A print job consists of a control file that contains information about the job and a set of data files that are the information to be printed. Here is the control file for the job that we printed:
Hh4.private Ppapowell J/tmp/hi CA Lpapowell Apapowell@h4+15850 D2000-04-26-18:13:55.505 Qlp N/tmp/hi fdfA015850h4.private UdfA015850h4.private
Each information line in the control file starts with an upper case letter, and except for the few options listed in the table below, these are passed as the corresponding command line options. For full details about the exact format of the control file see Job Files.
Table 4-1. Filter Options
Control File | Filter Option | Purpose or Value |
---|---|---|
-PPrinter | Print queue name - printcap information | |
H | -HHost | Host Name |
P | -nUser | User Login Name of job originator |
J | -JJob name | lpr -J option or file name |
C | -CClass | Print class (lpr -C option) |
L | -LBanner | Banner page request |
A | -AJobid | Job Id |
D | -DDate | Date or time information |
Q | -QQueue | Original Print queue job was sent to |
N | -NFilename | Filename |
f | -Ff | Format information for datafile |
With the exceptions of the -F, -n and -P command line literals, the command lines options have the same value as in the control file, and if they are present the lpd spooler will put them on the command line. The control file U line is used to indicate that the data file for the job should be removed after printing. This line is not used by most print spoolers but must be included in a job file to meet RCF1179 and vintage print spooler requirements.
Sometimes we want to pass only a small subset of these command line options to a filter or provide them in a specific order in order to be compatible with legacy print filters. LPRng provides several different ways to do this, and we will explore how to control command line options.
If the filter entry starts with -$, this suppresses the automatic addition of command line options; we can then add our own options to the command line. Modify the printcap entry to have the following form:
lp:sd=/var/spool/lpd/%P :force_localhost :lp=/tmp/lp :filter= -$ /tmp/testf '$P' $0P -X$-P ${lp} G\072
Lets print our /tmp/hi test file and then look at the lpq status:
h4: {167} % cp /dev/null /tmp/lp h4: {168} % lpr /tmp/hi h4: {169} % lpq -llll Printer: lp@h4 .... Status: IF filter msg - 'TESTF /tmp/testf -Plp -P lp -Xlp \ -Ylp /tmp/lp G:' at 01:20:21.560
The -$ suppresses the adding the default literals to the filter command line. You can pass specific options using $X; if the option has a non-null value then it will be expanded in the following format:
Option Value Expansion $X -X<value> $0X -X <value> $-X <value> ${name} printcap option value if value nonzero length \nnn single printable character $* all options expanded using $X
Command line options can be grouped and passed as a single argument by enclosing them in single or double quotes. You should be aware that LPRng has an extremely primitive way of handling quotes. When the /bin/sh -c parameter is not used, the the command line is broken on spaces and each unit is passed as an individual argument. If the first character after a space is a quote (single or double), the next quote is found, and then entire element is then used as a single parameter. Substitution of $X parameters is then done. As a special case, when you have a $0X, this causes a split and all of the string previous and including the -X flag is passed as a single option and all of the option value and following are passed as another option. If the result of the expansion is a zero length parameter then it is removed from the parameter list. When the /bin/sh -c is used the command line is not broken, and all non-empty option values are enclosed in single quotes.
The ${name} option is used to pass a printcap option value. For example, you can pass the value of the printcap option form as shown below. You can experiment with this by using the /tmp/testf filter and printcap shown below.
printcap: lp:sd=/var/spool/lpd/%P :force_localhost :lp=/tmp/lp :filter=/tmp/testf -F ${form} :form=payroll h4: {170} % cp /dev/null /tmp/lp h4: {171} % lpr /tmp/hi h4: {172} % lpq -llll Printer: lp@h4 ... Status: IF filter msg - 'TESTF /tmp/testf -F payroll' at 09:55:31.276 ...
If we have a legacy print filter that was originally written for the BSD print spooler, then we may find that it requires a small number of command line options in a very specific order. We can use the :bkf (BSD Kompatible Filter or BacKwards compatible Filter) flag to pass suitable options. Modify the printcap entry to have the following form:
lp:sd=/var/spool/lpd/%P :force_localhost :lp=/tmp/lp :filter=/tmp/testf :bk
Lets print our /tmp/hi test file and then look at the lpq status:
h4: {173} % cp /dev/null /tmp/lp h4: {174} % lpr /tmp/hi h4: {175} % lpq -llll Printer: lp@h4 .... Status: IF filter msg - 'TESTF /tmp/testf -Plp -w80 -l66 \ -x0 -y0 -Ff -Lpapowell -J/tmp/hi -CA -n papowell \ -h h4.private acct' at 08:07:46.583
Finally, there are times when we would like the print filter to be a simple shell command or to chain several programs together in a simple pipeline. While this is possible using a print filter, you can also do this in the filter specification. If your filter specification starts with a parenthesis (() or contains the IO redirection for pipeto (|), input redirection (<), or output redirection (>) then the lpd server will use the :shell configuration option value (default /bin/sh) and execute it using:
${shell} -c "( ${if} )"
If this is done, then no command line options are added to the command. However, expansion of $X parameters are still done. Modify the printcap entry to have the following form:
lp:sd=/var/spool/lpd/%P :force_localhost :lp=/tmp/lp :filter=(echo "PREAMBLE"; /tmp/testf; echo "APPENDIX")
Lets print our /tmp/hi test file and then look at the lpq status:
h4: {176} % cp /dev/null /tmp/lp h4: {177} % lpr /tmp/hi h4: {178} % lpq -llll Printer: lp@h4 .... Status: printing data file 'dfA018881h4.private', size 3, IF filter 'echo' at 09:22:11.476 Status: IF filter msg - 'TESTF /tmp/testf' at 09:22:11.510 Status: IF filter finished at 09:22:11.514
If we examine the /tmp/lp file we find:
PREAMBLE TESTF /tmp/testf ENV USER=papowell LD_LIBRARY_PATH=/lib:/usr/lib:/usr/5lib:/usr/ucblib ... PRINTER=lp LEADER hi TRAILER APPENDIX
As we expected, no options were passed on the command line. If the printcap is modified to have the following contents, then you will see:
lp:sd=/var/spool/lpd/%P :force_localhost :lp=/tmp/lp :filter=(echo "PREAMBLE"; /tmp/testf $*; echo "APPENDIX") h4: {179} % lpr /tmp/hi h4: {180} % lpq -llll Printer: lp@h4 .... Status: IF filter msg - 'TESTF /tmp/testf -Apapowell@h4+18941 \ -CA -D2000-04-29-09:27:30.700 -Ff -Hh4.private -J/tmp/hi \ -Lpapowell -Plp -Qlp -aacct -b3 -d/var/tmp/LPD/lp \ -edfA018941h4.private -f/tmp/hi -hh4.private -j018941 -kcfA018941h4.private \ -l66 -npapowell -sstatus -t2000-04-29-09:27:30.864 -w80 -x0 -y0 acct' at 09:27:30.879
Using the shell invocation is especially useful when you may have a parameter that has an empty string value, and need to pass this as a command line parameter. Modify the /tmp/testf filter, the printcap, and execute the following commands:
printcap: lp:sd=/var/spool/lpd/%P :force_localhost :lp=/tmp/lp :filter=( /tmp/testf -F '${form}' ) :form= #!/bin/sh # /tmp/testf - test filter for LPRng PATH=/bin:/usr/bin; export PATH echo TESTF $0 "$@" >&2 echo TESTF $0 "$@" while test $# -gt 0 ; do echo "PARM '$1'"; shift; done echo LEADER /bin/cat echo TRAILER exit 0 h4: {181} % cp /dev/null /tmp/lp h4: {182} % lpr /tmp/hi h4: {183} % lpq -llll Printer: lp@h4 ... Status: IF filter msg - 'TESTF /tmp/testf -F' at 09:59:27.365 h4: {184} % more /tmp/lp TESTF /tmp/testf -F PARM '-F' PARM '' LEADER hi TRAILER
As you can see, there is a parameters are not visible when printed but still have a command line option value. This is due to the combination of the $'{form} and using the :filter=(...) form.