[systemd-commits] 3 commits - Makefile.am src/libsystemd src/libudev src/shared src/systemd

Tom Gundersen tomegun at kemper.freedesktop.org
Fri Apr 17 03:23:15 PDT 2015


 Makefile.am                                          |    6 
 src/libsystemd/sd-device/device-enumerator-private.h |   34 
 src/libsystemd/sd-device/device-enumerator.c         |  972 +++++++++++++++++++
 src/libsystemd/sd-device/device-util.h               |   16 
 src/libudev/libudev-device-internal.h                |   10 
 src/libudev/libudev-enumerate.c                      |  792 ++-------------
 src/shared/macro.h                                   |    9 
 src/systemd/sd-device.h                              |   26 
 8 files changed, 1165 insertions(+), 700 deletions(-)

New commits:
commit c32eb440bab953a0169cd207dfef5cad16dfb340
Author: Tom Gundersen <teg at jklm.no>
Date:   Tue Apr 14 16:25:06 2015 +0200

    libudev: make libudev-enumerate a thin wrapper around sd-device

diff --git a/Makefile.am b/Makefile.am
index 837fd36..68d8252 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -3976,8 +3976,8 @@ test_libudev_SOURCES = \
 test_libudev_LDADD = \
 	libsystemd-label.la \
 	libudev-internal.la \
-	libsystemd-shared.la \
-	libsystemd-internal.la
+	libsystemd-internal.la \
+	libsystemd-shared.la
 
 test_udev_SOURCES = \
 	src/test/test-udev.c
diff --git a/src/libudev/libudev-device-internal.h b/src/libudev/libudev-device-internal.h
index b6ecce8..3f93fda 100644
--- a/src/libudev/libudev-device-internal.h
+++ b/src/libudev/libudev-device-internal.h
@@ -21,6 +21,7 @@
 #pragma once
 
 #include "libudev.h"
+#include "libudev-private.h"
 #include "sd-device.h"
 
 /**
diff --git a/src/libudev/libudev-enumerate.c b/src/libudev/libudev-enumerate.c
index 4e6e47c..290c3da 100644
--- a/src/libudev/libudev-enumerate.c
+++ b/src/libudev/libudev-enumerate.c
@@ -2,6 +2,7 @@
   This file is part of systemd.
 
   Copyright 2008-2012 Kay Sievers <kay at vrfy.org>
+  Copyright 2015 Tom Gundersen <teg at jklm.no>
 
   systemd is free software; you can redistribute it and/or modify it
   under the terms of the GNU Lesser General Public License as published by
@@ -28,7 +29,11 @@
 #include <sys/stat.h>
 
 #include "libudev.h"
-#include "libudev-private.h"
+#include "libudev-device-internal.h"
+#include "sd-device.h"
+#include "device-util.h"
+#include "device-enumerator-private.h"
+
 
 /**
  * SECTION:libudev-enumerate
@@ -38,11 +43,6 @@
  * and return a sorted list of devices.
  */
 
-struct syspath {
-        char *syspath;
-        size_t len;
-};
-
 /**
  * udev_enumerate:
  *
@@ -51,20 +51,10 @@ struct syspath {
 struct udev_enumerate {
         struct udev *udev;
         int refcount;
-        struct udev_list sysattr_match_list;
-        struct udev_list sysattr_nomatch_list;
-        struct udev_list subsystem_match_list;
-        struct udev_list subsystem_nomatch_list;
-        struct udev_list sysname_match_list;
-        struct udev_list properties_match_list;
-        struct udev_list tags_match_list;
-        struct udev_device *parent_match;
         struct udev_list devices_list;
-        struct syspath *devices;
-        unsigned int devices_cur;
-        unsigned int devices_max;
         bool devices_uptodate:1;
-        bool match_is_initialized;
+
+        sd_device_enumerator *enumerator;
 };
 
 /**
@@ -75,25 +65,30 @@ struct udev_enumerate {
  *
  * Returns: an enumeration context.
  **/
-_public_ struct udev_enumerate *udev_enumerate_new(struct udev *udev)
-{
+_public_ struct udev_enumerate *udev_enumerate_new(struct udev *udev) {
         struct udev_enumerate *udev_enumerate;
+        int r;
+
+        assert_return_errno(udev, NULL, EINVAL);
 
-        if (udev == NULL)
-                return NULL;
         udev_enumerate = new0(struct udev_enumerate, 1);
-        if (udev_enumerate == NULL)
+        if (!udev_enumerate) {
+                errno = ENOMEM;
+                return NULL;
+        }
+
+        r = sd_device_enumerator_new(&udev_enumerate->enumerator);
+        if (r < 0) {
+                free(udev_enumerate);
+                errno = -r;
                 return NULL;
+        }
+
         udev_enumerate->refcount = 1;
         udev_enumerate->udev = udev;
-        udev_list_init(udev, &udev_enumerate->sysattr_match_list, false);
-        udev_list_init(udev, &udev_enumerate->sysattr_nomatch_list, false);
-        udev_list_init(udev, &udev_enumerate->subsystem_match_list, true);
-        udev_list_init(udev, &udev_enumerate->subsystem_nomatch_list, true);
-        udev_list_init(udev, &udev_enumerate->sysname_match_list, true);
-        udev_list_init(udev, &udev_enumerate->properties_match_list, false);
-        udev_list_init(udev, &udev_enumerate->tags_match_list, true);
+
         udev_list_init(udev, &udev_enumerate->devices_list, false);
+
         return udev_enumerate;
 }
 
@@ -105,11 +100,10 @@ _public_ struct udev_enumerate *udev_enumerate_new(struct udev *udev)
  *
  * Returns: the passed enumeration context
  **/
-_public_ struct udev_enumerate *udev_enumerate_ref(struct udev_enumerate *udev_enumerate)
-{
-        if (udev_enumerate == NULL)
-                return NULL;
-        udev_enumerate->refcount++;
+_public_ struct udev_enumerate *udev_enumerate_ref(struct udev_enumerate *udev_enumerate) {
+        if (udev_enumerate)
+                udev_enumerate->refcount ++;
+
         return udev_enumerate;
 }
 
@@ -122,28 +116,13 @@ _public_ struct udev_enumerate *udev_enumerate_ref(struct udev_enumerate *udev_e
  *
  * Returns: #NULL
  **/
-_public_ struct udev_enumerate *udev_enumerate_unref(struct udev_enumerate *udev_enumerate)
-{
-        unsigned int i;
+_public_ struct udev_enumerate *udev_enumerate_unref(struct udev_enumerate *udev_enumerate) {
+        if (udev_enumerate && (-- udev_enumerate->refcount) == 0) {
+                udev_list_cleanup(&udev_enumerate->devices_list);
+                sd_device_enumerator_unref(udev_enumerate->enumerator);
+                free(udev_enumerate);
+        }
 
-        if (udev_enumerate == NULL)
-                return NULL;
-        udev_enumerate->refcount--;
-        if (udev_enumerate->refcount > 0)
-                return NULL;
-        udev_list_cleanup(&udev_enumerate->sysattr_match_list);
-        udev_list_cleanup(&udev_enumerate->sysattr_nomatch_list);
-        udev_list_cleanup(&udev_enumerate->subsystem_match_list);
-        udev_list_cleanup(&udev_enumerate->subsystem_nomatch_list);
-        udev_list_cleanup(&udev_enumerate->sysname_match_list);
-        udev_list_cleanup(&udev_enumerate->properties_match_list);
-        udev_list_cleanup(&udev_enumerate->tags_match_list);
-        udev_device_unref(udev_enumerate->parent_match);
-        udev_list_cleanup(&udev_enumerate->devices_list);
-        for (i = 0; i < udev_enumerate->devices_cur; i++)
-                free(udev_enumerate->devices[i].syspath);
-        free(udev_enumerate->devices);
-        free(udev_enumerate);
         return NULL;
 }
 
@@ -155,103 +134,10 @@ _public_ struct udev_enumerate *udev_enumerate_unref(struct udev_enumerate *udev
  *
  * Returns: a pointer to the context.
  */
-_public_ struct udev *udev_enumerate_get_udev(struct udev_enumerate *udev_enumerate)
-{
-        if (udev_enumerate == NULL)
-                return NULL;
-        return udev_enumerate->udev;
-}
-
-static int syspath_add(struct udev_enumerate *udev_enumerate, const char *syspath)
-{
-        char *path;
-        struct syspath *entry;
-
-        /* double array size if needed */
-        if (udev_enumerate->devices_cur >= udev_enumerate->devices_max) {
-                struct syspath *buf;
-                unsigned int add;
-
-                add = udev_enumerate->devices_max;
-                if (add < 1024)
-                        add = 1024;
-                buf = realloc(udev_enumerate->devices, (udev_enumerate->devices_max + add) * sizeof(struct syspath));
-                if (buf == NULL)
-                        return -ENOMEM;
-                udev_enumerate->devices = buf;
-                udev_enumerate->devices_max += add;
-        }
-
-        path = strdup(syspath);
-        if (path == NULL)
-                return -ENOMEM;
-        entry = &udev_enumerate->devices[udev_enumerate->devices_cur];
-        entry->syspath = path;
-        entry->len = strlen(path);
-        udev_enumerate->devices_cur++;
-        udev_enumerate->devices_uptodate = false;
-        return 0;
-}
-
-static int syspath_cmp(const void *p1, const void *p2)
-{
-        const struct syspath *path1 = p1;
-        const struct syspath *path2 = p2;
-        size_t len;
-        int ret;
-
-        len = MIN(path1->len, path2->len);
-        ret = memcmp(path1->syspath, path2->syspath, len);
-        if (ret == 0) {
-                if (path1->len < path2->len)
-                        ret = -1;
-                else if (path1->len > path2->len)
-                        ret = 1;
-        }
-        return ret;
-}
-
-/* For devices that should be moved to the absolute end of the list */
-static bool devices_delay_end(struct udev *udev, const char *syspath)
-{
-        static const char *delay_device_list[] = {
-                "/block/md",
-                "/block/dm-",
-                NULL
-        };
-        int i;
-
-        for (i = 0; delay_device_list[i] != NULL; i++) {
-                if (strstr(syspath + strlen("/sys"), delay_device_list[i]) != NULL)
-                        return true;
-        }
-        return false;
-}
-
-/* For devices that should just be moved a little bit later, just
- * before the point where some common path prefix changes. Returns the
- * number of characters that make up that common prefix */
-static size_t devices_delay_later(struct udev *udev, const char *syspath)
-{
-        const char *c;
-
-        /* For sound cards the control device must be enumerated last
-         * to make sure it's the final device node that gets ACLs
-         * applied. Applications rely on this fact and use ACL changes
-         * on the control node as an indicator that the ACL change of
-         * the entire sound card completed. The kernel makes this
-         * guarantee when creating those devices, and hence we should
-         * too when enumerating them. */
-
-        if ((c = strstr(syspath, "/sound/card"))) {
-                c += 11;
-                c += strcspn(c, "/");
-
-                if (startswith(c, "/controlC"))
-                        return c - syspath + 1;
-        }
+_public_ struct udev *udev_enumerate_get_udev(struct udev_enumerate *udev_enumerate) {
+        assert_return_errno(udev_enumerate, NULL, EINVAL);
 
-        return 0;
+        return udev_enumerate->udev;
 }
 
 /**
@@ -262,77 +148,30 @@ static size_t devices_delay_later(struct udev *udev, const char *syspath)
  *
  * Returns: a udev_list_entry.
  */
-_public_ struct udev_list_entry *udev_enumerate_get_list_entry(struct udev_enumerate *udev_enumerate)
-{
-        if (udev_enumerate == NULL)
-                return NULL;
+_public_ struct udev_list_entry *udev_enumerate_get_list_entry(struct udev_enumerate *udev_enumerate) {
+        assert_return_errno(udev_enumerate, NULL, EINVAL);
+
         if (!udev_enumerate->devices_uptodate) {
-                unsigned int i;
-                int move_later = -1;
-                unsigned int max;
-                struct syspath *prev = NULL;
-                size_t move_later_prefix = 0;
+                sd_device *device;
 
                 udev_list_cleanup(&udev_enumerate->devices_list);
-                qsort_safe(udev_enumerate->devices, udev_enumerate->devices_cur, sizeof(struct syspath), syspath_cmp);
-
-                max = udev_enumerate->devices_cur;
-                for (i = 0; i < max; i++) {
-                        struct syspath *entry = &udev_enumerate->devices[i];
-
-                        /* skip duplicated entries */
-                        if (prev != NULL &&
-                            entry->len == prev->len &&
-                            memcmp(entry->syspath, prev->syspath, entry->len) == 0)
-                                continue;
-                        prev = entry;
-
-                        /* skip to be delayed devices, and add them to the end of the list */
-                        if (devices_delay_end(udev_enumerate->udev, entry->syspath)) {
-                                syspath_add(udev_enumerate, entry->syspath);
-                                /* need to update prev here for the case realloc() gives a different address */
-                                prev = &udev_enumerate->devices[i];
-                                continue;
-                        }
 
-                        /* skip to be delayed devices, and move the to
-                         * the point where the prefix changes. We can
-                         * only move one item at a time. */
-                        if (move_later == -1) {
-                                move_later_prefix = devices_delay_later(udev_enumerate->udev, entry->syspath);
+                FOREACH_DEVICE_AND_SUBSYSTEM(udev_enumerate->enumerator, device) {
+                        const char *syspath;
+                        int r;
 
-                                if (move_later_prefix > 0) {
-                                        move_later = i;
-                                        continue;
-                                }
+                        r = sd_device_get_syspath(device, &syspath);
+                        if (r < 0) {
+                                errno = -r;
+                                return NULL;
                         }
 
-                        if ((move_later >= 0) &&
-                             !strneq(entry->syspath, udev_enumerate->devices[move_later].syspath, move_later_prefix)) {
-
-                                udev_list_entry_add(&udev_enumerate->devices_list,
-                                                    udev_enumerate->devices[move_later].syspath, NULL);
-                                move_later = -1;
-                        }
-
-                        udev_list_entry_add(&udev_enumerate->devices_list, entry->syspath, NULL);
-                }
-
-                if (move_later >= 0)
-                        udev_list_entry_add(&udev_enumerate->devices_list,
-                                            udev_enumerate->devices[move_later].syspath, NULL);
-
-                /* add and cleanup delayed devices from end of list */
-                for (i = max; i < udev_enumerate->devices_cur; i++) {
-                        struct syspath *entry = &udev_enumerate->devices[i];
-
-                        udev_list_entry_add(&udev_enumerate->devices_list, entry->syspath, NULL);
-                        free(entry->syspath);
+                        udev_list_entry_add(&udev_enumerate->devices_list, syspath, NULL);
                 }
-                udev_enumerate->devices_cur = max;
 
                 udev_enumerate->devices_uptodate = true;
         }
+
         return udev_list_get_entry(&udev_enumerate->devices_list);
 }
 
@@ -345,15 +184,10 @@ _public_ struct udev_list_entry *udev_enumerate_get_list_entry(struct udev_enume
  *
  * Returns: 0 on success, otherwise a negative error value.
  */
-_public_ int udev_enumerate_add_match_subsystem(struct udev_enumerate *udev_enumerate, const char *subsystem)
-{
-        if (udev_enumerate == NULL)
-                return -EINVAL;
-        if (subsystem == NULL)
-                return 0;
-        if (udev_list_entry_add(&udev_enumerate->subsystem_match_list, subsystem, NULL) == NULL)
-                return -ENOMEM;
-        return 0;
+_public_ int udev_enumerate_add_match_subsystem(struct udev_enumerate *udev_enumerate, const char *subsystem) {
+        assert_return(udev_enumerate, -EINVAL);
+
+        return sd_device_enumerator_add_match_subsystem(udev_enumerate->enumerator, subsystem, true);
 }
 
 /**
@@ -365,15 +199,10 @@ _public_ int udev_enumerate_add_match_subsystem(struct udev_enumerate *udev_enum
  *
  * Returns: 0 on success, otherwise a negative error value.
  */
-_public_ int udev_enumerate_add_nomatch_subsystem(struct udev_enumerate *udev_enumerate, const char *subsystem)
-{
-        if (udev_enumerate == NULL)
-                return -EINVAL;
-        if (subsystem == NULL)
-                return 0;
-        if (udev_list_entry_add(&udev_enumerate->subsystem_nomatch_list, subsystem, NULL) == NULL)
-                return -ENOMEM;
-        return 0;
+_public_ int udev_enumerate_add_nomatch_subsystem(struct udev_enumerate *udev_enumerate, const char *subsystem) {
+        assert_return(udev_enumerate, -EINVAL);
+
+        return sd_device_enumerator_add_match_subsystem(udev_enumerate->enumerator, subsystem, false);
 }
 
 /**
@@ -386,15 +215,10 @@ _public_ int udev_enumerate_add_nomatch_subsystem(struct udev_enumerate *udev_en
  *
  * Returns: 0 on success, otherwise a negative error value.
  */
-_public_ int udev_enumerate_add_match_sysattr(struct udev_enumerate *udev_enumerate, const char *sysattr, const char *value)
-{
-        if (udev_enumerate == NULL)
-                return -EINVAL;
-        if (sysattr == NULL)
-                return 0;
-        if (udev_list_entry_add(&udev_enumerate->sysattr_match_list, sysattr, value) == NULL)
-                return -ENOMEM;
-        return 0;
+_public_ int udev_enumerate_add_match_sysattr(struct udev_enumerate *udev_enumerate, const char *sysattr, const char *value) {
+        assert_return(udev_enumerate, -EINVAL);
+
+        return sd_device_enumerator_add_match_sysattr(udev_enumerate->enumerator, sysattr, value, true);
 }
 
 /**
@@ -407,35 +231,10 @@ _public_ int udev_enumerate_add_match_sysattr(struct udev_enumerate *udev_enumer
  *
  * Returns: 0 on success, otherwise a negative error value.
  */
-_public_ int udev_enumerate_add_nomatch_sysattr(struct udev_enumerate *udev_enumerate, const char *sysattr, const char *value)
-{
-        if (udev_enumerate == NULL)
-                return -EINVAL;
-        if (sysattr == NULL)
-                return 0;
-        if (udev_list_entry_add(&udev_enumerate->sysattr_nomatch_list, sysattr, value) == NULL)
-                return -ENOMEM;
-        return 0;
-}
+_public_ int udev_enumerate_add_nomatch_sysattr(struct udev_enumerate *udev_enumerate, const char *sysattr, const char *value) {
+        assert_return(udev_enumerate, -EINVAL);
 
-static int match_sysattr_value(struct udev_device *dev, const char *sysattr, const char *match_val)
-{
-        const char *val = NULL;
-        bool match = false;
-
-        val = udev_device_get_sysattr_value(dev, sysattr);
-        if (val == NULL)
-                goto exit;
-        if (match_val == NULL) {
-                match = true;
-                goto exit;
-        }
-        if (fnmatch(match_val, val, 0) == 0) {
-                match = true;
-                goto exit;
-        }
-exit:
-        return match;
+        return sd_device_enumerator_add_match_sysattr(udev_enumerate->enumerator, sysattr, value, false);
 }
 
 /**
@@ -448,15 +247,10 @@ exit:
  *
  * Returns: 0 on success, otherwise a negative error value.
  */
-_public_ int udev_enumerate_add_match_property(struct udev_enumerate *udev_enumerate, const char *property, const char *value)
-{
-        if (udev_enumerate == NULL)
-                return -EINVAL;
-        if (property == NULL)
-                return 0;
-        if (udev_list_entry_add(&udev_enumerate->properties_match_list, property, value) == NULL)
-                return -ENOMEM;
-        return 0;
+_public_ int udev_enumerate_add_match_property(struct udev_enumerate *udev_enumerate, const char *property, const char *value) {
+        assert_return(udev_enumerate, -EINVAL);
+
+        return sd_device_enumerator_add_match_property(udev_enumerate->enumerator, property, value);
 }
 
 /**
@@ -468,15 +262,10 @@ _public_ int udev_enumerate_add_match_property(struct udev_enumerate *udev_enume
  *
  * Returns: 0 on success, otherwise a negative error value.
  */
-_public_ int udev_enumerate_add_match_tag(struct udev_enumerate *udev_enumerate, const char *tag)
-{
-        if (udev_enumerate == NULL)
-                return -EINVAL;
-        if (tag == NULL)
-                return 0;
-        if (udev_list_entry_add(&udev_enumerate->tags_match_list, tag, NULL) == NULL)
-                return -ENOMEM;
-        return 0;
+_public_ int udev_enumerate_add_match_tag(struct udev_enumerate *udev_enumerate, const char *tag) {
+        assert_return(udev_enumerate, -EINVAL);
+
+        return sd_device_enumerator_add_match_tag(udev_enumerate->enumerator, tag);
 }
 
 /**
@@ -492,16 +281,13 @@ _public_ int udev_enumerate_add_match_tag(struct udev_enumerate *udev_enumerate,
  *
  * Returns: 0 on success, otherwise a negative error value.
  */
-_public_ int udev_enumerate_add_match_parent(struct udev_enumerate *udev_enumerate, struct udev_device *parent)
-{
-        if (udev_enumerate == NULL)
-                return -EINVAL;
-        if (parent == NULL)
+_public_ int udev_enumerate_add_match_parent(struct udev_enumerate *udev_enumerate, struct udev_device *parent) {
+        assert_return(udev_enumerate, -EINVAL);
+
+        if (!parent)
                 return 0;
-        if (udev_enumerate->parent_match != NULL)
-                udev_device_unref(udev_enumerate->parent_match);
-        udev_enumerate->parent_match = udev_device_ref(parent);
-        return 0;
+
+        return sd_device_enumerator_add_match_parent(udev_enumerate->enumerator, parent->device);
 }
 
 /**
@@ -522,12 +308,10 @@ _public_ int udev_enumerate_add_match_parent(struct udev_enumerate *udev_enumera
  *
  * Returns: 0 on success, otherwise a negative error value.
  */
-_public_ int udev_enumerate_add_match_is_initialized(struct udev_enumerate *udev_enumerate)
-{
-        if (udev_enumerate == NULL)
-                return -EINVAL;
-        udev_enumerate->match_is_initialized = true;
-        return 0;
+_public_ int udev_enumerate_add_match_is_initialized(struct udev_enumerate *udev_enumerate) {
+        assert_return(udev_enumerate, -EINVAL);
+
+        return sd_device_enumerator_add_match_is_initialized(udev_enumerate->enumerator);
 }
 
 /**
@@ -539,224 +323,10 @@ _public_ int udev_enumerate_add_match_is_initialized(struct udev_enumerate *udev
  *
  * Returns: 0 on success, otherwise a negative error value.
  */
-_public_ int udev_enumerate_add_match_sysname(struct udev_enumerate *udev_enumerate, const char *sysname)
-{
-        if (udev_enumerate == NULL)
-                return -EINVAL;
-        if (sysname == NULL)
-                return 0;
-        if (udev_list_entry_add(&udev_enumerate->sysname_match_list, sysname, NULL) == NULL)
-                return -ENOMEM;
-        return 0;
-}
-
-static bool match_sysattr(struct udev_enumerate *udev_enumerate, struct udev_device *dev)
-{
-        struct udev_list_entry *list_entry;
-
-        /* skip list */
-        udev_list_entry_foreach(list_entry, udev_list_get_entry(&udev_enumerate->sysattr_nomatch_list)) {
-                if (match_sysattr_value(dev, udev_list_entry_get_name(list_entry),
-                                        udev_list_entry_get_value(list_entry)))
-                        return false;
-        }
-        /* include list */
-        if (udev_list_get_entry(&udev_enumerate->sysattr_match_list) != NULL) {
-                udev_list_entry_foreach(list_entry, udev_list_get_entry(&udev_enumerate->sysattr_match_list)) {
-                        /* anything that does not match, will make it FALSE */
-                        if (!match_sysattr_value(dev, udev_list_entry_get_name(list_entry),
-                                                 udev_list_entry_get_value(list_entry)))
-                                return false;
-                }
-                return true;
-        }
-        return true;
-}
+_public_ int udev_enumerate_add_match_sysname(struct udev_enumerate *udev_enumerate, const char *sysname) {
+        assert_return(udev_enumerate, -EINVAL);
 
-static bool match_property(struct udev_enumerate *udev_enumerate, struct udev_device *dev)
-{
-        struct udev_list_entry *list_entry;
-        bool match = false;
-
-        /* no match always matches */
-        if (udev_list_get_entry(&udev_enumerate->properties_match_list) == NULL)
-                return true;
-
-        /* loop over matches */
-        udev_list_entry_foreach(list_entry, udev_list_get_entry(&udev_enumerate->properties_match_list)) {
-                const char *match_key = udev_list_entry_get_name(list_entry);
-                const char *match_value = udev_list_entry_get_value(list_entry);
-                struct udev_list_entry *property_entry;
-
-                /* loop over device properties */
-                udev_list_entry_foreach(property_entry, udev_device_get_properties_list_entry(dev)) {
-                        const char *dev_key = udev_list_entry_get_name(property_entry);
-                        const char *dev_value = udev_list_entry_get_value(property_entry);
-
-                        if (fnmatch(match_key, dev_key, 0) != 0)
-                                continue;
-                        if (match_value == NULL && dev_value == NULL) {
-                                match = true;
-                                goto out;
-                        }
-                        if (match_value == NULL || dev_value == NULL)
-                                continue;
-                        if (fnmatch(match_value, dev_value, 0) == 0) {
-                                match = true;
-                                goto out;
-                        }
-                }
-        }
-out:
-        return match;
-}
-
-static bool match_tag(struct udev_enumerate *udev_enumerate, struct udev_device *dev)
-{
-        struct udev_list_entry *list_entry;
-
-        /* no match always matches */
-        if (udev_list_get_entry(&udev_enumerate->tags_match_list) == NULL)
-                return true;
-
-        /* loop over matches */
-        udev_list_entry_foreach(list_entry, udev_list_get_entry(&udev_enumerate->tags_match_list))
-                if (!udev_device_has_tag(dev, udev_list_entry_get_name(list_entry)))
-                        return false;
-
-        return true;
-}
-
-static bool match_parent(struct udev_enumerate *udev_enumerate, struct udev_device *dev)
-{
-        if (udev_enumerate->parent_match == NULL)
-                return true;
-
-        return startswith(udev_device_get_devpath(dev), udev_device_get_devpath(udev_enumerate->parent_match));
-}
-
-static bool match_sysname(struct udev_enumerate *udev_enumerate, const char *sysname)
-{
-        struct udev_list_entry *list_entry;
-
-        if (udev_list_get_entry(&udev_enumerate->sysname_match_list) == NULL)
-                return true;
-
-        udev_list_entry_foreach(list_entry, udev_list_get_entry(&udev_enumerate->sysname_match_list)) {
-                if (fnmatch(udev_list_entry_get_name(list_entry), sysname, 0) != 0)
-                        continue;
-                return true;
-        }
-        return false;
-}
-
-static int scan_dir_and_add_devices(struct udev_enumerate *udev_enumerate,
-                                    const char *basedir, const char *subdir1, const char *subdir2)
-{
-        char path[UTIL_PATH_SIZE];
-        size_t l;
-        char *s;
-        DIR *dir;
-        struct dirent *dent;
-
-        s = path;
-        l = strpcpyl(&s, sizeof(path), "/sys/", basedir, NULL);
-        if (subdir1 != NULL)
-                l = strpcpyl(&s, l, "/", subdir1, NULL);
-        if (subdir2 != NULL)
-                strpcpyl(&s, l, "/", subdir2, NULL);
-        dir = opendir(path);
-        if (dir == NULL)
-                return -ENOENT;
-        for (dent = readdir(dir); dent != NULL; dent = readdir(dir)) {
-                char syspath[UTIL_PATH_SIZE];
-                struct udev_device *dev;
-
-                if (dent->d_name[0] == '.')
-                        continue;
-
-                if (!match_sysname(udev_enumerate, dent->d_name))
-                        continue;
-
-                strscpyl(syspath, sizeof(syspath), path, "/", dent->d_name, NULL);
-                dev = udev_device_new_from_syspath(udev_enumerate->udev, syspath);
-                if (dev == NULL)
-                        continue;
-
-                if (udev_enumerate->match_is_initialized) {
-                        /*
-                         * All devices with a device node or network interfaces
-                         * possibly need udev to adjust the device node permission
-                         * or context, or rename the interface before it can be
-                         * reliably used from other processes.
-                         *
-                         * For now, we can only check these types of devices, we
-                         * might not store a database, and have no way to find out
-                         * for all other types of devices.
-                         */
-                        if (!udev_device_get_is_initialized(dev) &&
-                            (major(udev_device_get_devnum(dev)) > 0 || udev_device_get_ifindex(dev) > 0))
-                                goto nomatch;
-                }
-                if (!match_parent(udev_enumerate, dev))
-                        goto nomatch;
-                if (!match_tag(udev_enumerate, dev))
-                        goto nomatch;
-                if (!match_property(udev_enumerate, dev))
-                        goto nomatch;
-                if (!match_sysattr(udev_enumerate, dev))
-                        goto nomatch;
-
-                syspath_add(udev_enumerate, udev_device_get_syspath(dev));
-nomatch:
-                udev_device_unref(dev);
-        }
-        closedir(dir);
-        return 0;
-}
-
-static bool match_subsystem(struct udev_enumerate *udev_enumerate, const char *subsystem)
-{
-        struct udev_list_entry *list_entry;
-
-        if (!subsystem)
-                return false;
-
-        udev_list_entry_foreach(list_entry, udev_list_get_entry(&udev_enumerate->subsystem_nomatch_list)) {
-                if (fnmatch(udev_list_entry_get_name(list_entry), subsystem, 0) == 0)
-                        return false;
-        }
-
-        if (udev_list_get_entry(&udev_enumerate->subsystem_match_list) != NULL) {
-                udev_list_entry_foreach(list_entry, udev_list_get_entry(&udev_enumerate->subsystem_match_list)) {
-                        if (fnmatch(udev_list_entry_get_name(list_entry), subsystem, 0) == 0)
-                                return true;
-                }
-                return false;
-        }
-
-        return true;
-}
-
-static int scan_dir(struct udev_enumerate *udev_enumerate, const char *basedir, const char *subdir, const char *subsystem)
-{
-        char path[UTIL_PATH_SIZE];
-        DIR *dir;
-        struct dirent *dent;
-
-        strscpyl(path, sizeof(path), "/sys/", basedir, NULL);
-        dir = opendir(path);
-        if (dir == NULL)
-                return -1;
-        for (dent = readdir(dir); dent != NULL; dent = readdir(dir)) {
-                if (dent->d_name[0] == '.')
-                        continue;
-                if (!match_subsystem(udev_enumerate, subsystem != NULL ? subsystem : dent->d_name))
-                        continue;
-                scan_dir_and_add_devices(udev_enumerate, basedir, dent->d_name, subdir);
-        }
-        closedir(dir);
-        return 0;
+        return sd_device_enumerator_add_match_sysname(udev_enumerate->enumerator, sysname);
 }
 
 /**
@@ -768,141 +338,23 @@ static int scan_dir(struct udev_enumerate *udev_enumerate, const char *basedir,
  *
  * Returns: 0 on success, otherwise a negative error value.
  */
-_public_ int udev_enumerate_add_syspath(struct udev_enumerate *udev_enumerate, const char *syspath)
-{
-        struct udev_device *udev_device;
-
-        if (udev_enumerate == NULL)
-                return -EINVAL;
-        if (syspath == NULL)
-                return 0;
-        /* resolve to real syspath */
-        udev_device = udev_device_new_from_syspath(udev_enumerate->udev, syspath);
-        if (udev_device == NULL)
-                return -EINVAL;
-        syspath_add(udev_enumerate, udev_device_get_syspath(udev_device));
-        udev_device_unref(udev_device);
-        return 0;
-}
-
-static int scan_devices_tags(struct udev_enumerate *udev_enumerate)
-{
-        struct udev_list_entry *list_entry;
-
-        /* scan only tagged devices, use tags reverse-index, instead of searching all devices in /sys */
-        udev_list_entry_foreach(list_entry, udev_list_get_entry(&udev_enumerate->tags_match_list)) {
-                DIR *dir;
-                struct dirent *dent;
-                char path[UTIL_PATH_SIZE];
-
-                strscpyl(path, sizeof(path), "/run/udev/tags/", udev_list_entry_get_name(list_entry), NULL);
-                dir = opendir(path);
-                if (dir == NULL)
-                        continue;
-                for (dent = readdir(dir); dent != NULL; dent = readdir(dir)) {
-                        struct udev_device *dev;
-
-                        if (dent->d_name[0] == '.')
-                                continue;
-
-                        dev = udev_device_new_from_device_id(udev_enumerate->udev, dent->d_name);
-                        if (dev == NULL)
-                                continue;
-
-                        if (!match_subsystem(udev_enumerate, udev_device_get_subsystem(dev)))
-                                goto nomatch;
-                        if (!match_sysname(udev_enumerate, udev_device_get_sysname(dev)))
-                                goto nomatch;
-                        if (!match_parent(udev_enumerate, dev))
-                                goto nomatch;
-                        if (!match_property(udev_enumerate, dev))
-                                goto nomatch;
-                        if (!match_sysattr(udev_enumerate, dev))
-                                goto nomatch;
-
-                        syspath_add(udev_enumerate, udev_device_get_syspath(dev));
-nomatch:
-                        udev_device_unref(dev);
-                }
-                closedir(dir);
-        }
-        return 0;
-}
+_public_ int udev_enumerate_add_syspath(struct udev_enumerate *udev_enumerate, const char *syspath) {
+        _cleanup_device_unref_ sd_device *device = NULL;
+        int r;
 
-static int parent_add_child(struct udev_enumerate *enumerate, const char *path)
-{
-        struct udev_device *dev;
-        int r = 0;
-
-        dev = udev_device_new_from_syspath(enumerate->udev, path);
-        if (dev == NULL)
-                return -ENODEV;
-
-        if (!match_subsystem(enumerate, udev_device_get_subsystem(dev)))
-                goto nomatch;
-        if (!match_sysname(enumerate, udev_device_get_sysname(dev)))
-                goto nomatch;
-        if (!match_property(enumerate, dev))
-                goto nomatch;
-        if (!match_sysattr(enumerate, dev))
-                goto nomatch;
-
-        syspath_add(enumerate, udev_device_get_syspath(dev));
-        r = 1;
-
-nomatch:
-        udev_device_unref(dev);
-        return r;
-}
+        assert_return(udev_enumerate, -EINVAL);
 
-static int parent_crawl_children(struct udev_enumerate *enumerate, const char *path, int maxdepth)
-{
-        DIR *d;
-        struct dirent *dent;
-
-        d = opendir(path);
-        if (d == NULL)
-                return -errno;
-
-        for (dent = readdir(d); dent != NULL; dent = readdir(d)) {
-                char *child;
-
-                if (dent->d_name[0] == '.')
-                        continue;
-                if (dent->d_type != DT_DIR)
-                        continue;
-                if (asprintf(&child, "%s/%s", path, dent->d_name) < 0)
-                        continue;
-                parent_add_child(enumerate, child);
-                if (maxdepth > 0)
-                        parent_crawl_children(enumerate, child, maxdepth-1);
-                free(child);
-        }
-
-        closedir(d);
-        return 0;
-}
-
-static int scan_devices_children(struct udev_enumerate *enumerate)
-{
-        const char *path;
+        if (!syspath)
+                return 0;
 
-        path = udev_device_get_syspath(enumerate->parent_match);
-        parent_add_child(enumerate, path);
-        return parent_crawl_children(enumerate, path, 256);
-}
+        r = sd_device_new_from_syspath(&device, syspath);
+        if (r < 0)
+                return r;
 
-static int scan_devices_all(struct udev_enumerate *udev_enumerate)
-{
-        struct stat statbuf;
+        r = sd_device_enumerator_add_device(udev_enumerate->enumerator, device);
+        if (r < 0)
+                return r;
 
-        if (stat("/sys/subsystem", &statbuf) == 0) {
-                /* we have /subsystem/, forget all the old stuff */
-                scan_dir(udev_enumerate, "subsystem", "devices", NULL);
-        } else {
-                scan_dir(udev_enumerate, "bus", "devices", NULL);
-                scan_dir(udev_enumerate, "class", NULL, NULL);
-        }
         return 0;
 }
 
@@ -915,21 +367,10 @@ static int scan_devices_all(struct udev_enumerate *udev_enumerate)
  *
  * Returns: 0 on success, otherwise a negative error value.
  **/
-_public_ int udev_enumerate_scan_devices(struct udev_enumerate *udev_enumerate)
-{
-        if (udev_enumerate == NULL)
-                return -EINVAL;
+_public_ int udev_enumerate_scan_devices(struct udev_enumerate *udev_enumerate) {
+        assert_return(udev_enumerate, -EINVAL);
 
-        /* efficiently lookup tags only, we maintain a reverse-index */
-        if (udev_list_get_entry(&udev_enumerate->tags_match_list) != NULL)
-                return scan_devices_tags(udev_enumerate);
-
-        /* walk the subtree of one parent device only */
-        if (udev_enumerate->parent_match != NULL)
-                return scan_devices_children(udev_enumerate);
-
-        /* scan devices of all subsystems */
-        return scan_devices_all(udev_enumerate);
+        return device_enumerator_scan_devices(udev_enumerate->enumerator);
 }
 
 /**
@@ -940,29 +381,8 @@ _public_ int udev_enumerate_scan_devices(struct udev_enumerate *udev_enumerate)
  *
  * Returns: 0 on success, otherwise a negative error value.
  **/
-_public_ int udev_enumerate_scan_subsystems(struct udev_enumerate *udev_enumerate)
-{
-        struct stat statbuf;
-        const char *subsysdir;
-
-        if (udev_enumerate == NULL)
-                return -EINVAL;
-
-        /* all kernel modules */
-        if (match_subsystem(udev_enumerate, "module"))
-                scan_dir_and_add_devices(udev_enumerate, "module", NULL, NULL);
-
-        if (stat("/sys/subsystem", &statbuf) == 0)
-                subsysdir = "subsystem";
-        else
-                subsysdir = "bus";
-
-        /* all subsystems (only buses support coldplug) */
-        if (match_subsystem(udev_enumerate, "subsystem"))
-                scan_dir_and_add_devices(udev_enumerate, subsysdir, NULL, NULL);
-
-        /* all subsystem drivers */
-        if (match_subsystem(udev_enumerate, "drivers"))
-                scan_dir(udev_enumerate, subsysdir, "drivers", "drivers");
-        return 0;
+_public_ int udev_enumerate_scan_subsystems(struct udev_enumerate *udev_enumerate) {
+        assert_return(udev_enumerate, -EINVAL);
+
+        return device_enumerator_scan_subsystems(udev_enumerate->enumerator);
 }

commit 96df036fe3d25525a44f5efdb2fc8560e82e6cfd
Author: Tom Gundersen <teg at jklm.no>
Date:   Tue Apr 14 16:22:39 2015 +0200

    sd-device: add device-enumerator library

diff --git a/Makefile.am b/Makefile.am
index 72a2c3c..837fd36 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -3030,6 +3030,8 @@ libsystemd_internal_la_SOURCES = \
 	src/libsystemd/sd-hwdb/hwdb-internal.h \
 	src/libsystemd/sd-device/device-internal.h \
 	src/libsystemd/sd-device/device-util.h \
+	src/libsystemd/sd-device/device-enumerator.c \
+	src/libsystemd/sd-device/device-enumerator-private.h \
 	src/libsystemd/sd-device/sd-device.c \
 	src/libsystemd/sd-device/device-private.c \
 	src/libsystemd/sd-device/device-private.h
diff --git a/src/libsystemd/sd-device/device-enumerator-private.h b/src/libsystemd/sd-device/device-enumerator-private.h
new file mode 100644
index 0000000..515a60d
--- /dev/null
+++ b/src/libsystemd/sd-device/device-enumerator-private.h
@@ -0,0 +1,34 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+#pragma once
+
+/***
+  This file is part of systemd.
+
+  Copyright 2015 Tom Gundersen <teg at jklm.no>
+
+  systemd is free software; you can redistribute it and/or modify it
+  under the terms of the GNU Lesser General Public License as published by
+  the Free Software Foundation; either version 2.1 of the License, or
+  (at your option) any later version.
+
+  systemd is distributed in the hope that it will be useful, but
+  WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+  Lesser General Public License for more details.
+
+  You should have received a copy of the GNU Lesser General Public License
+  along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include "sd-device.h"
+
+int device_enumerator_scan_devices(sd_device_enumerator *enumeartor);
+int device_enumerator_scan_subsystems(sd_device_enumerator *enumeartor);
+sd_device *device_enumerator_get_first(sd_device_enumerator *enumerator);
+sd_device *device_enumerator_get_next(sd_device_enumerator *enumerator);
+
+#define FOREACH_DEVICE_AND_SUBSYSTEM(enumerator, device)       \
+        for (device = device_enumerator_get_first(enumerator); \
+             device;                                           \
+             device = device_enumerator_get_next(enumerator))
diff --git a/src/libsystemd/sd-device/device-enumerator.c b/src/libsystemd/sd-device/device-enumerator.c
new file mode 100644
index 0000000..37d46e5
--- /dev/null
+++ b/src/libsystemd/sd-device/device-enumerator.c
@@ -0,0 +1,972 @@
+/***
+  This file is part of systemd.
+
+  Copyright 2008-2012 Kay Sievers <kay at vrfy.org>
+  Copyright 2014-2015 Tom Gundersen <teg at jklm.no>
+
+  systemd is free software; you can redistribute it and/or modify it
+  under the terms of the GNU Lesser General Public License as published by
+  the Free Software Foundation; either version 2.1 of the License, or
+  (at your option) any later version.
+
+  systemd is distributed in the hope that it will be useful, but
+  WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+  Lesser General Public License for more details.
+
+  You should have received a copy of the GNU Lesser General Public License
+  along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include "util.h"
+#include "prioq.h"
+#include "strv.h"
+#include "set.h"
+
+#include "sd-device.h"
+
+#include "device-util.h"
+#include "device-enumerator-private.h"
+
+#define DEVICE_ENUMERATE_MAX_DEPTH 256
+
+typedef enum DeviceEnumerationType {
+        DEVICE_ENUMERATION_TYPE_DEVICES,
+        DEVICE_ENUMERATION_TYPE_SUBSYSTEMS,
+        _DEVICE_ENUMERATION_TYPE_MAX,
+        _DEVICE_ENUMERATION_TYPE_INVALID = -1,
+} DeviceEnumerationType;
+
+struct sd_device_enumerator {
+        unsigned n_ref;
+
+        DeviceEnumerationType type;
+        Prioq *devices;
+        bool scan_uptodate;
+
+        Set *match_subsystem;
+        Set *nomatch_subsystem;
+        Hashmap *match_sysattr;
+        Hashmap *nomatch_sysattr;
+        Hashmap *match_property;
+        Set *match_sysname;
+        Set *match_tag;
+        sd_device *match_parent;
+        bool match_is_initialized;
+};
+
+_public_ int sd_device_enumerator_new(sd_device_enumerator **ret) {
+        _cleanup_device_enumerator_unref_ sd_device_enumerator *enumerator = NULL;
+
+        assert(ret);
+
+        enumerator = new0(sd_device_enumerator, 1);
+        if (!enumerator)
+                return -ENOMEM;
+
+        enumerator->n_ref = 1;
+        enumerator->type = _DEVICE_ENUMERATION_TYPE_INVALID;
+
+        *ret = enumerator;
+        enumerator = NULL;
+
+        return 0;
+}
+
+_public_ sd_device_enumerator *sd_device_enumerator_ref(sd_device_enumerator *enumerator) {
+        assert_return(enumerator, NULL);
+
+        assert_se((++ enumerator->n_ref) >= 2);
+
+        return enumerator;
+}
+
+_public_ sd_device_enumerator *sd_device_enumerator_unref(sd_device_enumerator *enumerator) {
+        if (enumerator && (-- enumerator->n_ref) == 0) {
+                sd_device *device;
+
+                while ((device = prioq_pop(enumerator->devices)))
+                        sd_device_unref(device);
+
+                prioq_free(enumerator->devices);
+
+                set_free_free(enumerator->match_subsystem);
+                set_free_free(enumerator->nomatch_subsystem);
+                hashmap_free_free_free(enumerator->match_sysattr);
+                hashmap_free_free_free(enumerator->nomatch_sysattr);
+                hashmap_free_free_free(enumerator->match_property);
+                set_free_free(enumerator->match_sysname);
+                set_free_free(enumerator->match_tag);
+                sd_device_unref(enumerator->match_parent);
+
+                free(enumerator);
+        }
+
+        return NULL;
+}
+
+_public_ int sd_device_enumerator_add_match_subsystem(sd_device_enumerator *enumerator, const char *subsystem, int match) {
+        Set **set;
+        int r;
+
+        assert_return(enumerator, -EINVAL);
+        assert_return(subsystem, -EINVAL);
+
+        if (match)
+                set = &enumerator->match_subsystem;
+        else
+                set = &enumerator->nomatch_subsystem;
+
+        r = set_ensure_allocated(set, NULL);
+        if (r < 0)
+                return r;
+
+        r = set_put_strdup(*set, subsystem);
+        if (r < 0)
+                return r;
+
+        enumerator->scan_uptodate = false;
+
+        return 0;
+}
+
+_public_ int sd_device_enumerator_add_match_sysattr(sd_device_enumerator *enumerator, const char *_sysattr, const char *_value, int match) {
+        _cleanup_free_ char *sysattr = NULL, *value = NULL;
+        Hashmap **hashmap;
+        int r;
+
+        assert_return(enumerator, -EINVAL);
+        assert_return(_sysattr, -EINVAL);
+        assert_return(_value, -EINVAL);
+
+        if (match)
+                hashmap = &enumerator->match_sysattr;
+        else
+                hashmap = &enumerator->nomatch_sysattr;
+
+        r = hashmap_ensure_allocated(hashmap, NULL);
+        if (r < 0)
+                return r;
+
+        sysattr = strdup(_sysattr);
+        if (!sysattr)
+                return -ENOMEM;
+
+        value = strdup(_value);
+        if (!value)
+                return -ENOMEM;
+
+        r = hashmap_put(*hashmap, sysattr, value);
+        if (r < 0)
+                return r;
+
+        sysattr = NULL;
+        value = NULL;
+
+        enumerator->scan_uptodate = false;
+
+        return 0;
+}
+
+_public_ int sd_device_enumerator_add_match_property(sd_device_enumerator *enumerator, const char *_property, const char *_value) {
+        _cleanup_free_ char *property = NULL, *value = NULL;
+        int r;
+
+        assert_return(enumerator, -EINVAL);
+        assert_return(_property, -EINVAL);
+        assert_return(_value, -EINVAL);
+
+        r = hashmap_ensure_allocated(&enumerator->match_property, NULL);
+        if (r < 0)
+                return r;
+
+        property = strdup(_property);
+        if (!property)
+                return -ENOMEM;
+
+        value = strdup(_value);
+        if (!value)
+                return -ENOMEM;
+
+        r = hashmap_put(enumerator->match_property, property, value);
+        if (r < 0)
+                return r;
+
+        property = NULL;
+        value = NULL;
+
+        enumerator->scan_uptodate = false;
+
+        return 0;
+}
+
+_public_ int sd_device_enumerator_add_match_sysname(sd_device_enumerator *enumerator, const char *sysname) {
+        int r;
+
+        assert_return(enumerator, -EINVAL);
+        assert_return(sysname, -EINVAL);
+
+        r = set_ensure_allocated(&enumerator->match_sysname, NULL);
+        if (r < 0)
+                return r;
+
+        r = set_put_strdup(enumerator->match_sysname, sysname);
+        if (r < 0)
+                return r;
+
+        enumerator->scan_uptodate = false;
+
+        return 0;
+}
+
+_public_ int sd_device_enumerator_add_match_tag(sd_device_enumerator *enumerator, const char *tag) {
+        int r;
+
+        assert_return(enumerator, -EINVAL);
+        assert_return(tag, -EINVAL);
+
+        r = set_ensure_allocated(&enumerator->match_tag, NULL);
+        if (r < 0)
+                return r;
+
+        r = set_put_strdup(enumerator->match_tag, tag);
+        if (r < 0)
+                return r;
+
+        enumerator->scan_uptodate = false;
+
+        return 0;
+}
+
+_public_ int sd_device_enumerator_add_match_parent(sd_device_enumerator *enumerator, sd_device *parent) {
+        assert_return(enumerator, -EINVAL);
+        assert_return(parent, -EINVAL);
+
+        sd_device_unref(enumerator->match_parent);
+        enumerator->match_parent = sd_device_ref(parent);
+
+        enumerator->scan_uptodate = false;
+
+        return 0;
+}
+
+_public_ int sd_device_enumerator_add_match_is_initialized(sd_device_enumerator *enumerator) {
+        assert_return(enumerator, -EINVAL);
+
+        enumerator->match_is_initialized = true;
+
+        enumerator->scan_uptodate = false;
+
+        return 0;
+}
+
+static int device_compare(const void *_a, const void *_b) {
+        sd_device *a = (sd_device *)_a, *b = (sd_device *)_b;
+        const char *devpath_a, *devpath_b, *sound_a;
+        bool delay_a = false, delay_b = false;
+
+        assert_se(sd_device_get_devpath(a, &devpath_a) >= 0);
+        assert_se(sd_device_get_devpath(b, &devpath_b) >= 0);
+
+        sound_a = strstr(devpath_a, "/sound/card");
+        if (sound_a) {
+                /* For sound cards the control device must be enumerated last to
+                 * make sure it's the final device node that gets ACLs applied.
+                 * Applications rely on this fact and use ACL changes on the
+                 * control node as an indicator that the ACL change of the
+                 * entire sound card completed. The kernel makes this guarantee
+                 * when creating those devices, and hence we should too when
+                 * enumerating them. */
+                sound_a += strlen("/sound/card");
+                sound_a = strchr(sound_a, '/');
+
+                if (sound_a) {
+                        unsigned prefix_len;
+
+                        prefix_len = sound_a - devpath_a;
+
+                        if (strncmp(devpath_a, devpath_b, prefix_len) == 0) {
+                                const char *sound_b;
+
+                                sound_b = devpath_b + prefix_len;
+
+                                if (startswith(sound_a, "/controlC") &&
+                                    !startswith(sound_b, "/contolC"))
+                                        return 1;
+
+                                if (!startswith(sound_a, "/controlC") &&
+                                    startswith(sound_b, "/controlC"))
+                                        return -1;
+                        }
+                }
+        }
+
+        /* md and dm devices are enumerated after all other devices */
+        if (strstr(devpath_a, "/block/md") || strstr(devpath_a, "/block/dm-"))
+                delay_a = true;
+
+        if (strstr(devpath_b, "/block/md") || strstr(devpath_b, "/block/dm-"))
+                delay_b = true;
+
+        if (delay_a && !delay_b)
+                return 1;
+
+        if (!delay_a && delay_b)
+                return -1;
+
+        return strcmp(devpath_a, devpath_b);
+}
+
+_public_ int sd_device_enumerator_add_device(sd_device_enumerator *enumerator, sd_device *device) {
+        int r;
+
+        assert_return(enumerator, -EINVAL);
+        assert_return(device, -EINVAL);
+
+        r = prioq_ensure_allocated(&enumerator->devices, device_compare);
+        if (r < 0)
+                return r;
+
+        r = prioq_put(enumerator->devices, device, NULL);
+        if (r < 0)
+                return r;
+
+        sd_device_ref(device);
+
+        return 0;
+}
+
+static bool match_sysattr_value(sd_device *device, const char *sysattr, const char *match_value) {
+        const char *value;
+        int r;
+
+        assert(device);
+        assert(sysattr);
+
+        r = sd_device_get_sysattr_value(device, sysattr, &value);
+        if (r < 0)
+                return false;
+
+        if (!match_value)
+                return true;
+
+        if (fnmatch(match_value, value, 0) == 0)
+                return true;
+
+        return false;
+}
+
+static bool match_sysattr(sd_device_enumerator *enumerator, sd_device *device) {
+        const char *sysattr;
+        const char *value;
+        Iterator i;
+
+        assert(enumerator);
+        assert(device);
+
+        HASHMAP_FOREACH_KEY(sysattr, value, enumerator->nomatch_sysattr, i)
+                if (match_sysattr_value(device, sysattr, value))
+                        return false;
+
+        HASHMAP_FOREACH_KEY(sysattr, value, enumerator->match_sysattr, i)
+                if (!match_sysattr_value(device, sysattr, value))
+                        return false;
+
+        return true;
+}
+
+static bool match_property(sd_device_enumerator *enumerator, sd_device *device) {
+        const char *property;
+        const char *value;
+        Iterator i;
+
+        assert(enumerator);
+        assert(device);
+
+        if (hashmap_isempty(enumerator->match_property))
+                return true;
+
+        HASHMAP_FOREACH_KEY(property, value, enumerator->match_property, i) {
+                const char *property_dev, *value_dev;
+
+                FOREACH_DEVICE_PROPERTY(device, property_dev, value_dev) {
+                        if (fnmatch(property, property_dev, 0) != 0)
+                                continue;
+
+                        if (!value && !value_dev)
+                                return true;
+
+                        if (!value || !value_dev)
+                                continue;
+
+                        if (fnmatch(value, value_dev, 0) == 0)
+                                return true;
+                }
+        }
+
+        return false;
+}
+
+static bool match_tag(sd_device_enumerator *enumerator, sd_device *device) {
+        const char *tag;
+        Iterator i;
+
+        assert(enumerator);
+        assert(device);
+
+        SET_FOREACH(tag, enumerator->match_tag, i)
+                if (!sd_device_has_tag(device, tag))
+                        return false;
+
+        return true;
+}
+
+static bool match_parent(sd_device_enumerator *enumerator, sd_device *device) {
+        const char *devpath, *devpath_dev;
+        int r;
+
+        assert(enumerator);
+        assert(device);
+
+        if (!enumerator->match_parent)
+                return true;
+
+        r = sd_device_get_devpath(enumerator->match_parent, &devpath);
+        assert(r >= 0);
+
+        r = sd_device_get_devpath(device, &devpath_dev);
+        assert(r >= 0);
+
+        return startswith(devpath_dev, devpath);
+}
+
+static bool match_sysname(sd_device_enumerator *enumerator, const char *sysname) {
+        const char *sysname_match;
+        Iterator i;
+
+        assert(enumerator);
+        assert(sysname);
+
+        if (set_isempty(enumerator->match_sysname))
+                return true;
+
+        SET_FOREACH(sysname_match, enumerator->match_sysname, i)
+                if (fnmatch(sysname_match, sysname, 0) == 0)
+                        return true;
+
+        return false;
+}
+
+static int enumerator_scan_dir_and_add_devices(sd_device_enumerator *enumerator, const char *basedir, const char *subdir1, const char *subdir2) {
+        _cleanup_closedir_ DIR *dir = NULL;
+        char *path;
+        struct dirent *dent;
+        int r = 0;
+
+        assert(enumerator);
+        assert(basedir);
+
+        path = strjoina("/sys/", basedir, "/");
+
+        if (subdir1)
+                path = strjoina(path, subdir1, "/");
+
+        if (subdir2)
+                path = strjoina(path, subdir2, "/");
+
+        dir = opendir(path);
+        if (!dir)
+                return -errno;
+
+        FOREACH_DIRENT_ALL(dent, dir, return -errno) {
+                _cleanup_device_unref_ sd_device *device = NULL;
+                char syspath[strlen(path) + 1 + strlen(dent->d_name) + 1];
+                dev_t devnum;
+                int ifindex, initialized, k;
+
+                if (dent->d_name[0] == '.')
+                        continue;
+
+                if (!match_sysname(enumerator, dent->d_name))
+                        continue;
+
+                (void)sprintf(syspath, "%s%s", path, dent->d_name);
+
+                k = sd_device_new_from_syspath(&device, syspath);
+                if (k < 0) {
+                        log_debug_errno(k, "device-enumerator: failed to create device from syspath %s: %m", syspath);
+                        r = k;
+                        continue;
+                }
+
+                k = sd_device_get_devnum(device, &devnum);
+                if (k < 0) {
+                        r = k;
+                        continue;
+                }
+
+                k = sd_device_get_ifindex(device, &ifindex);
+                if (k < 0) {
+                        r = k;
+                        continue;
+                }
+
+                k = sd_device_get_is_initialized(device, &initialized);
+                if (k < 0) {
+                        r = k;
+                        continue;
+                }
+
+                /*
+                 * All devices with a device node or network interfaces
+                 * possibly need udev to adjust the device node permission
+                 * or context, or rename the interface before it can be
+                 * reliably used from other processes.
+                 *
+                 * For now, we can only check these types of devices, we
+                 * might not store a database, and have no way to find out
+                 * for all other types of devices.
+                 */
+                if (enumerator->match_is_initialized &&
+                    !initialized &&
+                    (major(devnum) > 0 || ifindex > 0))
+                        continue;
+
+                if (!match_parent(enumerator, device))
+                        continue;
+
+                if (!match_tag(enumerator, device))
+                        continue;
+
+                if (!match_property(enumerator, device))
+                        continue;
+
+                if (!match_sysattr(enumerator, device))
+                        continue;
+
+                k = sd_device_enumerator_add_device(enumerator, device);
+                if (k < 0)
+                        r = k;
+        }
+
+        return r;
+}
+
+static bool match_subsystem(sd_device_enumerator *enumerator, const char *subsystem) {
+        const char *subsystem_match;
+        Iterator i;
+
+        assert(enumerator);
+
+        if (!subsystem)
+                return false;
+
+        SET_FOREACH(subsystem_match, enumerator->nomatch_subsystem, i)
+                if (fnmatch(subsystem_match, subsystem, 0) == 0)
+                        return false;
+
+        if (set_isempty(enumerator->match_subsystem))
+                return true;
+
+        SET_FOREACH(subsystem_match, enumerator->match_subsystem, i)
+                if (fnmatch(subsystem_match, subsystem, 0) == 0)
+                        return true;
+
+        return false;
+}
+
+static int enumerator_scan_dir(sd_device_enumerator *enumerator, const char *basedir, const char *subdir, const char *subsystem) {
+        _cleanup_closedir_ DIR *dir = NULL;
+        char *path;
+        struct dirent *dent;
+        int r = 0;
+
+        path = strjoina("/sys/", basedir);
+
+        dir = opendir(path);
+        if (!dir)
+                return -errno;
+
+        log_debug("  device-enumerator: scanning %s", path);
+
+        FOREACH_DIRENT_ALL(dent, dir, return -errno) {
+                int k;
+
+                if (dent->d_name[0] == '.')
+                        continue;
+
+                if (!match_subsystem(enumerator, subsystem ? : dent->d_name))
+                        continue;
+
+                k = enumerator_scan_dir_and_add_devices(enumerator, basedir, dent->d_name, subdir);
+                if (k < 0)
+                        r = k;
+        }
+
+        return r;
+}
+
+static int enumerator_scan_devices_tag(sd_device_enumerator *enumerator, const char *tag) {
+        _cleanup_closedir_ DIR *dir = NULL;
+        char *path;
+        struct dirent *dent;
+        int r = 0;
+
+        assert(enumerator);
+        assert(tag);
+
+        path = strjoina("/run/udev/tags/", tag);
+
+        dir = opendir(path);
+        if (!dir) {
+                if (errno == ENOENT)
+                        return 0;
+                else {
+                        log_error("sd-device-enumerator: could not open tags directory %s: %m", path);
+                        return -errno;
+                }
+        }
+
+        /* TODO: filter away subsystems? */
+
+        FOREACH_DIRENT_ALL(dent, dir, return -errno) {
+                _cleanup_device_unref_ sd_device *device = NULL;
+                const char *subsystem, *sysname;
+                int k;
+
+                if (dent->d_name[0] == '.')
+                        continue;
+
+                k = sd_device_new_from_device_id(&device, dent->d_name);
+                if (k < 0) {
+                        r = k;
+                        continue;
+                }
+
+                k = sd_device_get_subsystem(device, &subsystem);
+                if (k < 0) {
+                        r = k;
+                        continue;
+                }
+
+                if (!match_subsystem(enumerator, subsystem))
+                        continue;
+
+                k = sd_device_get_sysname(device, &sysname);
+                if (k < 0) {
+                        r = k;
+                        continue;
+                }
+
+                if (!match_sysname(enumerator, sysname))
+                        continue;
+
+                if (!match_parent(enumerator, device))
+                        continue;
+
+                if (!match_property(enumerator, device))
+                        continue;
+
+                if (!match_sysattr(enumerator, device))
+                        continue;
+
+                k = sd_device_enumerator_add_device(enumerator, device);
+                if (k < 0) {
+                        r = k;
+                        continue;
+                }
+        }
+
+        return r;
+}
+
+static int enumerator_scan_devices_tags(sd_device_enumerator *enumerator) {
+        const char *tag;
+        Iterator i;
+        int r;
+
+        assert(enumerator);
+
+        SET_FOREACH(tag, enumerator->match_tag, i) {
+                r = enumerator_scan_devices_tag(enumerator, tag);
+                if (r < 0)
+                        return r;
+        }
+
+        return 0;
+}
+
+static int parent_add_child(sd_device_enumerator *enumerator, const char *path) {
+        _cleanup_device_unref_ sd_device *device = NULL;
+        const char *subsystem, *sysname;
+        int r;
+
+        r = sd_device_new_from_syspath(&device, path);
+        if (r == -ENOENT)
+                return 0;
+        else if (r < 0)
+                return r;
+
+        r = sd_device_get_subsystem(device, &subsystem);
+        if (r < 0)
+                return r;
+
+        if (!match_subsystem(enumerator, subsystem))
+                return 0;
+
+        r = sd_device_get_sysname(device, &sysname);
+        if (r < 0)
+                return r;
+
+        if (!match_sysname(enumerator, sysname))
+                return 0;
+
+        if (!match_property(enumerator, device))
+                return 0;
+
+        if (!match_sysattr(enumerator, device))
+                return 0;
+
+        r = sd_device_enumerator_add_device(enumerator, device);
+        if (r < 0)
+                return r;
+
+        return 1;
+}
+
+static int parent_crawl_children(sd_device_enumerator *enumerator, const char *path, unsigned maxdepth) {
+        _cleanup_closedir_ DIR *dir = NULL;
+        struct dirent *dent;
+        int r = 0;
+
+        dir = opendir(path);
+        if (!dir) {
+                log_debug("sd-device-enumerate: could not open parent directory %s: %m", path);
+                return -errno;
+        }
+
+        FOREACH_DIRENT_ALL(dent, dir, return -errno) {
+                _cleanup_free_ char *child = NULL;
+                int k;
+
+                if (dent->d_name[0] == '.')
+                        continue;
+
+                if (dent->d_type != DT_DIR)
+                        continue;
+
+                k = asprintf(&child, "%s/%s", path, dent->d_name);
+                if (k < 0)
+                        return -errno;
+
+                k = parent_add_child(enumerator, child);
+                if (k < 0)
+                        r = k;
+
+                if (maxdepth > 0)
+                        parent_crawl_children(enumerator, child, maxdepth - 1);
+                else
+                        log_debug("device-enumerate: max depth reached, %s: ignoring devices", child);
+        }
+
+        return r;
+}
+
+static int enumerator_scan_devices_children(sd_device_enumerator *enumerator) {
+        const char *path;
+        int r = 0, k;
+
+        r = sd_device_get_syspath(enumerator->match_parent, &path);
+        if (r < 0)
+                return r;
+
+        k = parent_add_child(enumerator, path);
+        if (k < 0)
+                r = k;
+
+        k = parent_crawl_children(enumerator, path, DEVICE_ENUMERATE_MAX_DEPTH);
+        if (k < 0)
+                r = k;
+
+        return r;
+}
+
+static int enumerator_scan_devices_all(sd_device_enumerator *enumerator) {
+        int r = 0;
+
+        log_debug("device-enumerator: scan all dirs");
+
+        if (access("/sys/subsystem", F_OK) >= 0) {
+                /* we have /subsystem/, forget all the old stuff */
+                r = enumerator_scan_dir(enumerator, "subsystem", "devices", NULL);
+                if (r < 0) {
+                        log_debug("device-enumerator: failed to scan /sys/subsystem: %s", strerror(-r));
+                        return r;
+                }
+        } else {
+                int k;
+
+                k = enumerator_scan_dir(enumerator, "bus", "devices", NULL);
+                if (k < 0) {
+                        log_debug_errno(k, "device-enumerator: failed to scan /sys/bus: %m");
+                        r = k;
+                }
+
+                k = enumerator_scan_dir(enumerator, "class", NULL, NULL);
+                if (k < 0) {
+                        log_debug_errno(k, "device-enumerator: failed to scan /sys/class: %m");
+                        r = k;
+                }
+        }
+
+        return r;
+}
+
+int device_enumerator_scan_devices(sd_device_enumerator *enumerator) {
+        sd_device *device;
+        int r;
+
+        assert(enumerator);
+
+        if (enumerator->scan_uptodate &&
+            enumerator->type == DEVICE_ENUMERATION_TYPE_DEVICES)
+                return 0;
+
+        while ((device = prioq_pop(enumerator->devices)))
+                sd_device_unref(device);
+
+        if (!set_isempty(enumerator->match_tag)) {
+                r = enumerator_scan_devices_tags(enumerator);
+                if (r < 0)
+                        return r;
+        } else if (enumerator->match_parent) {
+                r = enumerator_scan_devices_children(enumerator);
+                if (r < 0)
+                        return r;
+        } else {
+                r = enumerator_scan_devices_all(enumerator);
+                if (r < 0)
+                        return r;
+        }
+
+        enumerator->scan_uptodate = true;
+
+        return 0;
+}
+
+_public_ sd_device *sd_device_enumerator_get_device_first(sd_device_enumerator *enumerator) {
+        int r;
+
+        assert_return(enumerator, NULL);
+
+        r = device_enumerator_scan_devices(enumerator);
+        if (r < 0)
+                return NULL;
+
+        enumerator->type = DEVICE_ENUMERATION_TYPE_DEVICES;
+
+        return prioq_peek(enumerator->devices);
+}
+
+_public_ sd_device *sd_device_enumerator_get_device_next(sd_device_enumerator *enumerator) {
+        assert_return(enumerator, NULL);
+
+        if (!enumerator->scan_uptodate ||
+            enumerator->type != DEVICE_ENUMERATION_TYPE_DEVICES)
+                return NULL;
+
+        sd_device_unref(prioq_pop(enumerator->devices));
+
+        return prioq_peek(enumerator->devices);
+}
+
+int device_enumerator_scan_subsystems(sd_device_enumerator *enumerator) {
+        sd_device *device;
+        const char *subsysdir;
+        int r = 0, k;
+
+        assert(enumerator);
+
+        if (enumerator->scan_uptodate &&
+            enumerator->type == DEVICE_ENUMERATION_TYPE_SUBSYSTEMS)
+                return 0;
+
+        while ((device = prioq_pop(enumerator->devices)))
+                sd_device_unref(device);
+
+        /* modules */
+        if (match_subsystem(enumerator, "module")) {
+                k = enumerator_scan_dir_and_add_devices(enumerator, "module", NULL, NULL);
+                if (k < 0) {
+                        log_debug_errno(k, "device-enumerator: failed to scan modules: %m");
+                        r = k;
+                }
+        }
+
+        if (access("/sys/subsystem", F_OK) >= 0)
+                subsysdir = "subsystem";
+        else
+                subsysdir = "bus";
+
+        /* subsystems (only buses support coldplug) */
+        if (match_subsystem(enumerator, "subsystem")) {
+                k = enumerator_scan_dir_and_add_devices(enumerator, subsysdir, NULL, NULL);
+                if (k < 0) {
+                        log_debug_errno(k, "device-enumerator: failed to scan subsystems: %m");
+                        r = k;
+                }
+        }
+
+        /* subsystem drivers */
+        if (match_subsystem(enumerator, "drivers")) {
+                k = enumerator_scan_dir(enumerator, subsysdir, "drivers", "drivers");
+                if (k < 0) {
+                        log_debug_errno(k, "device-enumerator: failed to scan drivers: %m");
+                        r = k;
+                }
+        }
+
+        enumerator->scan_uptodate = true;
+
+        return r;
+}
+
+_public_ sd_device *sd_device_enumerator_get_subsystem_first(sd_device_enumerator *enumerator) {
+        int r;
+
+        assert_return(enumerator, NULL);
+
+        r = device_enumerator_scan_subsystems(enumerator);
+        if (r < 0)
+                return NULL;
+
+        enumerator->type = DEVICE_ENUMERATION_TYPE_SUBSYSTEMS;
+
+        return prioq_peek(enumerator->devices);
+}
+
+_public_ sd_device *sd_device_enumerator_get_subsystem_next(sd_device_enumerator *enumerator) {
+        assert_return(enumerator, NULL);
+
+        if (enumerator->scan_uptodate ||
+            enumerator->type != DEVICE_ENUMERATION_TYPE_SUBSYSTEMS)
+                return NULL;
+
+        sd_device_unref(prioq_pop(enumerator->devices));
+
+        return prioq_peek(enumerator->devices);
+}
+
+sd_device *device_enumerator_get_first(sd_device_enumerator *enumerator) {
+        assert_return(enumerator, NULL);
+
+        return prioq_peek(enumerator->devices);
+}
+
+sd_device *device_enumerator_get_next(sd_device_enumerator *enumerator) {
+        assert_return(enumerator, NULL);
+
+        sd_device_unref(prioq_pop(enumerator->devices));
+
+        return prioq_peek(enumerator->devices);
+}
diff --git a/src/libsystemd/sd-device/device-util.h b/src/libsystemd/sd-device/device-util.h
index bfbb328..9b05a24 100644
--- a/src/libsystemd/sd-device/device-util.h
+++ b/src/libsystemd/sd-device/device-util.h
@@ -5,7 +5,7 @@
 /***
   This file is part of systemd.
 
-  Copyright 2014 Tom Gundersen <teg at jklm.no>
+  Copyright 2014-2015 Tom Gundersen <teg at jklm.no>
 
   systemd is free software; you can redistribute it and/or modify it
   under the terms of the GNU Lesser General Public License as published by
@@ -24,9 +24,11 @@
 #include "util.h"
 
 DEFINE_TRIVIAL_CLEANUP_FUNC(sd_device*, sd_device_unref);
-
 #define _cleanup_device_unref_ _cleanup_(sd_device_unrefp)
 
+DEFINE_TRIVIAL_CLEANUP_FUNC(sd_device_enumerator*, sd_device_enumerator_unref);
+#define _cleanup_device_enumerator_unref_ _cleanup_(sd_device_enumerator_unrefp)
+
 #define FOREACH_DEVICE_PROPERTY(device, key, value)                \
         for (key = sd_device_get_property_first(device, &(value)); \
              key;                                                  \
@@ -46,3 +48,13 @@ DEFINE_TRIVIAL_CLEANUP_FUNC(sd_device*, sd_device_unref);
         for (devlink = sd_device_get_devlink_first(device); \
              devlink;                                   \
              devlink = sd_device_get_devlink_next(device))
+
+#define FOREACH_DEVICE(enumerator, device)                               \
+        for (device = sd_device_enumerator_get_device_first(enumerator); \
+             device;                                                     \
+             device = sd_device_enumerator_get_device_next(enumerator))
+
+#define FOREACH_SUBSYSTEM(enumerator, device)                               \
+        for (device = sd_device_enumerator_get_subsystem_first(enumerator); \
+             device;                                                        \
+             device = sd_device_enumerator_get_subsystem_next(enumerator))
diff --git a/src/systemd/sd-device.h b/src/systemd/sd-device.h
index d737753..5fcd35f 100644
--- a/src/systemd/sd-device.h
+++ b/src/systemd/sd-device.h
@@ -7,7 +7,7 @@
   This file is part of systemd.
 
   Copyright 2008-2012 Kay Sievers <kay at vrfy.org>
-  Copyright 2014 Tom Gundersen <teg at jklm.no>
+  Copyright 2014-2015 Tom Gundersen <teg at jklm.no>
 
   systemd is free software; you can redistribute it and/or modify it
   under the terms of the GNU Lesser General Public License as published by
@@ -31,6 +31,9 @@
 _SD_BEGIN_DECLARATIONS;
 
 typedef struct sd_device sd_device;
+typedef struct sd_device_enumerator sd_device_enumerator;
+
+/* device */
 
 sd_device *sd_device_ref(sd_device *device);
 sd_device *sd_device_unref(sd_device *device);
@@ -72,6 +75,27 @@ int sd_device_get_sysattr_value(sd_device *device, const char *sysattr, const ch
 
 int sd_device_set_sysattr_value(sd_device *device, const char *sysattr, char *value);
 
+/* device enumerator */
+
+int sd_device_enumerator_new(sd_device_enumerator **ret);
+sd_device_enumerator *sd_device_enumerator_ref(sd_device_enumerator *enumerator);
+sd_device_enumerator *sd_device_enumerator_unref(sd_device_enumerator *enumerator);
+
+int sd_device_enumerator_add_device(sd_device_enumerator *enumerator, sd_device *device);
+
+sd_device *sd_device_enumerator_get_device_first(sd_device_enumerator *enumerator);
+sd_device *sd_device_enumerator_get_device_next(sd_device_enumerator *enumerator);
+sd_device *sd_device_enumerator_get_subsystem_first(sd_device_enumerator *enumerator);
+sd_device *sd_device_enumerator_get_subsystem_next(sd_device_enumerator *enumerator);
+
+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_property(sd_device_enumerator *enumerator, const char *property, const char *value);
+int sd_device_enumerator_add_match_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_add_match_parent(sd_device_enumerator *enumerator, sd_device *parent);
+int sd_device_enumerator_add_match_is_initialized(sd_device_enumerator *enumerator);
+
 _SD_END_DECLARATIONS;
 
 #endif

commit aa02962840e10fa7d052760b98a5c092dd0990e1
Author: Tom Gundersen <teg at jklm.no>
Date:   Fri Apr 10 20:39:43 2015 +0200

    shared: move assert_return_errno() from libudev
    
    This should not be used for any new code, as we don't set errno in new code,
    but there are several legacy users, so let's keep it in shared.

diff --git a/src/libudev/libudev-device-internal.h b/src/libudev/libudev-device-internal.h
index 18ae7a9..b6ecce8 100644
--- a/src/libudev/libudev-device-internal.h
+++ b/src/libudev/libudev-device-internal.h
@@ -51,12 +51,3 @@ struct udev_device {
 };
 
 struct udev_device *udev_device_new(struct udev *udev);
-
-#define assert_return_errno(expr, r, err)                               \
-        do {                                                            \
-                if (_unlikely_(!(expr))) {                              \
-                        log_assert_failed_return(#expr, __FILE__, __LINE__, __PRETTY_FUNCTION__); \
-                        errno = err;                                    \
-                        return (r);                                     \
-                }                                                       \
-        } while (false)
diff --git a/src/shared/macro.h b/src/shared/macro.h
index 7f89951..7ae1ed8 100644
--- a/src/shared/macro.h
+++ b/src/shared/macro.h
@@ -256,6 +256,15 @@ static inline unsigned long ALIGN_POWER2(unsigned long u) {
                 }                                                       \
         } while (false)
 
+#define assert_return_errno(expr, r, err)                               \
+        do {                                                            \
+                if (_unlikely_(!(expr))) {                              \
+                        log_assert_failed_return(#expr, __FILE__, __LINE__, __PRETTY_FUNCTION__); \
+                        errno = err;                                    \
+                        return (r);                                     \
+                }                                                       \
+        } while (false)
+
 #define PTR_TO_INT(p) ((int) ((intptr_t) (p)))
 #define INT_TO_PTR(u) ((void *) ((intptr_t) (u)))
 #define PTR_TO_UINT(p) ((unsigned int) ((uintptr_t) (p)))



More information about the systemd-commits mailing list