LPRng-HOWTO: Job Processing

Next Previous Contents

## 12. Job Processing

Much of the flexibility of the LPRng software is obtained from the ability to control the details of each step of job processing. The following section details each step in the processing of a job, and explains the printcap options used to control each operation.

Assume the `pr` printcap entry has the form:

> `

>     pr
>         :lp=/dev/lp  OR  :lp=rp@rm
>         :sd=/var/spool/lpd/pr
>         :lf=log
>         :of=/usr/local/bin/lpf
>         :if=/usr/local/bin/lpf

> `

Assume that we have used the following command to print a set of files.

> `

>     lpr -Ppr file1 file2

> `

This will create a control file in the `/var/spool/lpd/pr` directory with the following contents (this is an example - in practice there may be minor differences between the example and an actual control file):

> `

>     Hastart4.astart.com
>     J/tmp/file1 /tmp/file2
>     CA
>     Lpapowell
>     Ppapowell
>     fdfA002230astart4.astart.com
>     N/tmp/file1
>     UdfA002230astart4.astart.com
>     fdfB002230astart4.astart.com
>     N/tmp/file2
>     UdfB002230astart4.astart.com

> `

## 12.1 Opening the Output Device

Options used:

- `achk` Accounting check at start
- `af=`Accounting File
- `ar` Remote printer accounting enabled
- `as=`Accounting at start
- `connect_grace#` Time between jobs
- `connect_interval#` Connection interval
- `connect_timeout#` Connection timeout
- `control_filter=`Control file filter
- `ff` form feed
- `fo` form feed on open
- `la` Local printer accounting enabled
- `ld=`leader on open (initialization string)
- `lk` Lock IO device
- `lp=`IO device pathname
- `nb` Nonblocking device open
- `network_connect_grace#` Time between jobs
- `of=`of filter
- `retry_econnrefused#` Retry if open failed
- `retry_nolink#` Retry if open failed
- `rm` the remote machine to send the job to
- `rp` the remote print queue to send the job to
- `rw` device opened RW flag
- `server_tmp_dir=`temporary directory

Sequence of Operations:

1. During the server operations, it will try to create temporary files in the print queue spool directory. If this is not desirable, it will create them in the `server_tmp_dir` directory.
2. If the accounting file specified by `af` exists, it is opened (af_fd) and the af_fd is passed as file descriptor 3 to all filters. If the `af` value has the form `af=|/program` then the program is started and the program STDIN is used as af_fd. If the `af` value has the form `af=host%port`, then a TCP/IP connection to the corresponding port on the remote host is made and the port used as af_fd. In the latter two cases, the filter STDIN (file descriptor 0) is actually opened read/write, and is used when information is needed from the accounting filter or remote server. See Accounting Printcap Options for more information on the LPRng accounting support.
3. If `la` (local accounting) is true and we are printing a job or `ar` (remote accounting) is true and we are transferring a job, the `as` value is examined. If it is a filter (program) specification, then the program is started with its STDIN attached to `/dev/null`, STDOUT will be read by the print spooler, STDERR output will be written to the error log, and file descriptor 3 output will be appended to the accounting file. The lpd program will wait until the accounting filter program terminates, and examine the error code for action, as for the filters (see errorcodes below). If the exit status is 0, (JSUCC) then the printing process will continue, if JHOLD the job will be held, if JREMOVE the job will be removed, if JFAIL the job processing will terminate with a JFAIL indication, otherwise the job processing will terminate with a JABORT indication.
4. If the accounting filter exited with a JSUCC (no error code) and the `achk` (accounting check) flag is set, the line read from the accounting filter STDOUT will be examined. This line should be `accept`, `hold`, `fail`, `remove`, otherwise the job processing terminates with a JABORT indication. An `accept` will allow the job to be printed, `hold` will hold the job, `fail` will cause the job to fail, `remove` will cause the job to be removed.
5. If the `connect_grace` value is non-zero and the server is opening a device or `network_connect_grace` is non-zero and a network connection is being made, the server will pause the specified time. This is to accommodate devices which need a recovery time between jobs.
6. The `lp` option is checked to determine the type of IO device.

   Format | Meaning
   `/pathname` | Absolute pathname of IO device
   `pr@host` | transfer to `pr` on remote `host`
   `host%port` | open a TCP/IP connection to port on host. host can be name or IP address
   `|filter` | run the filter program; it STDIN will be used as device

7. The IO device specified by `lp` is opened write-only or read-write if the `rw` flag is true, and the resulting file descriptor is io_fd. If the `nb` flag is set, a non-blocking open will be done as well. If the `lk` (lock device) flag is true, the device will be locked against use by other LPD servers.
8. If a `host%port` combination, a TCP/IP connection will be opened to the remote port and the connection will be used as io_fd.
9. If a filter program is specified, the filter program will be run and the STDIN of the filter will be used as the device file descriptor.
10. If a `rp@rm` combination, or none of the above combinations are true and the `rm` and `rp` values are non-zero, then the job will be transferred to a remote printer. The type of operation will be a job transfer, rather than printing operation.
11. If the `connect_timeout` value is non-zero, a timeout is setup for the device or socket open. If the device or connection open does not succeed within the timeout, then the open operation fails.
12. If a connection is to a network address (i.e. - `connect()` system call) and the connection attempt fails with an `ECONNREFUSED` error, if the `retry_econnrefused` flag is set then the connection attempt is retried, but this time using an alternative port number. See RFC1179 for details. This is repeated until all of the possible originating port numbers are exhausted.
13. If the open or connect operation fails, and the `retry_nolink` flag is set, then the server will pause for a minimum of `connect_grace` plus a multiple of `connect_interval` seconds based on the number of attempts before retrying the open operation. Note that the interval may increase as the number of attempts increases.
14. If printing a job and the `of` filter is specified, it is created with its STDOUT (fd 1) attached to the io_fd. Its stdin (of_fd) will be used in the steps listed below. If there is no `of` filter, then the of_fd value will be the io_fd descriptor.
15. If transferring a job and the `control_filter` option is specified, then the program specified by the `control_filter` value will be run. It will have its STDIN set to the control file, and its STDOUT output will be used as the new value of the control file to transfer to the remote host. See Filter Command Line Flags for details of options passed to the control filter, and errorcodes for the exit codes of the filter.
16. If the operation is a job transfer, the operation proceeds as outlined in RFC1179, and then the Normal Termination operations are carried out.
17. If the operation is a print operation and the `ld` (leader on open) value is provided, the string is translated (escapes removed) and written to the of_fd file descriptor.
18. If the `fo` (form feed on open) flag is true, then the `ff` (form feed) string is translated (escapes removed) and written to the of_fd file descriptor.

## 12.2 Printing Banner At Beginning

Options used:

- `ab` Always print banner (default FALSE)
- `be=`End banner generator program
- `bl=`Short banner line format
- `bp=`Banner generator program
- `bs=`Start banner generator
- `generate_banner` Generate banner for forwarded jobs
- `hl` Banner (header) Last
- `of=`Banner and File Separator Filter
- `sb` Short banner (default FALSE)
- `sh` Suppress header (banners) (default FALSE)

Banner printing is one of the more complicated configuration options of LPRng. This is due mainly to historical evolution of the software, as well as a lack of a well defined standard for filter responsibilities. In the original BSD print spoolers, the philosophy was that banner printing should be delegated to the filters, as they were the most aware of the capabilities of the printers. This required an out of band method to convey banner printing information to the filter, and resulted in a complicated interface. The original interface was:

1. The filter doing banner printing was invoked as a special `of` filter, or passed a special flag.
2. The print spooling software would send a special single line of information telling it what the banner information should be. Note that this line was never documented except for the source code, and was inconsistent from version to version. Also, there was no indication of what to do with additional lines, if any.
3. The filter would generate the banner, discard the line, and then pass other lines to the output device.

Adding to the confusion, the original print spoolers had a `:sh` (suppress header or banner) flag, which was supposed to suppress banner printing. It did this by having the print spooler not generate the magic banner information line.

A more sophisticated banner printing system would allow the print spooler software to generate the banner, and would then have the `of` filter act as a pass through. Thus, we need configure the `of` filter NOT to use the first line as banner printing information, and to pass through all information to the device.

Complicating this whole mess is the `ld` (leader option) and `tr` (trailer option) which is a string sent to the output device (`of` filter) when the device (filter) is initialized or terminated. This can sometimes be interpreted as the banner line, leading to unexpected results.

Sequence of Operations:

1. If the `sh` (suppress header) flag is true, no banner is printed, and the actions in this section are skipped. No banner information line is generated for the `of` filter, and no banner printing program is invoked. If there is an `of` filter and it is expecting such a line and you have `ld` or `tr` information then you may get unexpected results (actually, catastrophic failure is a better term, but I digress).
2. If the `hl` (header last) flag is true the banner is printed at the end of the job and the actions in this section are done at the end of the job.
3. If the user does not want banner pages she can use the `lpr -h` option. This will cause the `lpr` program to delete the `L` (banner name) line in the control file. If there is no `L` line in the control file and `ab` (always print a banner) is false (the default), then no banner is printed and the other actions in this section are skipped. If `ab` is true and the `L` line is missing then the `N` (user login name) is used; if it is missing as well, then ANONYMOUS is used for the user name.
4. If a banner printing program is specified by `bp`, tt`bs`, or `be` options, then LPRng will invoke the program to generate a banner and then send the generated banner to the printer via the `of` filter. The banner printing program will be invoked using the standard filter command line flags (see Filter Command Line Flags for details), with is STDIN attached to /dev/null and STDOUT attached to a file to hold the output banner.
5. If no banner printing program is specified and the `sb` (short banner) option is TRUE (default is true), then the `bl=...` (banner line) option value is expanded and sent to the `of_fd` (`of` filter or device. The default `bl` value is: `bl=$-'C:$-'n Job: $-'J Date: $-'t`. Using our example, this will get translated to:

   > `

   >     papowell:A Job: file1 file2 Date: Thu Nov 27 23:02:04 PST 1997

   > `

6. If no banner printing program is specified and we have `sb@` (no short banner) then we skip banner generation, i.e. - we do not send a banner generation line to the output (`of` filter).
7. If the queue is a normal forwarding queue, then the `generate_banner` option will invoke the `bp`, `bs` or `be` program as appropriate to create a banner page file which is then made the first (default) or last (`hl` flag or `be=...` present) file in a job. This option has no effect in other types of queues. See the `translate_format` option as well.

## 12.3 Printing Job Files

Options used:

- `Xf=`Format Filter
- `if=`Default F Format Filter
- `pr=`pr formatting program
- `send_job_rw_timeout=` print job read/write timeout
- `send_query_rw_timeout=` status query operation read/write timeout
- `sf` Suppress FF Print File Separators

Sequence of Operations: for each job in listed in the control file, the following operations are done in turn.

1. If there is an `of` filter present, the suspend string `\031\001` is written to of_fd and the no further action is taken until the of filter is suspended.
2. The control file line for the job is examined, and the first letter of the data file specification is used as the format.
3. If the format is `p`, the job is first processed by the program specified by the `pr` program, and the program output used as the print file.
4. If the format is `f`, `l`, or `p` then the `if` filter is used, otherwise the keyword `Xf` is used. Note that certain formats such as `p, a, l`, may not be used as formats.
5. The filter program is started with an appropriate set of command line options (see Filter Command Line Flags), and with its STDOUT attached to the printing device (io_fd), STDERR to a pipe which results in the output being written to the status file, and file descriptor 3 to the accounting file or program. If debugging is enabled, then the STDERR output is also written to the error log file (lf).
6. When doing a read/write operation to a device or remote system, a timeout can be specified. When doing a print or job transfer operation, the `send_job_rw_timeout` value is used. When doing a status or query operation, the `send_query_rw_timeout` value is used. If a write or write operation does not complete within the specified timeout seconds, then we have an error condition and job processing or the query operation is terminated with JFAIL status. If the timeout value is 0, then no timeout is done.
7. `lpd` will then wait for the filter to exit. The exit status can be as follows:

   > `

   >     Key      Value   Meaning
   >     JSUCC    0       Successful
   >     JFAIL    1, 32   Failed - retry later
   >     JABORT   2, 33   Abort - terminate queue processing
   >     JREMOVE  3, 34   Failed - remove job
   >     JHOLD    6, 37   Failed - hold this job
   >     Other            Abort - terminate queue processing

   > `

8. If the filter exit status was JSUCC (0), or no error indicated, then processing will continue otherwise the job termination takes (see Abnormal Termination).
9. If the `of` filter is present, then it is reactivated with a `kill -CONT` signal.
10. If the `sf` (suppress FF print file separators ) is false, then the `ff` (form feed) string will be interpreted and sent to the of_fd.

## 12.4 Printing Banner At End

Options used:

- `hl` Header (Banner) Last

The actions taken in this step are identical to those for the Printing Banner At Beginning, with the exception that the `be` (end banner program) is used to select the banner generation program rather than the `bs` (start banner program).

If we have `hl` true, then we print a banner at the end of the job, rather than start.

## 12.5 Normal Termination

Options used:

- `fq` Form Feed on Close
- `la` Local Printer Accounting
- `tr=`Trailer on Close
- `ae=`Accounting at end
- `save_when_done` Save when done
- `wait_for_eof` Wait for EOF before closing device
- `exit_linger_timeout` connection linger on close timeout

Sequence of Operations:

1. If we are printing and the `fq` flag is set and the `sf` (suppress interfile FF) flag is set, then the `ff` (form feed) string will be interpreted and sent to the of_fd.
2. If we are printing, the `tr` (trailer) string will be interpreted and sent to the of_fd.
3. If printing and the `la` (local printer accounting) flag is set or transferring a job and the `ar` (remote accounting) flag is set, the `ae` is examined and accounting is done as described for the `as field.`
4. If the `of` filter is present, its STDIN is closed, and the `lpd` server waits for it to exit. The exit status is used as described above.
5. If the device is a socket or network connection, the socket linger time is set to `job_send_rw_timeout` value if nonzero or the `exit_linger_timeout` value if nonzero, a write `shutdown` is done, and if the `wait_for_eof` option is true (default) then a read is done on the connection until an EOF is found. The device (io_fd) is then closed.
6. The job is marked as completed in the spool queue.
7. If the `save_when_done` flag is not specified, the job is removed.

## 12.6 Abnormal Termination

Options used:

- `mail_from=`Mail from user name
- `mail_operator_on_error=`Mail to operator on error
- `send_try#` Maximum Print or Transfer Attempts
- `save_on_error` Do not delete on error
- `send_failure_action=`Action on Failure
- `sendmail=`sendmail path name and options
- `stop_on_abort` Stop processing queue on filter abort

If the job processing terminates abnormally, the following sequence of events occurs:

1. The job is marked as having an error during processing.
2. The LPD server will attempt to kill all filters and other associated processes by sending a SIGINT and SIGCONT (`kill -INT` and `kill -CONT`) to them.
3. If there is a `mail_operator_on_error` value, the specified operator will be mailed an error indication. The `sendmail` option specifies the pathname of the sendmail program and the options needed to have it read mail addresses from its standard input. For example, `sendmail=/usr/sbin/sendmail -oi -t` is a commonly used set of options.
4. The `mail_from` value specifies the user name used for mail origination. If not specified, the default is to use the print spool queue or printer name.
5. If there is a `send_failure_action` specified, then it is decoded and the corresponding action taken. If the value is `remove`, `hold`, `abort`, or `retry`, then the job is removed, held, aborted, or retried. If the value is `|/program`, the program is executed and the number of attempts are written to the filter STDIN. The exit status of the filter will be used to determine the consequent actions. That is, JSUCC (0) will be success, and the standard success action will be taken; JFAIL will cause retry, JREMOVE will cause the job to be removed, JHOLD will cause the job to be held, JABORT or other status will abort processing.
6. If the status is ABORT and the `stop_on_abort` flag is set, then further processing of jobs is terminated. The job is not removed from the queue.
7. If the error status indicates removal, and the `save_on_error` flag is clear then the job is removed from the spool queue.
8. If the error status indicates that no further operations should be performed on the queue, then the `lpd` server will stop processing jobs.
9. If the error code indicated that the job should be retried, and the `send_try` value is 0 or the number of attempts is less than the `send_try` value, then the job is retried. Between each attempt to transfer a job to a remote site. This pause will double after each attempt, reaching a maximum of `max_connect_interval` seconds. If `max_connect_interval` is 0, there is no limit on the interval value.

## 12.7 LPD Spool Queue Processing

Options used:

- `lpd_force_poll=`Force LPD to periodically poll print queues
- `lpd_poll_time#`Time between polls
- `max_servers_active#`Maximum number of active servers

When the `lpd` server starts, it will fork a set of subserver processes, each which will handle an individual queue.

If a system has a large number of queues, then this forking operation may result in the `lpd` server exhausting the process resources. To control this, the `max_servers_active` value restricts the number of active children to the specified value. If this value is 0, then 50% of the maximum system processes value will be used.

Due to the limits on the number of processes, there may be times when a job is placed in a queue, but the `lpd` server is unable to start handling the job. When all of the children of the main `lpd` server have exited, the server starts a timer. After `lpd_poll_time` seconds, it will scan the queues, looking for jobs to process, and starts a process to service them. If it does not find any jobs it remains idle.

The `lpd_force_poll` flag causes the server to periodically poll the queues. This is useful when there is a high possibility that jobs could fail to be printed due to high loads on the server.

Next Previous Contents