SD_DEV..._PARENT(3)

πŸ’– SD_DEV..._PARENT(3) πŸ’–

okay bestie, sit down, hydrate, because today we're talking about device enumeration and it is lowkey the most useful thing ever. This page covers a whole squad of sd_device_enumerator filter functions. Every single one of them is out here adding a filter to your device enumerator. it's giving ✨curated vibes✨.


✨ NAME ✨

sd_device_enumerator_add_match_parent, sd_device_enumerator_add_match_property, sd_device_enumerator_add_match_property_required, sd_device_enumerator_add_match_subsystem, sd_device_enumerator_add_match_sysattr, sd_device_enumerator_add_match_sysname, sd_device_enumerator_add_nomatch_sysname, sd_device_enumerator_add_match_tag, sd_device_enumerator_allow_uninitialized, sd_device_enumerator_add_all_parents β€” they all add a filter to the device enumerator. that's it, that's the job. 🫢


πŸ“œ SYNOPSIS πŸ“œ

#include <systemd/sd-device.h>

int sd_device_enumerator_add_match_parent(sd_device_enumerator *enumerator,
                                          sd_device *parent);

int sd_device_enumerator_add_match_property(sd_device_enumerator *enumerator,
                                            const char *property,
                                            const char *value);

int sd_device_enumerator_add_match_property_required(sd_device_enumerator *enumerator,
                                                     const char *property,
                                                     const char *value);

int sd_device_enumerator_add_match_subsystem(sd_device_enumerator *enumerator,
                                             const char *subsystem,
                                             int match);

int sd_device_enumerator_add_match_sysattr(sd_device_enumerator *enumerator,
                                           const char *sysattr,
                                           const char *value,
                                           int match);

int sd_device_enumerator_add_match_sysname(sd_device_enumerator *enumerator,
                                           const char *sysname);

int sd_device_enumerator_add_nomatch_sysname(sd_device_enumerator *enumerator,
                                             const char *sysname);

int sd_device_enumerator_add_match_tag(sd_device_enumerator *enumerator,
                                       const char *tag);

int sd_device_enumerator_allow_uninitialized(sd_device_enumerator *enumerator);

int sd_device_enumerator_add_all_parents(sd_device_enumerator *enumerator);

🌸 DESCRIPTION 🌸

so here's the tea on each one, bestie, in order, no skips:

  • sd_device_enumerator_add_match_parent() β€” drops a filter in so that only devices under the tree of the parent device you specify get enumerated. call it multiple times and the previously set parent device gets cleared, so only the last call takes effect. no stacking, only the final answer. πŸ’…
  • sd_device_enumerator_add_match_property() β€” filters so only devices whose specified property equals value get enumerated. both property and value can be a glob pattern ✨. call it multiple times and you get devices that have at least one of the specified properties with matching values. that means the filters are ORed. periodt.
  • sd_device_enumerator_add_match_property_required() β€” the stricter sibling of the one above. same "only devices where property equals value" energy, but call it multiple times and only devices that have all the specified properties with matching values get enumerated. the filters are ANDed, no exceptions. πŸ‘‘
  • sd_device_enumerator_add_match_subsystem() β€” when match is true, all devices in the specified subsystem get enumerated. when match is false, every device except the ones in that subsystem gets enumerated. called multiple times? positive filters are ORed, negative ones are ANDed. iykyk. πŸ¦‹
  • sd_device_enumerator_add_match_sysattr() β€” adds a filter on the sysfs attribute sysattr matching value. value can be a glob pattern. if value is NULL, devices that either have (when match is true) or do not have (when match is false) the specified sysattr are included, regardless of its value β€” so NULL is mostly equivalent to "*". call it multiple times and only devices that match all the specified sysattr filters get enumerated. these filters are ANDed.
  • sd_device_enumerator_add_match_sysname() β€” filters so only devices whose sysname equals sysname get enumerated. sysname can be a glob pattern. called multiple times, the filters are ORed.
  • sd_device_enumerator_add_nomatch_sysname() β€” adds a filter so that devices whose sysname equals sysname are excluded from the enumeration. perfect for yeeting specific devices out of the enumeration process. called multiple times, filters are ANDed. 🚫
  • sd_device_enumerator_add_match_tag() β€” filters so only devices tagged with tag get enumerated. called multiple times, filters are ORed. 🏷️
  • sd_device_enumerator_allow_uninitialized() β€” lets devices that udev hasn't initialized yet be included in the enumeration. letting the babies in early, love that. πŸ™ˆ
  • sd_device_enumerator_add_all_parents() β€” enumerates all parent devices of the matching devices. iconic for when you want the entire device tree leading up to a specific device. 🌳

πŸ”₯ RETURN VALUE πŸ”₯

all of these functions return 0 or a positive integer on success, or a negative errno-style error code on failure. 😭

🫧 Errors 🫧

the errors that come back may mean these things:

  • -ENOMEM β€” memory allocation failed. the allocator said no. πŸ’€
  • -EINVAL β€” one of the arguments is invalid. double-check those args bestie. πŸ™ˆ

πŸ’» EXAMPLES πŸ’»

Example 1. Detect Removable USB Devices (Using Match and Exclude)

look at this little program, it's so clean:

/* SPDX-License-Identifier: MIT-0 */

#include <stdbool.h>
#include <stdio.h>
#include <systemd/sd-device.h>

int main(void) {
    __attribute__((cleanup(sd_device_enumerator_unrefp))) sd_device_enumerator *enumerator = NULL;
    sd_device *device;
    int r;

    /* Create a new device enumerator */
    r = sd_device_enumerator_new(&enumerator);
    if (r < 0) {
        fprintf(stderr, "Failed to create device enumerator: %s\n", strerror(-r));
        return 1;
    }

    /* Include only devices from the "usb" subsystem */
    r = sd_device_enumerator_add_match_subsystem(enumerator, "usb", true);
    if (r < 0) {
        fprintf(stderr, "Failed to add subsystem match: %s\n", strerror(-r));
        return 1;
    }

    /*
     * Exclude devices where the "removable" sysattr is "0"
     * These are typically non-removable devices like built-in USB interfaces
     */
    r = sd_device_enumerator_add_match_sysattr(enumerator, "removable", "0", false);
    if (r < 0) {
        fprintf(stderr, "Failed to add sysattr match: %s\n", strerror(-r));
        return 1;
    }

    /* Begin enumerating matching devices */
    for (device = sd_device_enumerator_get_device_first(enumerator);
         device;
         device = sd_device_enumerator_get_device_next(enumerator)) {
        const char *syspath;

        /* Get syspath for the device */
        if (sd_device_get_syspath(device, &syspath) >= 0)
            printf("Removable USB device found: %s\n", syspath);
    }
    return 0;
}

πŸ•°οΈ HISTORY πŸ•°οΈ

a little lore for you, because knowing when things dropped is a flex:

  • sd_device_enumerator_add_match_parent(), sd_device_enumerator_add_match_property(), sd_device_enumerator_add_match_subsystem(), sd_device_enumerator_add_match_sysattr(), sd_device_enumerator_add_match_sysname(), sd_device_enumerator_add_match_tag(), and sd_device_enumerator_allow_uninitialized() were added in version 240. πŸŽ€
  • sd_device_enumerator_add_nomatch_sysname() was added in version 251.
  • sd_device_enumerator_add_match_property_required() was added in version 255.
  • sd_device_enumerator_add_all_parents() was added in version 258. πŸŽ‰

πŸ‘€ SEE ALSO πŸ‘€

go read these next, they're the friends of this page:


bestie reminder: every filter you add is a vibe you're setting for your enumeration. add them on purpose, not by accident. πŸ’–

and that's the whole page!! mwah πŸ’‹ this one comes to you from systemd 262.1, shipped under SD_DEV..._PARENT(3), so go forth and enumerate responsibly. slay. 🌈✨

πŸ“¦ where this page comes from
  • arch rolling: systemd-libs 262.1-1 Β· LGPL-2.1-or-later AND CC0-1.0 AND GPL-2.0-or-later WITH Linux-syscall-note
  • πŸ’– girlified by deepseek-ai/DeepSeek-V4.1-Flash on : a language model's rewrite of the original, under its terms