chiark / gitweb /
libudev: enumerate - do not try to match against an empty subsystem
[elogind.git] / src / libudev / libudev-enumerate.c
index 4725912c362add46dbe511f61c5afb69cb09f848..bc1e37d3413bc1decd74c833a23fe98b82339418 100644 (file)
@@ -1,13 +1,21 @@
-/*
- * libudev - interface to udev device information
- *
- * Copyright (C) 2008-2010 Kay Sievers <kay.sievers@vrfy.org>
- *
- * This library 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.
- */
+/***
+  This file is part of systemd.
+
+  Copyright 2008-2012 Kay Sievers <kay@vrfy.org>
+
+  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 <stdio.h>
 #include <stdlib.h>
@@ -65,12 +73,16 @@ struct udev_enumerate {
  * udev_enumerate_new:
  * @udev: udev library context
  *
- * Returns: an enumeration context
+ * Create an enumeration context to scan /sys.
+ *
+ * Returns: an enumeration context.
  **/
 _public_ struct udev_enumerate *udev_enumerate_new(struct udev *udev)
 {
         struct udev_enumerate *udev_enumerate;
 
+        if (udev == NULL)
+                return NULL;
         udev_enumerate = calloc(1, sizeof(struct udev_enumerate));
         if (udev_enumerate == NULL)
                 return NULL;
@@ -109,16 +121,18 @@ _public_ struct udev_enumerate *udev_enumerate_ref(struct udev_enumerate *udev_e
  *
  * Drop a reference of an enumeration context. If the refcount reaches zero,
  * all resources of the enumeration context will be released.
+ *
+ * Returns: the passed enumeration context if it has still an active reference, or #NULL otherwise.
  **/
-_public_ void udev_enumerate_unref(struct udev_enumerate *udev_enumerate)
+_public_ struct udev_enumerate *udev_enumerate_unref(struct udev_enumerate *udev_enumerate)
 {
         unsigned int i;
 
         if (udev_enumerate == NULL)
-                return;
+                return NULL;
         udev_enumerate->refcount--;
         if (udev_enumerate->refcount > 0)
-                return;
+                return udev_enumerate;
         udev_list_cleanup(&udev_enumerate->sysattr_match_list);
         udev_list_cleanup(&udev_enumerate->sysattr_nomatch_list);
         udev_list_cleanup(&udev_enumerate->subsystem_match_list);
@@ -132,13 +146,16 @@ _public_ void udev_enumerate_unref(struct udev_enumerate *udev_enumerate)
                 free(udev_enumerate->devices[i].syspath);
         free(udev_enumerate->devices);
         free(udev_enumerate);
+        return NULL;
 }
 
 /**
  * udev_enumerate_get_udev:
  * @udev_enumerate: context
  *
- * Returns: the udev library context.
+ * Get the udev library context.
+ *
+ * Returns: a pointer to the context.
  */
 _public_ struct udev *udev_enumerate_get_udev(struct udev_enumerate *udev_enumerate)
 {
@@ -243,7 +260,9 @@ static size_t devices_delay_later(struct udev *udev, const char *syspath)
  * udev_enumerate_get_list_entry:
  * @udev_enumerate: context
  *
- * Returns: the first entry of the sorted list of device paths.
+ * Get the first entry of the sorted list of device paths.
+ *
+ * Returns: a udev_list_entry.
  */
 _public_ struct udev_list_entry *udev_enumerate_get_list_entry(struct udev_enumerate *udev_enumerate)
 {
@@ -251,8 +270,9 @@ _public_ struct udev_list_entry *udev_enumerate_get_list_entry(struct udev_enume
                 return NULL;
         if (!udev_enumerate->devices_uptodate) {
                 unsigned int i;
+                int move_later = -1;
                 unsigned int max;
-                struct syspath *prev = NULL, *move_later = NULL;
+                struct syspath *prev = NULL;
                 size_t move_later_prefix = 0;
 
                 udev_list_cleanup(&udev_enumerate->devices_list);
@@ -284,23 +304,25 @@ _public_ struct udev_list_entry *udev_enumerate_get_list_entry(struct udev_enume
                                 move_later_prefix = devices_delay_later(udev_enumerate->udev, entry->syspath);
 
                                 if (move_later_prefix > 0) {
-                                        move_later = entry;
+                                        move_later = i;
                                         continue;
                                 }
                         }
 
-                        if (move_later &&
-                            strncmp(entry->syspath, move_later->syspath, move_later_prefix) != 0) {
+                        if ((move_later >= 0) &&
+                             !strneq(entry->syspath, udev_enumerate->devices[move_later].syspath, move_later_prefix)) {
 
-                                udev_list_entry_add(&udev_enumerate->devices_list, move_later->syspath, NULL);
-                                move_later = NULL;
+                                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)
-                        udev_list_entry_add(&udev_enumerate->devices_list, move_later->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++) {
@@ -321,6 +343,8 @@ _public_ struct udev_list_entry *udev_enumerate_get_list_entry(struct udev_enume
  * @udev_enumerate: context
  * @subsystem: filter for a subsystem of the device to include in the list
  *
+ * Match only devices belonging to a certain kernel subsystem.
+ *
  * Returns: 0 on success, otherwise a negative error value.
  */
 _public_ int udev_enumerate_add_match_subsystem(struct udev_enumerate *udev_enumerate, const char *subsystem)
@@ -339,6 +363,8 @@ _public_ int udev_enumerate_add_match_subsystem(struct udev_enumerate *udev_enum
  * @udev_enumerate: context
  * @subsystem: filter for a subsystem of the device to exclude from the list
  *
+ * Match only devices not belonging to a certain kernel subsystem.
+ *
  * Returns: 0 on success, otherwise a negative error value.
  */
 _public_ int udev_enumerate_add_nomatch_subsystem(struct udev_enumerate *udev_enumerate, const char *subsystem)
@@ -358,6 +384,8 @@ _public_ int udev_enumerate_add_nomatch_subsystem(struct udev_enumerate *udev_en
  * @sysattr: filter for a sys attribute at the device to include in the list
  * @value: optional value of the sys attribute
  *
+ * Match only devices with a certain /sys device attribute.
+ *
  * 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)
@@ -377,6 +405,8 @@ _public_ int udev_enumerate_add_match_sysattr(struct udev_enumerate *udev_enumer
  * @sysattr: filter for a sys attribute at the device to exclude from the list
  * @value: optional value of the sys attribute
  *
+ * Match only devices not having a certain /sys device attribute.
+ *
  * 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)
@@ -416,6 +446,8 @@ exit:
  * @property: filter for a property of the device to include in the list
  * @value: value of the property
  *
+ * Match only devices with a certain property.
+ *
  * 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)
@@ -434,6 +466,8 @@ _public_ int udev_enumerate_add_match_property(struct udev_enumerate *udev_enume
  * @udev_enumerate: context
  * @tag: filter for a tag of the device to include in the list
  *
+ * Match only devices with a certain tag.
+ *
  * Returns: 0 on success, otherwise a negative error value.
  */
 _public_ int udev_enumerate_add_match_tag(struct udev_enumerate *udev_enumerate, const char *tag)
@@ -503,6 +537,8 @@ _public_ int udev_enumerate_add_match_is_initialized(struct udev_enumerate *udev
  * @udev_enumerate: context
  * @sysname: filter for the name of the device to include in the list
  *
+ * Match only devices with a given /sys device name.
+ *
  * Returns: 0 on success, otherwise a negative error value.
  */
 _public_ int udev_enumerate_add_match_sysname(struct udev_enumerate *udev_enumerate, const char *sysname)
@@ -626,11 +662,11 @@ static int scan_dir_and_add_devices(struct udev_enumerate *udev_enumerate,
         struct dirent *dent;
 
         s = path;
-        l = util_strpcpyl(&s, sizeof(path), "/sys/", basedir, NULL);
+        l = strpcpyl(&s, sizeof(path), "/sys/", basedir, NULL);
         if (subdir1 != NULL)
-                l = util_strpcpyl(&s, l, "/", subdir1, NULL);
+                l = strpcpyl(&s, l, "/", subdir1, NULL);
         if (subdir2 != NULL)
-                util_strpcpyl(&s, l, "/", subdir2, NULL);
+                strpcpyl(&s, l, "/", subdir2, NULL);
         dir = opendir(path);
         if (dir == NULL)
                 return -ENOENT;
@@ -644,7 +680,7 @@ static int scan_dir_and_add_devices(struct udev_enumerate *udev_enumerate,
                 if (!match_sysname(udev_enumerate, dent->d_name))
                         continue;
 
-                util_strscpyl(syspath, sizeof(syspath), path, "/", dent->d_name, NULL);
+                strscpyl(syspath, sizeof(syspath), path, "/", dent->d_name, NULL);
                 dev = udev_device_new_from_syspath(udev_enumerate->udev, syspath);
                 if (dev == NULL)
                         continue;
@@ -685,10 +721,14 @@ static bool match_subsystem(struct udev_enumerate *udev_enumerate, const char *s
 {
         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)
@@ -696,6 +736,7 @@ static bool match_subsystem(struct udev_enumerate *udev_enumerate, const char *s
                 }
                 return false;
         }
+
         return true;
 }
 
@@ -705,7 +746,7 @@ static int scan_dir(struct udev_enumerate *udev_enumerate, const char *basedir,
         DIR *dir;
         struct dirent *dent;
 
-        util_strscpyl(path, sizeof(path), "/sys/", basedir, NULL);
+        strscpyl(path, sizeof(path), "/sys/", basedir, NULL);
         dir = opendir(path);
         if (dir == NULL)
                 return -1;
@@ -756,7 +797,7 @@ static int scan_devices_tags(struct udev_enumerate *udev_enumerate)
                 struct dirent *dent;
                 char path[UTIL_PATH_SIZE];
 
-                util_strscpyl(path, sizeof(path), "/run/udev/tags/", udev_list_entry_get_name(list_entry), NULL);
+                strscpyl(path, sizeof(path), "/run/udev/tags/", udev_list_entry_get_name(list_entry), NULL);
                 dir = opendir(path);
                 if (dir == NULL)
                         continue;
@@ -766,7 +807,7 @@ static int scan_devices_tags(struct udev_enumerate *udev_enumerate)
                         if (dent->d_name[0] == '.')
                                 continue;
 
-                        dev = udev_device_new_from_id_filename(udev_enumerate->udev, dent->d_name);
+                        dev = udev_device_new_from_device_id(udev_enumerate->udev, dent->d_name);
                         if (dev == NULL)
                                 continue;
 
@@ -793,23 +834,27 @@ nomatch:
 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)))
-                return 0;
+                goto nomatch;
         if (!match_sysname(enumerate, udev_device_get_sysname(dev)))
-                return 0;
+                goto nomatch;
         if (!match_property(enumerate, dev))
-                return 0;
+                goto nomatch;
         if (!match_sysattr(enumerate, dev))
-                return 0;
+                goto nomatch;
 
         syspath_add(enumerate, udev_device_get_syspath(dev));
+        r = 1;
+
+nomatch:
         udev_device_unref(dev);
-        return 1;
+        return r;
 }
 
 static int parent_crawl_children(struct udev_enumerate *enumerate, const char *path, int maxdepth)
@@ -867,6 +912,9 @@ static int scan_devices_all(struct udev_enumerate *udev_enumerate)
  * udev_enumerate_scan_devices:
  * @udev_enumerate: udev enumeration context
  *
+ * Scan /sys for all devices which match the given filters. No matches
+ * will return all currently available devices.
+ *
  * Returns: 0 on success, otherwise a negative error value.
  **/
 _public_ int udev_enumerate_scan_devices(struct udev_enumerate *udev_enumerate)
@@ -890,6 +938,8 @@ _public_ int udev_enumerate_scan_devices(struct udev_enumerate *udev_enumerate)
  * udev_enumerate_scan_subsystems:
  * @udev_enumerate: udev enumeration context
  *
+ * Scan /sys for all kernel subsystems, including buses, classes, drivers.
+ *
  * Returns: 0 on success, otherwise a negative error value.
  **/
 _public_ int udev_enumerate_scan_subsystems(struct udev_enumerate *udev_enumerate)