A printer usually understands one or more Print Job Languages. Files sent to this printer must be in one of these languages and have the appropriate job format, control characters, or other information. The most common Print Job Languages are PostScript and PCL.
In order for a printer to reliably print a job, it needs to be reset to a known configuration. This is usually done by sending it a special start of job and end of job command. These commands differ from printer to printer, and even depend on the type of print job language that the print job is in. Some vintage line printers also have a set of proprietary escape sequences that are used to set up margins, form size, and other printing characteristics. Usually a setup string of these escape sequences needs to be sent to the printer before the file can be printed.
In order to handle these problems, the LPRng system uses a filter program to provide the set of escape sequences or carry out the initialization required for a printer. The files in a print job are assigned a lower case letter format using the lpr format options; the default format is f. The l (literal or binary) format is used to indicate that the file should be passed directly to the printer, or have at the most a minimal amount of processing. See Print Job Formats for more information about formats and their use with filters.
We will set up a very simple filter and use it to demonstrate how the lpd spooler uses it. First, set up the /tmp/testf file as shown below.
#!/bin/sh # /tmp/testf - test filter for LPRng PATH=/bin:/usr/bin; export PATH echo TESTF $0 "$@" >&2 echo TESTF $0 "$@" echo ENV set echo LEADER /bin/cat echo TRAILER exit 0
Let us carefully examine the script line by line. The first couple of lines are standard boilerplate. You should always set the PATH value in a filter script or use full pathnames. This is a good practice as it ensures that only the specified directories will be searched for commands.
The next lines echo the command line arguments to file descriptor 2 (STDERR) and to STDOUT. We will soon see how this information is displayed by the LPRng software. We then use the set command to list the shell variables to STDOUT, print LEADER to STDOUT, copy STDIN to STDOUT, and print TRAILER to STDOUT. We exit with a zero result code.
We can test our script, with the results shown below:
h4: {161} % chmod 755 /tmp/testf h4: {162} % echo hi |/tmp/testf -a1 TESTF /tmp/testf -a1 TESTF /tmp/testf -a1 ENV USER=papowell HOSTNAME=h4 ... PATH=/bin:/usr/bin LEADER hi TRAILER
Let's now use this filter. Edit the lp printcap entry so it has contents indicated below, use checkpc -f to check the printcap, and then use lpc reread to restart the lpd server.
lp:sd=/var/spool/lpd/%P :force_localhost :lp=/tmp/lp :filter=/tmp/testf
Execute the following commands to print the /tmp/hi file and observe the results:
h4: {163} % cp /dev/null /tmp/lp h4: {164} % lpr /tmp/hi h4: {165} % lpq -llll Printer: lp@h4 Queue: no printable jobs in queue Status: lp@h4.private: job 'papowell@h4+26593' printed at 21:37:21.312 Status: job 'papowell@h4+26593' removed at 21:37:21.323 Status: subserver pid 26683 starting at 21:39:21.908 Status: accounting at start at 21:39:21.908 Status: opening device '/tmp/lp' at 21:39:21.909 Status: printing job 'papowell@h4+26681' at 21:39:21.909 Status: no banner at 21:39:21.909 Status: printing data file 'dfA026681h4.private', size 3, IF filter 'testf' at 21:39:21.909 Status: IF filter msg - 'TESTF /tmp/testf -Apapowell@h4+26681 -CA -D2000-04 -11-21:39:21.877 -Ff -Hh4.private -J/tmp/hi -Lpapowell -Plp -Qlp -aacct -b3 -d/v ar/tmp/LPD/lp -edfA026681h4.private -f/tmp/hi -hh4.private -j026681 -kcfA026681h 4.private -l66 -npapowell -sstatus -t2000-04-11-21:39:21.000 -w80 -x0 -y0 acct' at 21:39:21.914 Status: IF filter finished at 21:39:22.070 Status: printing done 'papowell@h4+26681' at 21:39:22.070 Status: accounting at end at 21:39:22.070 Status: finished 'papowell@h4+26681', status 'JSUCC' at 21:39:22.070 Status: subserver pid 26683 exit status 'JSUCC' at 21:39:22.072 Status: lp@h4.private: job 'papowell@h4+26681' printed at 21:39:22.072 Status: job 'papowell@h4+26681' removed at 21:39:22.085 h4: {166} % more /tmp/lp TESTF /tmp/testf -Apapowell@h4+26681 -CA -D2000-04 -11-21:39:21.877 -Ff -Hh4.private -J/tmp/hi -Lpapowell -Plp -Qlp -aacct -b3 -d/var/tmp/LPD/lp -edfA026681h4.private -f/tmp/hi -hh4.private -j026681 -kcfA026681h4.private -l66 -npapowell -sstatus -t2000-04-11-21:39:21.000 -w80 -x0 -y0 acct ENV USER=papowell LD_LIBRARY_PATH=/lib:/usr/lib:/usr/5lib:/usr/ucblib HOME=/home/papowell PRINTCAP_ENTRY=lp :force_localhost :filter=/tmp/testf :lp=/var/tmp/lp :sd=/var/tmp/LPD/lp PS1=$ OPTIND=1 PS2=> SPOOL_DIR=/var/tmp/LPD/lp LOGNAME=papowell CONTROL=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 PATH=/bin:/usr/bin SHELL=/bin/sh LOGDIR=/home/papowell IFS= PRINTER=lp LEADER test Test TRAILER
The cp command clears out the /tmp/lp file we are using as a dummy output device. The lpr command prints the /tmp/hi file and the lpq -llll command shows the status information. The status information now contains the line that the testf script wrote to STDERR. The lpd server captures filter STDERR messages and puts it them in the spool queue status file.
As we see from the lpq status, lpd passes a large number of command line options to our filter. These options and their meanings are discussed in detail in Filter Command Line Options and Environment Variables. We will discuss these in more detail in the next section.
If we look at the /tmp/lp file, we see the command line options and values of the shell variables. For a full discussion of the environment variables passed to a filter see Filter Command Line Options and Environment Variables. The more interesting environment variables include the PRINTCAP_ENTRY variable, which is a copy of the printcap entry for this printer, and the CONTROL variable, which is a copy of the control file for the the print job.