A device-file manager and filesystem for *nix
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

12 KiB

How to Test vdev

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.

Step 1: Compile and Install vdev

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.

Step 2: Set up a Fake /dev

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.

Step 3: Generate a Fake /dev

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.

Step 4: Inspect the Fake /dev and Logfile

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.

Step 5: Send Me a Listing of /dev and the Logfile

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!

Appendix A: A Crash-Course to vdevd

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 running vdevd 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 as sda or input/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 with OS_ matches an OS-specific device attribute. On Linux, these include names of uevent fields. For example, an action can match a device’s subsystem using the OS_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 Linux uevent packet that does not have SUBSYSTEM defined will not match an action with OS_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 is PATH_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 tells vdevd to continue processing the action immediately after running its command. This is useful for long-running device setup tasks, where it is undesirable to block vdevd.
  • daemonlet: If set to “True”, this tells vdevd 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 the event 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 file vdevd is using.
  • $VDEV_HELPERS: This is the absolute path to the directory containing vdevd's helper programs.
  • $VDEV_INSTANCE: This is a randomly-generated string that corresponds to this running intance of vdevd. It will be different on each invocation of vdevd.
  • $VDEV_GLOBAL_METADATA: The absolute path to the metadata directory into which vdevd writes metadata (e.g. /dev/metadata).
  • $VDEV_LOGFILE: If specified, this is the path to vdevd'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 the rename_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 with VDEV_OS_. For example, on Linux, the SUBSYSTEM field in the device’s uevent packet will be exported as $VDEV_OS_SUBSYSTEM. Similarly, the DEVPATH field in a device’s uevent packet will be exported as $VDEV_OS_DEVPATH.
  • $VDEV_PATH: If the device is given a path (either by the kernel or the rename_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:

  1. vdevd will fork() and exec() the command directly. It will not invoke the system shell to run it.
  2. vdevd will write a sequence of newline-terminated strings to the command’s stdin, followed by an empty newline string. These strings encode the request’s environment variables, and are in the form NAME=VALUE\n.
  3. The command is expected to write an ASCII-encoded exit code to stdout 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.

Appendix B: Booting with vdevd

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)