DEVD.CONF(5)

πŸ“¦
version 15.1 Β· 2 versions
, in freebsd 15.1

πŸŽ€ DEVD.CONF(5) πŸŽ€

bestie, this is the DEVD.CONF(5) page from the File Formats Manual β€” the whole vibe is the configuration file format for devd(8). no cap, it’s giving very specific config-file energy. πŸ’…

✨ NAME ✨

devd.conf β€” configuration file format for devd(8)

🌸 DESCRIPTION 🌸

πŸ’– General Syntax πŸ’–

A devd(8) configuration has two general features: statements and comments. Every statement ends with a semicolon. Many statements can contain substatements, and those are also terminated with a semicolon. πŸŽ€

The following statements are supported:

  • attach β€” specifies various matching criteria and actions to perform when a newly attached device matches said criteria.
  • detach β€” specifies various matching criteria and actions to perform when a newly detached device matches said criteria.
  • nomatch β€” specifies various matching criteria and actions to perform when no device driver currently loaded in the kernel claims a (new) device.
  • notify β€” specifies various matching criteria and actions to perform when the kernel sends an event notification to userland.
  • options β€” specifies various options and parameters for the operation of devd(8).

Statements may occur in any order in the configuration file, and may be repeated as often as required. Further details on the syntax and meaning of each statement and their substatements are explained below. πŸ’–

Each statement, except options, has a priority (an arbitrary number) associated with it, where 0 is defined as the lowest priority. If two statements match the same event, only the action of the statement with highest priority will be executed. In this way generic statements can be overridden for devices or notifications that require special attention. πŸ‘‘

The general syntax of a statement is:

statement priority {
        substatement "value";
        ...
        substatement "value";
};

πŸŽ€ Sub-statements πŸŽ€

The following sub-statements are supported within the options statement.

  • directory "/some/path"; β€” adds the given directory to the list of directories from which devd(8) will read all files named "*.conf" as further configuration files. Any number of directory statements can be used.
  • pid-file "/var/run/devd.pid"; β€” specifies PID file.
  • set regexp-name "(some|regexp)"; β€” creates a regular expression and assigns it to the variable regexp-name. The variable is available throughout the rest of the configuration file. If the string begins with !, it matches if the regular expression formed by the rest of the string does not match. All regular expressions have an implicit ^$ around them.

The following sub-statements are supported within the attach and detach statements.

  • action "command"; β€” command to execute upon a successful match. Example "/etc/pccard_ether $device-name start".
  • class "string"; β€” this is shorthand for match "class" "string".
  • device-name "string"; β€” this is shorthand for match "device-name" "string". This matches a device named string, which is allowed to be a regular expression or a variable previously created containing a regular expression. The device-name variable is available for later use with the action statement.
  • match "variable" "value"; β€” matches the content of value against variable; the content of value may be a regular expression. Not required during attach nor detach events since the device-name statement takes care of all device matching. For a partial list of variables, see below.
  • media-type "string"; β€” for network devices, media-type will match devices that have the given media type. Valid media types are: "Ethernet", "802.11", and "ATM".
  • subdevice "string"; β€” this is shorthand for match "subdevice" "string".

The following sub-statements are supported within the nomatch statement.

  • action "command"; β€” same as above.
  • match "variable" "value"; β€” matches the content of value against variable; the content of value may be a regular expression. For a partial list of variables, see below.

The following sub-statements are supported within the notify statement. The notify variable is available inside this statement and contains, a value, depending on which system and subsystem that delivered the event. πŸ¦‹

  • action "command"; β€” command to execute upon a successful match. Example "/etc/rc.d/power_profile $notify".
  • match "system | subsystem | type | notify" "value"; β€” any number of match statements can exist within a notify statement; value can be either a fixed string or a regular expression. Below is a list of available systems, subsystems, and types.
  • media-type "string"; β€” see above.

🌈 Variables that can be used with the match statement 🌈

A partial list of variables and their possible values that can be used together with the match statement. The variables are published by the bus based on characteristics of the device that generated the event (for device events). Variables for other classes of events are dependent on those events. πŸ’œ

  • * β€” the entire message from the current event.
  • _ β€” the entire message from the current event, after the initial type character.
  • timestamp β€” the time this event was processed, in seconds since 1970 dot fraction.
  • bus β€” device name of parent bus.
  • cdev β€” device node path if one is created by the devfs(4) filesystem.
  • class β€” device class.
  • comm β€” executable name (kernel).
  • core β€” path to core file (kernel).
  • device β€” device ID.
  • devclass β€” device Class (USB).
  • devsubclass β€” device Sub-class (USB).
  • device-name β€” name of attached/detached device.
  • endpoints β€” endpoint count (USB).
  • function β€” card functions.
  • interface β€” interface ID (USB).
  • intclass β€” interface Class (USB).
  • intprotocol β€” interface Protocol (USB).
  • intsubclass β€” interface Sub-class (USB).
  • jail β€” jail name for the process triggering the rule (RCTL).
  • mode β€” peripheral mode (USB).
  • notify β€” match the value of the notify variable.
  • parent β€” parent device.
  • pid β€” PID of the process triggering the rule (RCTL).
  • port β€” hub port number (USB).
  • product β€” product ID (USB).
  • release β€” hardware revision (USB).
  • ruid β€” real UID of the process triggering the rule (RCTL).
  • rule β€” rule (RCTL).
  • sernum β€” serial Number (USB).
  • slot β€” card slot.
  • subvendor β€” sub-vendor ID (PCI).
  • subdevice β€” sub-device ID (PCI).
  • subsystem β€” matches a subsystem of a system, see below.
  • system β€” matches a system type, see below.
  • type β€” type of notification, see below.
  • vendor β€” vendor ID.

πŸ”₯ Notify matching πŸ”₯

A partial list of systems, subsystems, and types used within the notify mechanism.

Here’s the System / Subsystem / Type situation, with descriptions attached. πŸ’–

  • ACPI β€” events related to the ACPI Subsystem.
    • ACPI, ACAD β€” AC line state ($notify=0x00 is offline, 0x01 is online).
    • ACPI, Button β€” button state ($notify=0x00 is power, 0x01 is sleep).
    • ACPI, CMBAT β€” battery events.
    • ACPI, Dock β€” dock state ($notify=0x00 is undocked, 0x01 is docked).
    • ACPI, Lid β€” lid state ($notify=0x00 is closed, 0x01 is open).
    • ACPI, PROCESSOR β€” processor state/configuration ($notify=0x81 is a change in available Cx states).
    • ACPI, Resume β€” resume notification.
    • ACPI, Suspend β€” suspend notification.
    • ACPI, Thermal β€” thermal zone events.
  • AEON, power, press β€” the power button on an Amiga has been pressed.
  • CAM β€” events related to the cam(4) system.
    • CAM, periph β€” events related to peripheral devices.
    • CAM, periph, error β€” generic errors.
    • CAM, periph, timeout β€” command timeouts.
  • CARP β€” events related to the carp(4) protocol.
    • CARP, vhid@inet β€” the "subsystem" contains the actual CARP vhid and the name of the network interface on which the event took place.
    • CARP, vhid@inet, MASTER β€” node become the master for a virtual host.
    • CARP, vhid@inet, BACKUP β€” node become the backup for a virtual host.
  • coretemp β€” events related to the coretemp(4) device.
    • coretemp, Thermal β€” notification that the CPU core has reached critical temperature.
    • coretemp, Thermal, temperature β€” string containing the temperature of the core that has become too hot.
  • DEVFS β€” system listed on its own in the table.
    • DEVFS, CDEV, CREATE β€” the devfs(4) node is created.
    • DEVFS, CDEV, DESTROY β€” the devfs(4) node is destroyed.
  • ETHERNET, inet, IFATTACH β€” notification when the default VNET instance of the inet interface is attached.

πŸ’Ύ GEOM β€” the disk-ish corner of the universe

Okay so GEOM is all the events coming out of the geom(4) framework. The difference compared to DEVFS is that GEOM only includes disk-like devices. That's it, that's the whole vibe check. πŸ’…

  • GEOM β€” Events related to the geom(4) framework. The difference compared to DEVFS is that GEOM only includes disk-like devices.
  • GEOM / DEV / CREATE β€” A geom(4) provider is created. New disk just dropped ✨
  • GEOM / DEV / DESTROY β€” A geom(4) provider is destroyed. gone, reduced to atoms 😭
  • GEOM / DEV / GEOM::physpath β€” The physical path of a device has changed.
  • GEOM / DEV / GEOM::rotation_rate β€” The rotation rate of the disk has changed.
  • GEOM / DEV / MEDIACHANGE β€” Physical media has changed.
  • GEOM / DEV / SIZECHANGE β€” A geom(4) provider size has changed.

🌐 IFNET β€” network interface drama

  • IFNET β€” the base system. Lowkey the star of the show here is the subsystem field:
Heads up bestie: for every IFNET event, the β€œsubsystem” is the actual name of the network interface on which the event took place. Not a category, not a label β€” the interface name itself. iconique πŸŽ€
  • IFNET / inet β€” the β€œsubsystem” is the actual name of the network interface on which the event took place.
  • IFNET / inet / LINK_UP β€” Carrier status changed to UP. we're so back πŸ”₯
  • IFNET / inet / LINK_DOWN β€” Carrier status changed to DOWN. it's giving disconnected πŸ’€
  • IFNET / inet / ATTACH β€” The network interface is attached to the system.
  • IFNET / inet / DETACH β€” The network interface is detached from the system.
  • IFNET / inet / RENAME β€” The network interface is renamed.
  • IFNET / inet / ADDR_ADD β€” The network interface address added.
  • IFNET / inet / ADDR_DEL β€” The network interface address removed.

🧠 kernel β€” the big boss events

  • kernel / signal / coredump β€” Notification that a process has crashed and dumped core. rip bozo, we have a core file now πŸ™ˆ
  • kernel / power / resume β€” Notification that the system has woken from the suspended state. good morning sunshine β˜€οΈ

πŸ’½ nvme β€” controller tea

Controller events provide the controller name (for example, nvme0) in $name. Slay, now you know who's talking to you.

  • nvme / controller β€” Controller events provide the controller name (for example, nvme0) in $name.
  • nvme / controller / SMART_ERROR β€” A SMART Critical Warning State change has happened. $state has a hex bitmask of the bits that changed, as defined in the NVMe Standard for Critical Warning field of log page 2 β€œSMART / Health Information Log”:
    • 0x1 β€” Spare capacity below threshold
    • 0x2 β€” Temperature outside acceptable range
    • 0x4 β€” Reliability of media degraded
    • 0x8 β€” Media placed into read-only mode
    • 0x10 β€” Volatime memory backup failure
    • 0x20 β€” Persistent memory read-only or degraded
  • nvme / controller / RESET β€” A controller reset event has happened. $event is one of β€œstart”, β€œsuccess”, and β€œtimed_out” representing the start of a controller reset, the successful completion of a controller reset, or a timeout while waiting for the controller to reset, respectively.
  • nvme / controller / RECONNECT β€” An NVMe over Fabrics host has disconnected and is requesting a reconnect. bestie please come back πŸ₯Ί

πŸ”‹ PMU β€” the power management unit chronicles

PMU is your notification hookup for events from various types of Power Management Units. There's a lot here, so buckle up 🎒

⚑ PMU / AC β€” wall power behaviour

  • PMU / AC β€” Notifications of AC power related events.
  • PMU / AC / overvoltage β€” An over-voltage condition was detected on the AC power line. too much voltage, that's not slay 😬
  • PMU / AC / plugged β€” Power has been applied to the AC power line.
  • PMU / AC / unplugged β€” Power has been removed from the AC power line. on battery now, stay calm 🫢

πŸ”‹ PMU / Battery β€” the whole battery saga

  • PMU / Battery β€” the battery subsystem itself.
  • PMU / Battery / absent β€” Battery is no longer absent. not me misreading that β€” yes, β€œno longer absent”, that's the wording, copy it exactly ✨
  • PMU / Battery / charged β€” The battery has become charged. full bars energy πŸ‘‘
  • PMU / Battery / charging β€” The battery has started charging.
  • PMU / Battery / disconnected β€” The battery has been disconnected.
  • PMU / Battery / high-temp β€” The battery reported a temperature over the limit. she's running hot πŸ”₯
  • PMU / Battery / low-temp β€” The battery reported a temperature under the limit.
  • PMU / Battery / plugged β€” The battery has become plugged (eg connected).
  • PMU / Battery / shutdown-threshold β€” The power in the battery has fallen below the shutdown threshold. you have approximately zero seconds left, save your work πŸ’€
  • PMU / Battery / warning-threshold β€” The power in the battery has fallen below the warn the user threshold.

πŸŽ›οΈ PMU / Button β€” button go press

  • PMU / Button / pressed β€” A button on a adb(4) or pmu(4) has been pressed.

⌨️ PMU / keys β€” keyboard keys doing things

  • PMU / keys β€” One of the keys on the adb(4) keyboard has been pressed.
  • PMU / keys / brightness β€” A brightness level change has been requested. Direction is in the $notify variable.
  • PMU / keys / mute β€” The mute key 🎀
  • PMU / keys / volume β€” A volume level change has been requested. Direction is in the $notify variable.
  • PMU / keys / eject β€” An ejection has been requested.

πŸšͺ PMU / lid β€” laptop lid lore

  • PMU / lid / close β€” The pmc(4) device has detected the lid closing.
  • PMU / lid / open β€” The pmc(4) device has detected the lid openinging. (That's the manpage's spelling, not mine, I promise β€” keeping it forever πŸ’…)

πŸ”Œ PMU / POWER β€” the AC line state report

  • PMU / POWER / ACLINE β€” The pmc(4) device has detected an AC line state ($notify=0x00 is offline, 0x01 is online).

πŸ”— PMU / USB β€” power pins going feral

  • PMU / USB / overvoltage β€” An over-voltage condition on the power lines for the USB power pins.
  • PMU / USB / plugged β€” A device has been plugged into a USB device.
  • PMU / USB / undervoltage β€” An under-voltage condition on the power lines for the USB power pins.
  • PMU / USB / unplugged β€” A device has been unplugged from a USB device.

πŸ“ RCTL β€” resource control events

  • RCTL β€” Events related to the rctl(8) framework.
  • RCTL / rule / matched β€” A rule with action specified as "devctl" was triggered. the rule did its little job, periodt ✨

πŸ”Œ USB β€” plug it in, pull it out

  • USB β€” Events related to the USB subsystem.
  • USB / DEVICE / ATTACH β€” USB device is attached to the system.
  • USB / DEVICE / DETACH β€” USB device is detached to the system.
  • USB / INTERFACE / ATTACH β€” USB interface is attached to a device.
  • USB / INTERFACE / DETACH β€” USB interface is detached from a device.

πŸ—‚οΈ VFS β€” filesystem mounting behaviour

  • VFS β€” Events from the vfs system.
  • VFS / FS β€” Events that change what is mounted to the system.
  • VFS / FS / MOUNT β€” Notification of a filesystem is mounted for the first time.
  • VFS / FS / REMOUNT β€” Notification of a filesystem is remounted (whether or not the options actually change).
  • VFS / FS / UNMOUNT β€” Notification of a filesystem being unmounted. bye bestie, hope to see you at the next mount πŸ¦‹
  • System VT, Subsystem BELL, Type RING β€” bestie, the console bell literally rang. That's it, that's the notification. Peep vt(4) for the whole story.

  • System ZFS, Subsystem ZFS β€” all the tea about the ZFS subsystem lives here. See zfsd(8) and /etc/devd/zfs.conf for the receipts.

  • System SND β€” events spilling out of the sound(4) driver, no cap.
  • System SND, Subsystem CONN, Type IN β€” an input device got connected, and it's named in the cdev variable. πŸ’–
  • System SND, Subsystem CONN, Type OUT β€” same energy but output, also named in cdev.
  • System SND, Subsystem CONN, Type NODEV β€” zero devices connected. Nobody's home. πŸ’€

So like, a link state change to UP on the interface "fxp0" would give you this notify event, iconic:

system=IFNET subsystem=fxp0 type=LINK_UP

And an AC line state change to "offline"? That one drops this event:

system=ACPI subsystem=ACAD notify=0x00

πŸŽ€ Comments πŸŽ€

Okay so comments can show up literally anywhere whitespace can show up in a config file. And because the devs wanted to appeal to programmers of all kinds, you can write them C-style, C++-style, or shell/Perl-style. Versatile queen behavior. πŸ‘‘

C-style comments start with the two characters /* (slash, star) and end with */ (star, slash). Because they're completely delimited by those characters, you can use them to comment only a portion of a line, or to span multiple lines. Slay.

⚠️ C-style comments cannot be nested. Like, at all. This next one is not valid, because the whole comment ends at the first */:
/* This is the start of a comment.
   This is still part of the comment.
/* This is an incorrect attempt at nesting a comment. */
   This is no longer in any comment. */

C++-style comments start with the two characters // (slash, slash) and keep going to the end of the physical line. They cannot be continued across multiple physical lines β€” so if you want one logical comment to span multiple lines, every single line has to carry its own // pair. Example time:

// This is the start of a comment.  The next line
// is a new comment, even though it is logically
// part of the previous comment.

πŸ¦‹ Notes on Variable Expansion πŸ¦‹

Variables get expanded when you put a $ sign in front of them. Any text right after that sign β€” starting with a letter, a minus sign -, an underscore _, or an asterisk * β€” counts as an internal variable and gets expanded accordingly. And if that variable doesn't exist? It just silently expands to an empty string. No drama, no error, just nothing. 😭

So consequently, if your intention is to pass a sh(1) variable, it has to be surrounded by braces so it doesn't get mistaken for an internal variable. Periodt.

See "EXAMPLES" for a detailed example, iykyk.

To prevent issues with special shell characters, the following happens for each variable $foo:

  1. The characters $' are inserted.
  2. The string $foo is removed.
  3. The value of the foo variable is inserted into the buffer with all single quote characters prefixed by a backslash.
  4. A final ' is inserted.

See sh(1) for what this construct means. It's safe in all contexts β€” except one: inside single quotes. 🫣 So if foo=meta and bar=var, then a rule like this:

action "echo '$foo $bar'";

will be presented to the shell via system(3) as:

echo '$'meta' $'var''

which produces this as its output:

$meta $var

...which is an unanticipated result, bestie. A future version of this software will change this behavior. Users are discouraged from using single quotes inside an action value without due care. You've been warned. πŸ’…

The above should be written as:

action "echo $foo' '$bar"

to produce a single argument to echo. Given the above expansion, juxtaposing bare variables with single quote expressions will produce the right output, regardless of the value of the variable. Chef's kiss. 🧚

✨ FILES ✨

  • /etc/devd.conf β€” the devd(8) configuration file.
  • /etc/devd β€” a directory that devd searches for additional configuration files.
  • /usr/local/etc/devd β€” a directory that devd also searches for additional configuration files.

🌈 EXAMPLES 🌈

#
# This will catch link down events on the interfaces fxp0 and ath0
#
notify 0 {
        match "system"                  "IFNET";
        match "subsystem"               "(fxp0|ath0)";
        match "type"                    "LINK_DOWN";
        action "logger $subsystem is DOWN";
};

#
# Match lid open/close events
# These can be combined to a single event, by passing the
# value of $notify to the external script.
#
notify 0 {
        match "system"                  "ACPI";
        match "subsystem"               "Lid";
        match "notify"                  "0x00";
        action "logger Lid closed, we can sleep now!";
};

notify 0 {
        match "system"                  "ACPI";
        match "subsystem"               "Lid";
        match "notify"                  "0x01";
        action "logger Lid opened, the sleeper must awaken!";
};

#
# Match a USB device type
#
notify 0 {
        match "system"                  "USB";
        match "subsystem"               "INTERFACE";
        match "type"                    "ATTACH";
        match "intclass"                "0x0e";
        action "logger USB video device attached";
};

#
# Try to configure ath and iwn devices with pccard_ether
# as they are attached.
#
attach 0 {
        device-name "(ath|iwn)[0-9]+";
        action "/etc/pccard_ether $device-name start";
};

#
# Stop ath and iwn devices as they are detached from
# the system.
#
detach 0 {
        device-name "(ath|iwn)[0-9]+";
        action "/etc/pccard_ether $device-name stop";
};

The following example illustrates the difference between internal and shell variables β€” this is the one, watch closely:

attach 20 {
        device-name             "umodem[0-9]+";
        match "vendor"          "0x2047";
        match "product"         "0x001(0|3|4)";
        match "interface"       "0";
        action "cd /dev; p=$product; dn=$device-name; \
                un=$(sysctl -n dev.umodem.${dn#umodem}.ttyname); \
                chmod 666 cua${un}; ln -sf cua${un} mspfet${p#0x}";
};

So product and device-name are internal variables. Their contents get initially assigned to the shell variables p and dn, respectively. Then variable dn is used inside a shell command substitution, assigning to shell variable un. Finally, that shell variable is used in two other shell statements, where it needs to be wrapped in braces in order to prevent it from being considered an internal variable to devd. The way it all clicks together?? Obsessed. πŸŽ€

The installed /etc/devd.conf has many additional examples, so go snoop.

πŸ‘‘ SEE ALSO πŸ‘‘

cam(4), coretemp(4), devfs(4), re_format(7), devd(8)

πŸ’€ BUGS πŸ’€

The variable expansion's interaction with single quotes is suboptimal and surprising. Like, genuinely rude of it. πŸ™ˆ


That's the whole vibe, bestie β€” go forth and write the prettiest devd config of your life. This slice of manpage lore is from the Debian edition, dated February 26, 2026 (yes, future queen behavior, we don't question the calendar ✨). Mwah, love u, bye! πŸ«ΆπŸ’œ

πŸ“¦ where this page comes from
  • freebsd 15.1: base 15.1
  • πŸ’– girlified by deepseek-ai/DeepSeek-V4.1-Flash-1017 on : a language model's rewrite of the original, under its terms