This document is meant to help early adopters help me test vdev, and make sure it works with a wide variety of hardware. The reader is expected to be familiar with basic shell commands and have basic familiarity with Makefiles.
The steps to compile and prepare vdevd for testing are as follows:
$ git clone https://github.com/jcnelson/vdev vdev
$ cd vdev
$ make -C vdevd
As a result of these commands, you will have checked out the latest copy of vdev's source code, and built and installed the hotplug daemon vdevd
.
vdevd
is capable of running on a live system with udevd
or mdev
or the like, but we will need to ensure it creates device nodes somewhere else besides /dev
. To do so, we'll set up a tmpfs
mount:
$ mkdir vdev-test
$ sudo mount -t tmpfs none vdev-test/
vdevd
will populate the directory vdev-test/
with device nodes in the next step.
vdevd
has the option of scanning the contents of /sys
and exiting once it finishes. We call this "run once" mode. It's useful for generating a static /dev
, or updating a previously-generated static /dev
with only the device files that correspond to hardware plugged into your computer. We will use this feature to test vdevd
.
From the root of the source code repository you checked out in step 1, the command to have vdevd
generate a fake /dev
is:
$ sudo build/sbin/vdevd -v2 -c example/vdevd.conf -l /tmp/vdev.log --once vdev-test/
vdevd
should print out some runtime setup information to your console, run for a few seconds, and exit normally. If you run ls vdev-test/
, you should see a bunch of device files. All debugging information will have been written to /tmp/vdev.log
.
If you'd like, feel free to explore the vdev-test/
directory and skim through the /tmp/vdev.log
logfile, and note any missing or extra device files and symlinks.
You might notice the directory vdev-test/vdev/
. This directory contains device attributes for each device processed (specifically, the contents of the uevent
packet vdevd
processed, as well as a few other things documented in the Appendix). Programs that need to monitor the system for devices and query device properties need only look in this directory.
Once you're satisfied, please run tree /dev
and tree vdev-test/
, and send me the resulting directory tree listings so I can figure out what device files and symlinks vdevd
failed to create. Also, please send me the logfile /tmp/vdev.log
.
If either the listings or the /tmp/vdev.log
file contains information you'd rather not share, please take the time to trim that information out (and please note it in the listings). In particular /tmp/vdev.log
will contain a full listing of all the hardware plugged into your computer, including device serial numbers and network MAC addresses. I will keep the information to myself and not share with anyone, but nevertheless the information will be sent over the public Internet.
Once you're satisfied, please email them to judecn@devuan.org
.
Thank you very much for reading!
vdevd
has a --help
switch that prints out the directives it understands. In particular, you can:
- make it run in the foreground with
-f
. This is great if you want to watch it process hardware events (but this requires-v1
or-v2
). - change the log verbosity with
-v $LEVEL
. Substitute$LEVEL
with 0 for logging only drastic errors; 1 for logging non-critical notices, and 2 for logging debug messages. - change the log file with
-l $PATH_TO_LOGFILE
. If you omit this,vdevd
logs to stdout. - write a PID file with
-p $PATH_TO_PIDFILE
. This is useful only when runningvdevd
as a daemon.
vdevd
works internally by bufferring up device events from the kernel, matching device events against "actions," and running an action's associated script if it matches. The vdev project comes with a set of actions that are meant to make vdevd
behave as close as possible to udev. You can find them in example/actions/
, and you can find the Linux-specific scripts and binaries the actions execute in vdevd/helpers/LINUX/
.
Actions are defined as ini-files. Unless stated otherwise, all action fields are optional. All fields must match the device event for the action's command to be executed. The fields are:
event
: Required. Use "add" to match a device-add event, "remove" to match a device-remove event, "change" to match a device-change event (such as a battery level changing), or "any" to match any device event.path
: This is an extended POSIX regular expression that matches the kernel-given device path (such assda
orinput/mice
) to the action.type
: This is either "block" or "char", which will match the event only if it it is for a block or character device, respectively. Not all devices are representable by block or character device files, however, which is why this field is optional.OS_*
: Any field prefixed withOS_
matches an OS-specific device attribute. On Linux, these include names ofuevent
fields. For example, an action can match a device's subsystem using theOS_SUBSYSTEM
field. If an empty value is given (e.g. "OS_SUBSYSTEM=
"), then the action will match any value as long as the device attribute is present in the device event (for example, a Linuxuevent
packet that does not haveSUBSYSTEM
defined will not match an action withOS_SUBSYSTEM=
).
Once a device event is encountered that matches all of an action's fields, vdevd
runs the commands specified by the action's ini file. The fields that describe the commands are:
rename_command
: This is a shell command to run to generate the path to the device file to create. It will be evaluated after the device event matches the action, but before the device file is created. The command must write the desired path to stdout. Its output will be truncated at 4,096 characters (which isPATH_MAX
on most filesystems). Note that not all devices have paths given by the kernel.command
: This is the shell command to run once the device file has been successfully created. Unless specified otherwise,vdevd
will run this as a subprocess--it will wait until the command has completed before processing the next action.async
: If set to "True", this tellsvdevd
to continue processing the action immediately after running itscommand
. This is useful for long-running device setup tasks, where it is undesirable to blockvdevd
.daemonlet
: If set to "True", this tellsvdevd
to run the command as a daemonlet. See "Advanced Device Handling" below for a description of what this means.
Caveat: vdevd
matches a device event against actions according to their files' lexographic order. Moreover, it processes device events sequentially, in the order in which they arrive. This is also true for the Linux port--the kernel's SEQNUM field is ignored at this time (but is passed on to actions).
vdevd
communicates device information to action commands using environment variables. When a command
or rename_command
runs, the following environment variables will be set:
$VDEV_ACTION
: This is theevent
field of the action (i.e. "add", "remove", "change", or "any").$VDEV_DAEMONLET
: If set to 1, then the command is being invoked as a daemonlet (see the "Advanced Device Handling" subsection below).$VDEV_CONFIG_FILE
: This is the absolute path to the configuration filevdevd
is using.$VDEV_HELPERS
: This is the absolute path to the directory containingvdevd
's helper programs.$VDEV_INSTANCE
: This is a randomly-generated string that corresponds to this running intance ofvdevd
. It will be different on each invocation ofvdevd
.$VDEV_GLOBAL_METADATA
: The absolute path to the metadata directory into whichvdevd
writes metadata (e.g./dev/metadata
).$VDEV_LOGFILE
: If specified, this is the path tovdevd
's logfile.$VDEV_MAJOR
: If the device event corresponds to a block or character device, this is the device file's major number.$VDEV_METADATA
: If the device is given a path (either by the kernel or therename_command
output), this is the absolute path to the directory to contain the device's metadata.$VDEV_MINOR
: If the device event corresponds to a block or character device, this is the device file's minor number.$VDEV_MODE
: If the device event corresponds to a block or character device, this is the string "block" or "char" (respectively).$VDEV_MOUNTPOINT
: This is the absolute path to the directory in which the device files will be created. For example, this is usually/dev
.$VDEV_OS_*
: Any OS-specific device attributes will be encoded by name, prefixed withVDEV_OS_
. For example, on Linux, the SUBSYSTEM field in the device'suevent
packet will be exported as$VDEV_OS_SUBSYSTEM
. Similarly, the DEVPATH field in a device'suevent
packet will be exported as$VDEV_OS_DEVPATH
.$VDEV_PATH
: If the device is given a path (either by the kernel or therename_command
output), this is the path to the device file relative to$VDEV_MOUNTPOINT
. The absolute path to the device file can be found by$VDEV_MOUNTPOINT/$VDEV_PATH
. Note that not all devices have device files (such as batteries, PCI buses, etc.).
Advanced Device Handling
By default, vdevd
will fork()
and exec()
the command
for each device request in the system shell. However, as an optimization, vdevd
can run the command as a daemonlet. This means that the command
will be expected to stay resident once it proceses a device request, and receive and process subsequent device requests from vdevd
instead of simply exiting after each one. Doing so saves vdevd
from having to fork()
and exec()
the same command over and over again for common types of devices, and lets it avoid having to repeatly incur long command
start-up times. It also allows the administrator to define stateful or long-running actions that can work on sets of devices.
The programming model for daemonlet commands is as follows:
vdevd
willfork()
andexec()
the command directly. It will not invoke the system shell to run it.vdevd
will write a sequence of newline-terminated strings to the command'sstdin
, followed by an empty newline string. These strings encode the request's environment variables, and are in the formNAME=VALUE\n
.- The
command
is expected to write an ASCII-encoded exit code tostdout
to indicate the success/failure of processing the request. 0 indicates success, and non-zero indicates failure.
If the command
crashes or misbehaves, vdevd
will log as such and attempt to restart it.
NOTE: These instructions are Debian- and Devuan-specific, and very hacky. Use at your own risk.
WARNING: Readers are expected to know how to fix a broken initramfs and a broken bootsystem if they try this.
Running make && sudo make install
will get you most of the way towards installing vdev. But to use it, you will need to disable udev, enable vdev, and rebuild your initramfs to include vdev instead of udev.
On Debian and most Debian-derived distributions, it is possible to generate an initramfs image with this command:
$ cd example/ && make initramfs
This will generate an initramfs image in example/
, which can be installed with your bootloader of choice.
To enable vdev and disable udev in the init system, the command is
$ cd example/ && make install-initscript
I'm still working on the packaging scripts that will do all of this automatically.
Thanks for reading! Please send any questions, comments, and bug reports to the Devuan mailing list (dng@lists.dyne.org
)