Besides reading files and writing to devices, a backend must cooperate with the qdaemon in several ways:
The qdaemon and the backend communicate through a status file. Understanding Backend Routines in libqb explains the set of library routines that the backend should use to fulfill these communication requirements. These routines are in the /usr/lib/libqb.a library.
When the qdaemon process invokes a backend, it passes the following parameters, in order:
There is a status file for each device and its associated queue. These files are found in the /var/spool/lpd/stat directory.
The status file provides a means of communication for the qdaemon process and the backend. The qdaemon passes information such as the date of the file, whether to print burst pages, and the number of copies to be printed. The backend passes back the charge for the job it has just finished running. In addition, the backend periodically updates the number of pages it has printed and what percent of the job is finished. This information is read by the qchk command.
Note: Backends should never explicitly write into their status file. They should call the libqb library routines to do this.
There are two reasons for calling the routines:
To initialize certain data common to the library routines, the backend must call the routine log_init. For more information see Understanding Backend Routines in libqb. The call is:
This routine should be called to initialize the status file interface. The log_init routine, like all log_ routines in the library, returns a value of -1 if it fails.
The enq -N command prints extra copies of a file. For example, to print five copies of a file filename, enter this command:
enq -N5 filename
The enq command passes the information to the qdaemon process, which puts it into the status file. Backends should get the information by calling the get_copies (Understanding Backend Routines in libqb) routine, which returns the total number of copies requested.
The qchk command displays information about currently running jobs, including the originator, title, number of pages to be printed, and percentage completed. All this information comes from the status file. Most of the information is set up by the qdaemon when the backend is first invoked, except the pages printed and percent done fields, which must be filled in by the backend itself.
To provide this information, the backend should periodically call the libqb, see Understanding Backend Routines in libqb for the following functions:
The backend is free to call these routines at any time; once at the end of each page is recommended.
When a backend completes a job, the qdaemon reads the status file for a charge. If the qconfig file has been set up to do so, the charge is written to a file that is eventually processed by the accounting programs. This results in a bill (real or imaginary) for the user issuing the print request.
The backend passes the charge back to the qdaemon with the routine log_charge(charge). See Understanding Backend Routines in libqb. The backend should call this routine on exit. It should also call the routine along with log_progress while printing the job. For more information see Updating Job Status Information. Otherwise, if the job is canceled, no charge will be made for the pages printed up to that point.
The charge is interpreted by all current accounting programs as the number of pages printed. However, a backend can set the charge to be based on any multiplier, whole or fraction, of pages printed.
For more information about job accounting, see Chapter 3, Spooler Overview .
When a backend exits, the qdaemon looks at its exit code for such information as whether the job was completed successfully and whether the device is still usable. Therefore, it is important that backends use the same convention for their exit codes. The backend should use #include <IN/standard.h> for the values of the codes given here.
The permissible exit codes
|No problems encountered.
|The parameters could not be acted upon. Two common examples are a flag's not being valid or a file that could not be opened. The qdaemon sets the state of the device (displayed by qchk) to OFF, sends a message to the console, and does not run any further jobs on that device until someone has explicitly set its state to ON again (with an enq -Pqueuename -U command).
|The backend could not finish printing the job. The qdaemon restarts the same job from the beginning on the same device. The qdaemon enforces a limit on the number of times the job will be restarted.
|The job could not be finished because of a problem in the device that requires manual intervention. The qdaemon sets the state of the device (displayed by qchk) to OFF, sends a message to the console, and does not run any further jobs on that device until someone has explicitly set its state to ON again (with an enq -Pqueuename -U command).
|The backend was interrupted by a SIGTERM signal (#include <signal.h>).
|The backend has issued a warning to the qdaemon. The job may or may not be completed successfully, but in either case, when the qdaemon receives an EXITWARN from the backend, qdaemon returns a message explaining the problem.
When an error event occurs, the backend should send a message to the user. Before sending a message, the backend should check the PIO_IPCWRITEFD environment variable. If it is set, the message is sent to a print supervisor by way of a pipe. The print supervisor interprets the message and sends it to the user. If the PIO_IPCWRITEFD environment variable is not set, the backend sends the message to the user with the sysnot routine.
The qdaemon print spooler always uses the sysnot (Understanding Backend Routines in libqb) routine to send messages. Non-base operating system print spoolers can use sysnot routine or the pipe to send messages.
The backend can send messages directly to the user with the sysnot (Understanding Backend Routines in libqb) routine. The sysnot routine can either mail the message to the user or write the message to the user's terminal. The sysnot routine is called with the following syntax:
sysnot(user, host, message, pref) char *user; char *host; char *message; unsigned int *pref;
The value of the pref parameter should be DOMAIL or DOWRITE. DOMAIL mails the error message to the user. DOWRITE writes the message to the user's terminal if the user is logged on. If the user is not logged on, the message is mailed to the user. The DOMAIL and DOWRITE constants are defined in the /usr/include/IN/backend.h file.
The backend can send messages to the user by sending the message to a print supervisor by way of a pipe. This mechanism provides a one-way communication path between the printer backend and the print supervisor.
The print supervisor must open an unnamed pipe and obtain two file descriptors, one for read operations and one for write operations. The print supervisor must export the write end in the PIO_IPCWRITEFD environment variable before calling the printer backend with the fork and exec subroutines. If the PIO_IPCWRITEFD environment variable is set, the printer backend writes any messages to the write end of the pipe.
The print supervisor typically calls the select subroutine to poll the read side of the pipe for incoming messages. In addition to checking for exit status of the printer backend using the waitpid subroutine, the print supervisor polls for I/O on the pipe. The print supervisor sets up a signal handler for the SIGCHLD signal and performs a block read on the pipe. The signal handler examines the exit status of the printer backend and performs any action necessary. When no unread messages remain on the pipe, the print supervisor closes the pipe and proceeds to other cleanup work.
Each message sent by the printer backend consists of a message header frame, zero or more parameter header frames, a fully expanded message, and text consisting of zero or more parameters. The message header specifies the message type, message catalog information, length of expanded message text, and the number of variable message parameters. The variable message parameters are used to build the expanded message text from the basic message text that is extracted from the message catalog. The structure formats for the message header and the message parameter header frames are defined in the /usr/include/piostruct.h file.
When extracting messages from the pipe, the print supervisor reads the message header frame, then reads the message parameter header frames (0-9, as specified by the number of parameters specified in the message header frame). The print supervisor reads the expanded message text, the length of which is specified in the message header frame, followed by the parameters (if any). The type and length of any parameters are specified in the individual message parameter header frames.
The type of message is specified in the message header frame. The two message types are:
The actual message text is in expanded format. The parameters are placed in the message text after the parameters are extracted from the message catalog file in the server's locale. The print supervisor can use the message text or build its own message text from the supplied message catalog information and the message parameters. However, the printer backend cannot provide message catalog information (message number, set number, and catalog name) and variable message parameters in all cases. Therefore, the print supervisor must check for the catalog name field (pm_catnm field) to determine if the catalog name is a null string. If the catalog name is a null string, the print supervisor must use the supplied expanded message text.
If a catalog name is provided, the print supervisor can extract the message from the catalog and place any supplied message parameters in the message. The message parameters can be integer or string type. However, message parameters are passed from the printer backend as strings concatenated to the expanded message text. If the print supervisor extracts the message from the specified catalog and places the parameters in the message, the following conventions apply:
Error %8$d in opening %6$s file
Error %s in opening %s file
and assigns the first variable parameter pointer to the eighth parameter, the second variable parameter pointer to the sixth parameter, and the remaining variable parameter pointers to null strings. The print supervisor then calls the sprintf subroutine or a similar subroutine and pass the nine variable parameter pointers as parameters to the function.
The qchk command displays the status of a particular device. One of the entries in the table that is displayed shows the current state of the queue. This information is taken from the status file. See /usr/include/IN/backend.h for a list of valid queue states and their explanation.
Normally, the qdaemon keeps the status file updated. However, some backends may want to set explicitly the state to WAITING (#include <IN/backend.h>) if they can no longer send output to the device, and set it back to RUNNING when output resumes. For example, a backend that paused at the end of each page, waiting for user response, might want to set the status to WAITING during this time.
The log_status(status) routine can be used to change the status of the job from RUNNING to WAITING and back again. For more information see Understanding Backend Routines in libqb.The parameter is the new status.
In the case of a DEV_WAIT state on a queue device, issue enq -U -Pqueue to attempt to get the queue to a state of readiness. If this does not work move all the jobs in that queue and issue enq -G in order to flush the other queues and bring down the qdaemon. Then restart the qdaemon.
When a user cancels a running job with qcan, the command passes the request to the qdaemon. The backend must stop the print soon after receiving the signal. There are two ways to accomplish this.
First, the backend cannot do anything special about SIGTERM, in which case the signal stops the backend process immediately. This option is the simplest, but it does not allow the backend to do any cleanup (reset line speeds, put paper at top-of-form, hang up the phone) before it terminates.
Second, the backend can catch SIGTERM, carry out whatever cleanup tasks are required, and exit EXITSIGNAL (#include <IN/standard.h>). The special exit code tells the qdaemon that the job was canceled.
Backends that decide to catch SIGTERM should exit very soon after receipt of the signal.