Main page | Install | ttyreplay(1) | rpldev(4) | rpl(5) | ttyrpld(7) | rplctl(8) | rpld(8) | Netlogging | Legal | Support


Name > rpldev - tty logger kernel module
 
Description >

/dev/rpl is a character device file which returns the data captured from ttys through the rpldev kernel module. It has no fixed device number, since it asks the misc driver subsystem (char-major-10) to assign it a dynamic one.

This is a little feature rather than a bug. rpld will automatically read /proc/misc for the minor number and creates a device file in its working directory. You should not worry about the minor number and creating a device node, that's the idea behind. (udev is in a bad shape ATM.)

However, the hotplug subsystem and udev might happen to create /dev/rpl when the kernel module is loaded, for the misc subsystem calls the hotplug layer. /dev/rpl is not touched if it exists, and since the userspace hotplug components will be shutdown before the module is unloaded, the node will be kept (unless /dev is on a ram disk). If it exists, make sure nobody else than root can read it, usually mode 0400.

Data structures >

Everytime the kernel functions for reading/ writing from/to a terminal are executed, the call chain is extened into the rpldev hooks, i.e. an external function in the rpldev kernel module is called, which packs the tty buffer into so-called packets, which are then returned as /dev/rpl is read.

A packet consists of a device number, magic byte combined with kernel version, size of the data, and of course, the data itself. All fields are little-endian and packed, i.e. there are no alignment gaps. It can be represented in this C struct:

struct rpld_packet {
    uint32_t dev, dev2;
    uint16_t size;
    uint8_t event, magic;
} __attribute__((packed));

The data itself is actually not included in the struct, since it is of dynamic length. For further reference, the struct alone will be called packet header, whereas packet header plus data (or payload) equals packet. There are no byte-aligning gaps between the members, i.e. it is a so-called packed structure. (No pun between packet and packed.)

The .dev member contains the device number on which the event occurred. .dev2 is filled in for pseudo terminals (PTY) with the device number of "the other side". Both the master and the slave side of a pty pair can generate events, and as such, packets might have the major side's device number in .dev, while others have it in .dev2. Though, there is deterministic logic in it, and you can usually tell when a packet has either side in either field.

The following event types exist:

enum {
    EVT_INIT = 'i',
    EVT_OPEN = 1,
    EVT_READ = 2,
    EVT_WRITE = 3,
    EVT_IOCTL = 4,
    EVT_CLOSE = 5,
    EVT_DEINIT = 'd',
};

EVT_INIT is generated is generated when the tty is initialized. This usually happens when you open() it the first time.

EVT_OPEN, EVT_READ, EVT_WRITE and EVT_CLOSE are generated whenever an open(), read(), write() or close(), respectively, is done.

EVT_DEINIT is generated when the tty is about to be deinitialized. In theory, you do not know when a device will do this (i.e. deferred deinit). However, you've got the Kernel sources, and as such know when it actually happens (e.g. when the last open filedescriptor is closed).

EVT_IOCTL is generated when ioctl() is called on a tty. The data will consist of one uint32_t describing the cmd parameter. (See ioctl(2).)

 

by Jan Engelhardt