CAPS Universe documentation  1.0.4
All you need to know to be successful
Functions | Variables
caps-printer.c File Reference

CAPS Printing Driver Launcher. More...

Functions

static void caps_prn_print_verbose_printer_message (const struct usb_printer *p)
 
static int caps_prn_handle_pd (const struct usb_printer *prn, const struct caps_inif_table *devices_database)
 
static int fd_is_valid (int fd)
 
static int caps_prn_lock_device_node (const char *dev_node)
 
static void handle_nls (void)
 
static int node_cb (const struct caps_arg_parser *parser, const char *value)
 
static void fd_workaround_start (void)
 
static void fd_workaround_end (void)
 
int main (int argc, char *argv[])
 

Variables

static const struct caps_arg_parameter caps_printer_argument
 
static struct caps_arg_parser caps_printer_parser
 
static int locked_fd3 = -1
 

Detailed Description

Author
Jürgen Borleis
Warning
Use as experimental

caps-printer will be started as non-root and replaces itself by the regular printing device driver. On order to do so, it expects the printing device is already registered in the run-time printing device database. The Printer Preparation will ensure this (if a printing device driver is present). The printing device node will be locked to ensure only one printing driver instance will run for one printing device.

Function Documentation

◆ caps_prn_print_verbose_printer_message()

static void caps_prn_print_verbose_printer_message ( const struct usb_printer p)
static

Fill the log with some useful information why we failed

Parameters
[in]pThe USB printer device information

Give the user a chance to find/install the correct printer driver for this device by providing more useful information about it.

Note
This is a copy of the same function in lib-caps-printer-prep.c. Can we share it?

◆ caps_prn_handle_pd()

static int caps_prn_handle_pd ( const struct usb_printer prn,
const struct caps_inif_table devices_database 
)
static

Discover the corresponding printing driver and run it instead

Parameters
[in]prnThe technical details about the USB printing device
[in]devices_databaseThe run-time printing device database
Return values
nothingThis function should not return
-ENODEVNo driver for this printer device
negative-errno else

Since this function starts the regular printing device driver via execve() this function does not return in case of success.

◆ fd_is_valid()

static int fd_is_valid ( int  fd)
static

Check if the given file descriptor is still valid

Parameters
[in]fdFile descriptor to check
Return values
trueFile descriptor is valid
falseFile descriptor is invalid
Attention
This check isn't reliable!
Todo:
If the driver was started from within the template service unit, fcntl() always returns a valid file descriptor, even if the printer is already gone.

◆ caps_prn_lock_device_node()

static int caps_prn_lock_device_node ( const char *  dev_node)
static

Open and lock the given printer device node

Parameters
[in]dev_nodePath to the device node (from udev/systemd)
Return values
3Device node's file descriptor
-EINVALPrinter device node seems somehow insufficient or locking failed
Note
The opened and locked printing device node will be forwarded to the printing driver.
Attention
Don't use O_NONBLOCK for the printer's file descriptor. Read the comment of the kernel driver usblp.c, function usblp_wwait() why.
Note
We also don't enable LP_ABORT since this would result into data loss when the printer enters the error state ("out of paper" for example). We rely on continue printing, if the user adds more paper in this case.
Precondition
Don't log anything to the journal until the filedescriptor to the printer device node is opened!!
Postcondition
The returned filedescriptor is always 3 if successful.

◆ handle_nls()

static void handle_nls ( void  )
static

◆ node_cb()

static int node_cb ( const struct caps_arg_parser parser,
const char *  value 
)
static

◆ fd_workaround_start()

static void fd_workaround_start ( void  )
static

Begin the workaround to keep the filedescriptor 3 free for us

Whenever we use systemd's journald for logging, this could occupie our filedescriptor 3. We must lock it, before we do the first log output into the journal.

At some point running this tool, it had the following filedescriptors already open:

‍$ sudo ls -l /proc/<some pid>/fd total 0 lr-x---— 1 lp lp 64 Jun 7 19:19 0 -> /dev/null lrwx---— 1 lp lp 64 Jun 7 19:19 1 -> 'socket:[627790]' lrwx---— 1 lp lp 64 Jun 7 19:19 2 -> 'socket:[627790]' lrwx---— 1 lp lp 64 Jun 7 19:19 3 -> 'socket:[627799]'

After adding this workaround, the final open filehandles changed to:

‍sudo ls -l /proc/750245/fd total 0 lr-x---— 1 lp lp 64 Jun 7 19:31 0 -> /dev/null lrwx---— 1 lp lp 64 Jun 7 19:31 1 -> 'socket:[1245770]' lrwx---— 1 lp lp 64 Jun 7 19:31 2 -> 'socket:[1245770]' lrwx---— 1 lp lp 64 Jun 7 19:31 3 -> /dev/usb/lp0 lrwx---— 1 lp lp 64 Jun 7 19:31 4 -> 'socket:[1245780]' lrwx---— 1 lp lp 64 Jun 7 19:31 6 -> 'socket:[1245781]'

Precondition
Run this function before sending the first message to systemd's journald

◆ fd_workaround_end()

static void fd_workaround_end ( void  )
static
Postcondition
The fd 3 is free again for use

◆ main()

int main ( int  argc,
char *  argv[] 
)

We are called here for exactly one printer device when it gets attached or detected.

Parameters
[in]argcGuess what
[in]argvGuess what
Returns
EXIT_FAILURE, else we never return here

As a parameter we receive the corresponding device node via '–node=<nodename>'. We run as a systemd service with 'Type=notify'. After recognizing the corresponding printer driver we exec into this executable.

If we run as root, bail out. We need to run as a regular user here!

Just discover the corresponding printer driver and launch it.

Variable Documentation

◆ caps_printer_argument

const struct caps_arg_parameter caps_printer_argument
static
Initial value:
= {
.keyword = "node", .key = 'n', .cb = node_cb,
.arg = ( "NODE" ), .doc = ( "Printing device's node in '/dev'" ),
}
static int node_cb(const struct caps_arg_parser *parser, const char *value)
Definition: caps-printer.c:196

◆ caps_printer_parser

struct caps_arg_parser caps_printer_parser
static
Initial value:
= {
.parameter_cnt = 1,
.parameter_list = &caps_printer_argument,
.footer = ( "This argument is mandatory" ),
.domain = PACKAGE,
}
static const struct caps_arg_parameter caps_printer_argument
Definition: caps-printer.c:204

◆ locked_fd3

int locked_fd3 = -1
static

Just for a workaround to keep our filedescriptor 3 free for our purpose here