Getting udev to describe your system as assertions

Emery Hemingway came up with an excellent hack for getting udev to automatically populate a dataspace with assertions describing the devices attached to a Linux system. As devices are plugged in, reconfigured, and unplugged, the system automatically creates, updates and removes files in /run/etc/syndicate/hardware describing each device.

The trick is to install a udev RUN rule to execute a script which uses udevadm info --json=short to write out a Preserves file. Preserves is, syntactically, a superset of JSON, so it’s possible to directly use JSON output from programs like this as Preserves.

A syndicate-server can then be configured to load all files in /run/etc/syndicate/hardware into a dataspace by placing something like

1
2
let ?devices = dataspace
<require-service <config-watcher "/run/etc/syndicate/hardware" { config: $devices }>>

in the server’s configuration.

udev configuration and script

The run rule, placed in a file named something like /usr/local/lib/udev/rules.d/50-syndicate.rules, should be something like this:

1
ACTION=="add|change|move|remove", RUN+="/usr/local/bin/udev-syndicate-rule.sh"

And the script that does the work of maintaining the Preserves files in response to trigger events from udev, placed in /usr/local/bin/udev-syndicate-rule.sh, should look something like this:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#!/bin/sh
# Script based on https://git.syndicate-lang.org/ehmry/syndev#assertions-from-udev

if [ -z "$DEVNAME" -o -z "$MAJOR" -o -z "$MINOR" ]
then
        exit
fi

HARDWARE_DIR=/run/etc/syndicate/hardware
PR_FILE=$HARDWARE_DIR/$MAJOR-$MINOR.pr

mkdir -p $HARDWARE_DIR

case "$ACTION" in
        remove)
                rm -f $PR_FILE
                ;;
        *)
                echo '<device ' > $PR_FILE
                udevadm info --json=short $DEVNAME >> $PR_FILE
                echo '>' >> $PR_FILE
                ;;
esac

After adding the rule and the script to your system, you will need to either reboot or run

1
udevadm control --reload-rules && udevadm trigger

to get things started.

Example output

After installing the script on my system, I see about 250 files appear in /run/etc/syndicate/hardware.

For example, if I pipe /run/etc/syndicate/hardware/13-78.pr through preserves-tool for pretty-printing, I see:

<device {
  "CURRENT_TAGS": ":power-switch:"
  "DEVNAME": "/dev/input/event14"
  "DEVPATH": "/devices/pci0000:00/0000:00:01.1/0000:01:00.0/0000:02:00.0/0000:03:00.1/sound/card1/input14/event14"
  "ID_INPUT": "1"
  "ID_INPUT_SWITCH": "1"
  "ID_PATH": "pci-0000:03:00.1"
  "ID_PATH_TAG": "pci-0000_03_00_1"
  "ID_PROCESSING": "1"
  "LIBINPUT_DEVICE_GROUP": "0/0/0:ALSA"
  "MAJOR": "13"
  "MINOR": "78"
  "SUBSYSTEM": "input"
  "SYSNAME": "event14"
  "SYSNUM": "14"
  "TAGS": ":power-switch:"
  "USEC_INITIALIZED": "8598957"
}>