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.
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 |
class_in_status | Show job class name in lpq status information |
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 |
Options used:
cm=
comment for statusif=
default job file filter lf=
log file mx#
maximum job sizelp=
output devicesd=
spool directory file sh
suppress headers (banners) sf
suppress form feeds between filesThe 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:
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.cm
field can be used to supply a comment to
be used as a header in lpq
output.sd
specifies the spool directory.
This is where files
are stored until they are printed.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.mx
indicates the maximum file size for a print job.
Supplying 0 here means that there is no limit.sh
(suppress headers) flag. This will
inhibit banner pages.Options used:
br#
serial port bit ratems=
(alias for sy)sy=
stty options for serial port configurationty=
(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
Options used:
lp=
destinationrm=
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
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.
Options used:
force_localhost
force clients to send requests to localhost localhost=
localhost nameSome 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.
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
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.
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.
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.
-Pxxx
argument,
then the lp
option is assigned the value xxx
.xxx
,
then the lp
option is assigned value xxx
.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.rm
or rp
does not have a value,
then they are assigned the default_host
(usually localhost)
and default_printer
(usually lp) option values.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.
Options used:
bq=
destination for processed jobsgenerate_banner
do banner generationtranslate_format
do banner generationNormally, 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:
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.bq
option.sd
) on the lpd server host
to hold the files and temporary output while they are processed.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.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.
Options used:
lpr_bounce
lpr does filteringSome 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.
Options used:
destinations=
destinations for jobsrouter=
router programThe 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:
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.
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.
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.
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.
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
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";
Options used:
printcap_path=
printcap file locationslpd_printcap_path=
additional server printcap file locationsnw
NFS spool directoryThe 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.
#
are ignored, except if it follows a continuation line.
(Which makes sense.)_
,
@
or .
|
followed by the alias:
followed by the 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_
, @
,
or .
(period)
(eg.- @
name)
are treated like dummy
entries. They can be referenced with :tc=
entry:
,
but will be ignored otherwise.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.=
value.%
X%
X values are expanded when the printcap entry is used by
the client or server program.
The following values are expanded: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.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.
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.
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.
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.
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
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.
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.
In the
lpd.conf
file you can specify:
printcap_path=|programThis 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.
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
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.
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 .
---------- 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)
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
$ 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
/etc/lpd.conf
:
printcap_path=|/usr/lib/yp/match_printcap
$ lpq -Plp1 # shows the status of lp1
lpq
command,
and then try lpc printcap lp1
.Options used:
qq
Insert queue name into control fileuse_queuename
(alias for qq)force_queuename=
Queuename to be usedThe 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.
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.
Options used:
fd
Forwarding offWhen 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.
Options used:
rg=
Restricted group listThe 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.
Options used:
fx=
supported formats for printingThe 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.
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.
Options used:
fix_bad_job
fix bad jobsafe_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.
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.
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.
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.
Options:
bk
Berkeley compatible control filecontrol_filter=
Control file filterOne 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.
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.
Options used:
mi#
minimum spool queue space (Kbytes) minfree#
alias for miIf 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.
Options used:
debugging=
debugging optionsfull_time
full or extended time formatms_time_resolution
millisecond time resolutionsyslog_device=
syslog alternative deviceuse_date
put date information in control fileuse_info_cache
cache printcap and other informationThe 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.
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.
Options used:
ipv6
use IPV6 Network facilities lockfile=
lpd server lock filelogfile=
lpd server log filereport_server_as=
server name for status reportsspool_dir_perms#
spool directory permissions spool_file_perms#
spool file permissions spread_jobs#
job number spreadThese 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.
The following arguments have been provided for compatibility with legacy systems.
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.
Options used:
break_classname_priority_link
classname and priority can differclass_in_status
show class name in statusclassname_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.
Setting the class_in_status
option causes the class name rather
than priority to be displayed in the status information.
Options used:
reverse_lpq_format=
reverse LPQ status format for specified remote systemsVarious 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.
Options used:
return_short_status=
return short LPQ status for specified remote systemsshort_status_length#
short LPQ status length in linesIn 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.
Options used:
ignore_requested_user_priority
prevent users from queue jumpingforce_fqdn_hostname
force FQDN hostname in control fileSome 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.
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.
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.