hal: Branch 'master'
Kay Sievers
kay at kemper.freedesktop.org
Fri Sep 22 15:17:15 PDT 2006
hald/linux/blockdev.c | 2
hald/linux/coldplug.c | 645 ++++++++++++++++------------------------------
hald/linux/hotplug.c | 106 +------
hald/linux/osspec.c | 99 ++++---
hald/linux/osspec_linux.h | 2
5 files changed, 329 insertions(+), 525 deletions(-)
New commits:
diff-tree cd1823f11eea4de5e7a236bc19b29397658946f8 (from 6670789d3ca8cbc7c5ea9634f0621664c85e7dbb)
Author: Kay Sievers <kay.sievers at suse.de>
Date: Sat Sep 23 00:13:56 2006 +0200
rework Linux coldplug to work with future kernel changes
Adapt the current HAL coldplug/hotplug logic to work with future
kernels, where sysfs will have all device in a unified tree at
/sys/devices.
diff --git a/hald/linux/blockdev.c b/hald/linux/blockdev.c
index d6b10c4..7f48dbe 100644
--- a/hald/linux/blockdev.c
+++ b/hald/linux/blockdev.c
@@ -326,7 +326,7 @@ generate_fakevolume_hotplug_event_add_fo
hotplug_event = g_new0 (HotplugEvent, 1);
hotplug_event->action = HOTPLUG_ACTION_ADD;
- hotplug_event->type = HOTPLUG_EVENT_SYSFS;
+ hotplug_event->type = HOTPLUG_EVENT_SYSFS_BLOCK;
g_strlcpy (hotplug_event->sysfs.subsystem, "block", sizeof (hotplug_event->sysfs.subsystem));
g_strlcpy (hotplug_event->sysfs.sysfs_path, fake_sysfs_path, sizeof (hotplug_event->sysfs.sysfs_path));
if (device_file != NULL)
diff --git a/hald/linux/coldplug.c b/hald/linux/coldplug.c
index db9e922..2ce29f6 100644
--- a/hald/linux/coldplug.c
+++ b/hald/linux/coldplug.c
@@ -1,11 +1,9 @@
-/***************************************************************************
- * CVSID: $Id$
- *
- * coldplug.c : Synthesize hotplug events when starting up
+
+/*
+ * Synthesize device events when starting up
*
* Copyright (C) 2004 David Zeuthen, <david at fubar.dk>
- *
- * Licensed under the Academic Free License version 2.1
+ * Copyright (C) 2005-2006 Kay Sievers <kay.sievers at novell.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -21,7 +19,7 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
- **************************************************************************/
+ */
#ifdef HAVE_CONFIG_H
# include <config.h>
@@ -30,9 +28,9 @@
#include <stdint.h>
#include <stdio.h>
#include <string.h>
+#include <dirent.h>
#include <sys/stat.h>
#include <unistd.h>
-
#include <dbus/dbus.h>
#include <dbus/dbus-glib.h>
@@ -41,49 +39,22 @@
#include "../logger.h"
#include "../osspec.h"
#include "../util.h"
-
#include "osspec_linux.h"
#include "hotplug.h"
-
#include "coldplug.h"
#define DMPREFIX "dm-"
-/* For debugging */
-#define HAL_COLDPLUG_VERBOSE
+struct sysfs_device {
+ char *path;
+ char *subsystem;
+ HotplugEventType type;
+};
static GHashTable *sysfs_to_udev_map;
+static GSList *device_list;
static char dev_root[HAL_PATH_MAX];
-/* Returns the path of the udevinfo program
- *
- * @return Path or NULL if udevinfo program is not found
- */
-static const gchar *
-hal_util_get_udevinfo_path (void)
-{
- guint i;
- struct stat s;
- static gchar *path = NULL;
- gchar *possible_paths[] = {
- "/usr/bin/udevinfo",
- "/bin/udevinfo",
- "/usr/sbin/udevinfo",
- "/sbin/udevinfo",
- };
-
- if (path != NULL)
- return path;
-
- for (i = 0; i < sizeof (possible_paths) / sizeof (char *); i++) {
- if (stat (possible_paths[i], &s) == 0 && S_ISREG (s.st_mode)) {
- path = possible_paths[i];
- break;
- }
- }
- return path;
-}
-
static gboolean
hal_util_init_sysfs_to_udev_map (void)
{
@@ -95,8 +66,6 @@ hal_util_init_sysfs_to_udev_map (void)
char *p;
sysfs_to_udev_map = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
- udevdb_export_argv[0] = (char *) hal_util_get_udevinfo_path ();
- udevroot_argv[0] = (char *) hal_util_get_udevinfo_path ();
/* get udevroot */
if (g_spawn_sync ("/", udevroot_argv, NULL, 0, NULL, NULL,
@@ -153,9 +122,8 @@ hal_util_init_sysfs_to_udev_map (void)
if (line[0] == '\0') {
if (hotplug_event != NULL) {
g_hash_table_insert (sysfs_to_udev_map, g_strdup (hotplug_event->sysfs.sysfs_path), hotplug_event);
-#ifdef HAL_COLDPLUG_VERBOSE
- printf ("Got '%s' -> '%s'\n", hotplug_event->sysfs.sysfs_path, hotplug_event->sysfs.device_file);
-#endif
+ HAL_INFO (("found (udevdb export) '%s' -> '%s'",
+ hotplug_event->sysfs.sysfs_path, hotplug_event->sysfs.device_file));
hotplug_event = NULL;
}
continue;
@@ -234,7 +202,7 @@ error:
}
static HotplugEvent
-*coldplug_get_hotplug_event(const gchar *sysfs_path, const gchar *subsystem)
+*coldplug_get_hotplug_event(const gchar *sysfs_path, const gchar *subsystem, HotplugEventType type)
{
HotplugEvent *hotplug_event, *hotplug_event_udev;
const char *pos;
@@ -249,7 +217,7 @@ static HotplugEvent
hotplug_event_udev = (HotplugEvent *) g_hash_table_lookup (sysfs_to_udev_map, sysfs_path);
if (hotplug_event_udev != NULL) {
memcpy(hotplug_event, hotplug_event_udev, sizeof(HotplugEvent));
- HAL_INFO (("found in udevdb '%s' '%s'", hotplug_event->sysfs.sysfs_path, hotplug_event->sysfs.device_file));
+ HAL_INFO (("new event (dev node from udev) '%s' '%s'", hotplug_event->sysfs.sysfs_path, hotplug_event->sysfs.device_file));
} else {
/* device is not in udev database */
g_strlcpy(hotplug_event->sysfs.sysfs_path, sysfs_path, sizeof(hotplug_event->sysfs.sysfs_path));
@@ -271,421 +239,272 @@ static HotplugEvent
if (!S_ISBLK (statbuf.st_mode) && !S_ISCHR (statbuf.st_mode))
goto no_node;
- HAL_INFO (("found device_file %s for sysfs_path %s", path, sysfs_path));
+ HAL_INFO (("new event (dev node from kernel name) '%s' '%s'", sysfs_path, path));
g_strlcpy(hotplug_event->sysfs.device_file, path, sizeof(hotplug_event->sysfs.device_file));
}
no_node:
+ if (hotplug_event->sysfs.device_file[0] == '\0')
+ HAL_INFO (("new event (no dev node) '%s'", sysfs_path));
g_strlcpy (hotplug_event->sysfs.subsystem, subsystem, sizeof (hotplug_event->sysfs.subsystem));
hotplug_event->action = HOTPLUG_ACTION_ADD;
- hotplug_event->type = HOTPLUG_EVENT_SYSFS;
+ hotplug_event->type = type;
hotplug_event->sysfs.net_ifindex = -1;
return hotplug_event;
}
-static gboolean
-coldplug_synthesize_block_event(const gchar *f);
-
-static void
-coldplug_compute_visit_device (const gchar *path,
- GHashTable *sysfs_to_bus_map,
- GHashTable *sysfs_to_class_in_devices_map);
-
-static void
-free_hash_sys_to_class_in_dev (gpointer key, gpointer value, gpointer user_data)
-{
- GSList *i;
- GSList *list = (GSList *) value;
-
- for (i = list; i != NULL; i = g_slist_next (i))
- g_free (i->data);
- g_slist_free (list);
-}
-
-/** This function serves one major purpose : build an ordered list of
- * pairs (sysfs path, subsystem) to process when starting up:
- * coldplugging. The ordering is arranged such that all bus-devices
- * are visited in the same order as performing a traversal through
- * the tree; e.g. bus-device A is not processed before bus-device B
- * if B is a parent of A connection-wise.
- *
- * After all bus-devices are added to the list, then all block devices are
- * processed in the order they appear.
- *
- * Finally, all class devices are added to the list.
- *
- * @return Ordered list of sysfs paths or NULL
- * if there was an error
- */
-gboolean
-coldplug_synthesize_events (void)
+static int device_list_insert(const char *path, const char *subsystem,
+ HotplugEventType type)
{
- GDir *dir;
- GError *err = NULL;
- gchar path[HAL_PATH_MAX];
- gchar path1[HAL_PATH_MAX];
- gchar path2[HAL_PATH_MAX];
- const gchar *f;
- const gchar *f1;
- const gchar *f2;
- GSList *li;
-
- /** Mapping from sysfs path to subsystem for bus devices. This is consulted
- * when traversing /sys/devices
- *
- * Example:
- *
- * /sys/devices/pci0000:00/0000:00:07.2/usb1/1-1/1-1:1.0/host7/7:0:0:0 -> scsi
- * /sys/devices/pci0000:00/0000:00:07.1/ide1/1.1 -> ide
- * /sys/devices/pci0000:00/0000:00:07.1/ide1/1.0 -> ide
- * /sys/devices/pci0000:00/0000:00:07.1/ide0/0.0 -> ide
- * /sys/devices/pci0000:00/0000:00:07.2/usb1/1-1/1-1:1.0 -> usb
- * /sys/devices/pci0000:00/0000:00:07.2/usb1/1-1 -> usb
- * /sys/devices/pci0000:00/0000:00:07.2/usb1/1-0:1.0 -> usb
- * /sys/devices/pci0000:00/0000:00:07.2/usb1 -> usb
- * /sys/devices/pci0000:00/0000:00:04.1/0000:06:00.0 -> pci
- * /sys/devices/pci0000:00/0000:00:01.0/0000:01:00.0 -> pci
- * /sys/devices/pci0000:00/0000:00:08.0 -> pci
- * /sys/devices/platform/vesafb0 -> platform
- */
- GHashTable *sysfs_to_bus_map = NULL;
-
- /** Mapping from sysfs path in /sys/devices to the pairs (sysfs class path, classname)
- * for class devices; note that more than one class device might map to a physical device
- *
- * Example:
- *
- * /sys/devices/pci0000:00/0000:00:07.2/usb1/1-1/1-1:1.0/host7 -> (/sys/class/scsi_host/host7, scsi_host)
- * /sys/devices/platform/i8042/serio0/serio2 -> (/sys/class/input/event2, input, /sys/class/input/mouse1, input)
- */
- GHashTable *sysfs_to_class_in_devices_map = NULL;
-
- /* Class devices without device links; string list; example
- *
- * (/sys/class/input/mice, mouse, /sys/class/mem/null, mem, ...)
- */
- GSList *sysfs_other_class_dev = NULL;
-
- /* Device mapper devices that should be added after all other block devices
- *
- * Example:
- *
- * (/sys/block/dm-0)
- */
- GSList *sysfs_dm_dev = NULL;
+ char filename[HAL_PATH_MAX];
+ struct stat statbuf;
+ struct sysfs_device *sysfs_dev = NULL;
- if (hal_util_init_sysfs_to_udev_map () == FALSE) {
- HAL_ERROR (("Unable to get sysfs to dev map"));
+ /* we only have a device, if we have an uevent file */
+ g_strlcpy(filename, path, sizeof(filename));
+ g_strlcat(filename, "/uevent", sizeof(filename));
+ if (stat(filename, &statbuf) < 0)
goto error;
- }
-
- /* build bus map */
- sysfs_to_bus_map = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
- g_snprintf (path, HAL_PATH_MAX, "%s/bus", get_hal_sysfs_path ());
- if ((dir = g_dir_open (path, 0, &err)) == NULL) {
- HAL_ERROR (("Unable to open %/bus: %s", get_hal_sysfs_path (), err->message));
- g_error_free (err);
+ if (!(statbuf.st_mode & S_IWUSR))
goto error;
- }
- while ((f = g_dir_read_name (dir)) != NULL) {
- GDir *dir1;
- g_snprintf (path, HAL_PATH_MAX, "%s/bus/%s", get_hal_sysfs_path (), f);
- if ((dir1 = g_dir_open (path, 0, &err)) == NULL) {
- HAL_ERROR (("Unable to open %/bus/%s: %s", get_hal_sysfs_path (), f, err->message));
- g_error_free (err);
- goto error;
- }
- while ((f1 = g_dir_read_name (dir1)) != NULL) {
-
- if (strcmp (f1, "devices") == 0) {
- GDir *dir2;
+ sysfs_dev = g_new0 (struct sysfs_device, 1);
+ if (sysfs_dev == NULL)
+ goto error;
- g_snprintf (path, HAL_PATH_MAX, "%s/bus/%s/%s",
- get_hal_sysfs_path (), f, f1);
- if ((dir2 = g_dir_open (path, 0, &err)) == NULL) {
- HAL_ERROR (("Unable to open %s/bus/%s/%s: %s",
- get_hal_sysfs_path (), f, f1, err->message));
- g_error_free (err);
- goto error;
- }
- while ((f2 = g_dir_read_name (dir2)) != NULL) {
- gchar *target;
- gchar *normalized_target;
- g_snprintf (path, HAL_PATH_MAX, "%s/bus/%s/%s/%s",
- get_hal_sysfs_path (), f, f1, f2);
- if ((target = g_file_read_link (path, &err)) == NULL) {
- HAL_ERROR (("%s/bus/%s/%s/%s is not a symlink: %s!",
- get_hal_sysfs_path (),
- f, f1, f2, err->message));
- g_error_free (err);
- goto error;
- }
-
- g_snprintf (path, HAL_PATH_MAX, "%s/bus/%s/%s", get_hal_sysfs_path (), f, f1);
- normalized_target = hal_util_get_normalized_path (path, target);
- g_free (target);
+ /* resolve possible link to real target */
+ if (lstat(path, &statbuf) < 0)
+ goto error;
+ if (S_ISLNK(statbuf.st_mode)) {
+ gchar *target;
- g_hash_table_insert (sysfs_to_bus_map, normalized_target, g_strdup(f));
+ if ((target = g_file_read_link (path, NULL)) != NULL) {
+ gchar *normalized_target;
- }
- g_dir_close (dir2);
- }
+ g_strlcpy(filename, path, sizeof(filename));
+ hal_util_path_ascend (filename);
+ normalized_target = hal_util_get_normalized_path (filename, target);
+ g_free (target);
+ sysfs_dev->path = normalized_target;
+ goto found;
}
- g_dir_close (dir1);
- }
- g_dir_close (dir);
-
- /* build class map and class device map (values are free in separate foreach()) */
- sysfs_to_class_in_devices_map = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
- g_snprintf (path, HAL_PATH_MAX, "%s/class" , get_hal_sysfs_path ());
- if ((dir = g_dir_open (path, 0, &err)) == NULL) {
- HAL_ERROR (("Unable to open %/class: %s", get_hal_sysfs_path (), err->message));
goto error;
}
- while ((f = g_dir_read_name (dir)) != NULL) {
- GDir *dir1;
- g_snprintf (path, HAL_PATH_MAX, "%s/class/%s" , get_hal_sysfs_path (), f);
- if ((dir1 = g_dir_open (path, 0, &err)) == NULL) {
- HAL_ERROR (("Unable to open %s/class/%s: %s", get_hal_sysfs_path (), f, err->message));
- g_error_free (err);
- goto error;
- }
- while ((f1 = g_dir_read_name (dir1)) != NULL) {
- gchar *target;
- gchar *normalized_target;
+ sysfs_dev->path = g_strdup (path);
+found:
+ sysfs_dev->subsystem = g_strdup (subsystem);
+ device_list = g_slist_prepend (device_list, sysfs_dev);
+ return 0;
- g_snprintf (path2, HAL_PATH_MAX, "%s/class/%s/%s", get_hal_sysfs_path (), f, f1);
+error:
+ g_free (sysfs_dev);
+ return -1;
+}
- /* check if we find a symlink here pointing to a device _inside_ a class device,
- * like "input" in 2.6.15. This kernel sysfs layout will change again in the future,
- * for now resolve the link to the "real" device path, like real hotplug events
- * devpath would have
- */
- if ((target = g_file_read_link (path2, NULL)) != NULL) {
- char *pos = strrchr(path2, '/');
-
- if (pos)
- pos[0] = '\0';
- normalized_target = hal_util_get_normalized_path (path2, target);
- g_free (target);
- g_strlcpy(path2, normalized_target, sizeof(path2));
- g_free (normalized_target);
- }
-
- /* Accept net devices without device links too, they may be coldplugged PCMCIA devices */
- g_snprintf (path1, HAL_PATH_MAX, "%s/device", path2);
- if (((target = g_file_read_link (path1, NULL)) == NULL)) {
- /* no device link */
- sysfs_other_class_dev = g_slist_append (sysfs_other_class_dev, g_strdup (path2));
- sysfs_other_class_dev = g_slist_append (sysfs_other_class_dev, g_strdup (f));
- } else {
- GSList *classdev_strings;
-
- normalized_target = hal_util_get_normalized_path (path2, target);
- g_free (target);
-
- classdev_strings = g_hash_table_lookup (sysfs_to_class_in_devices_map,
- normalized_target);
-
- classdev_strings = g_slist_append (classdev_strings, g_strdup (path2));
- classdev_strings = g_slist_append (classdev_strings, g_strdup (f));
- g_hash_table_replace (sysfs_to_class_in_devices_map,
- normalized_target, classdev_strings);
- }
+static void scan_bus(void)
+{
+ char base[HAL_PATH_MAX];
+ DIR *dir;
+ struct dirent *dent;
+
+ g_strlcpy(base, get_hal_sysfs_path (), sizeof(base));
+ g_strlcat(base, "/bus", sizeof(base));
+
+ dir = opendir(base);
+ if (dir != NULL) {
+ for (dent = readdir(dir); dent != NULL; dent = readdir(dir)) {
+ char dirname[HAL_PATH_MAX];
+ DIR *dir2;
+ struct dirent *dent2;
+
+ if (dent->d_name[0] == '.')
+ continue;
+
+ g_strlcpy(dirname, base, sizeof(dirname));
+ g_strlcat(dirname, "/", sizeof(dirname));
+ g_strlcat(dirname, dent->d_name, sizeof(dirname));
+ g_strlcat(dirname, "/devices", sizeof(dirname));
+
+ /* look for devices */
+ dir2 = opendir(dirname);
+ if (dir2 != NULL) {
+ for (dent2 = readdir(dir2); dent2 != NULL; dent2 = readdir(dir2)) {
+ char dirname2[HAL_PATH_MAX];
+
+ if (dent2->d_name[0] == '.')
+ continue;
+
+ g_strlcpy(dirname2, dirname, sizeof(dirname2));
+ g_strlcat(dirname2, "/", sizeof(dirname2));
+ g_strlcat(dirname2, dent2->d_name, sizeof(dirname2));
+ device_list_insert(dirname2, dent->d_name, HOTPLUG_EVENT_SYSFS_BUS);
+ }
+ closedir(dir2);
+ }
}
- g_dir_close (dir1);
+ closedir(dir);
}
- g_dir_close (dir);
+}
- /* Now traverse /sys/devices and consult the map we've just
- * built; this includes adding a) bus devices; and b) class
- * devices that sit in /sys/devices */
- g_snprintf (path, HAL_PATH_MAX, "%s/devices", get_hal_sysfs_path ());
- if ((dir = g_dir_open (path, 0, &err)) == NULL) {
- HAL_ERROR (("Unable to open %/devices: %s", get_hal_sysfs_path (), err->message));
- g_error_free (err);
- goto error;
- }
- while ((f = g_dir_read_name (dir)) != NULL) {
- GDir *dir1;
+static void scan_block(void)
+{
+ char base[HAL_PATH_MAX];
+ DIR *dir;
+ struct dirent *dent;
+ struct stat statbuf;
- g_snprintf (path, HAL_PATH_MAX, "%s/devices/%s", get_hal_sysfs_path (), f);
- if ((dir1 = g_dir_open (path, 0, &err)) == NULL) {
- HAL_ERROR (("Unable to open %/devices/%s: %s", get_hal_sysfs_path (), f, err->message));
- g_error_free (err);
- goto error;
+ /* skip if "block" is already a "class" */
+ g_strlcpy(base, get_hal_sysfs_path (), sizeof(base));
+ g_strlcat(base, "/class/block", sizeof(base));
+ if (stat(base, &statbuf) == 0)
+ return;
+
+ g_strlcpy(base, get_hal_sysfs_path (), sizeof(base));
+ g_strlcat(base, "/block", sizeof(base));
+
+ dir = opendir(base);
+ if (dir != NULL) {
+ for (dent = readdir(dir); dent != NULL; dent = readdir(dir)) {
+ char dirname[HAL_PATH_MAX];
+ DIR *dir2;
+ struct dirent *dent2;
+
+ if (dent->d_name[0] == '.')
+ continue;
+
+ g_strlcpy(dirname, base, sizeof(dirname));
+ g_strlcat(dirname, "/", sizeof(dirname));
+ g_strlcat(dirname, dent->d_name, sizeof(dirname));
+ if (device_list_insert(dirname, "block", HOTPLUG_EVENT_SYSFS_BLOCK) != 0)
+ continue;
+
+ /* look for partitions */
+ dir2 = opendir(dirname);
+ if (dir2 != NULL) {
+ for (dent2 = readdir(dir2); dent2 != NULL; dent2 = readdir(dir2)) {
+ char dirname2[HAL_PATH_MAX];
+
+ if (dent2->d_name[0] == '.')
+ continue;
+
+ if (!strcmp(dent2->d_name,"device"))
+ continue;
+ g_strlcpy(dirname2, dirname, sizeof(dirname2));
+ g_strlcat(dirname2, "/", sizeof(dirname2));
+ g_strlcat(dirname2, dent2->d_name, sizeof(dirname2));
+ device_list_insert(dirname2, "block", HOTPLUG_EVENT_SYSFS_BLOCK);
+ }
+ closedir(dir2);
+ }
}
- while ((f1 = g_dir_read_name (dir1)) != NULL) {
+ closedir(dir);
+ }
+}
- g_snprintf (path, HAL_PATH_MAX, "%s/devices/%s/%s", get_hal_sysfs_path (), f, f1);
- coldplug_compute_visit_device (path, sysfs_to_bus_map, sysfs_to_class_in_devices_map);
+static void scan_class(void)
+{
+ char base[HAL_PATH_MAX];
+ DIR *dir;
+ struct dirent *dent;
+
+ g_strlcpy(base, get_hal_sysfs_path (), sizeof(base));
+ g_strlcat(base, "/class", sizeof(base));
+
+ dir = opendir(base);
+ if (dir != NULL) {
+ for (dent = readdir(dir); dent != NULL; dent = readdir(dir)) {
+ char dirname[HAL_PATH_MAX];
+ DIR *dir2;
+ struct dirent *dent2;
+
+ if (dent->d_name[0] == '.')
+ continue;
+
+ g_strlcpy(dirname, base, sizeof(dirname));
+ g_strlcat(dirname, "/", sizeof(dirname));
+ g_strlcat(dirname, dent->d_name, sizeof(dirname));
+ dir2 = opendir(dirname);
+ if (dir2 != NULL) {
+ for (dent2 = readdir(dir2); dent2 != NULL; dent2 = readdir(dir2)) {
+ char dirname2[HAL_PATH_MAX];
+
+ if (dent2->d_name[0] == '.')
+ continue;
+ if (!strcmp(dent2->d_name, "device"))
+ continue;
+
+ g_strlcpy(dirname2, dirname, sizeof(dirname2));
+ g_strlcat(dirname2, "/", sizeof(dirname2));
+ g_strlcat(dirname2, dent2->d_name, sizeof(dirname2));
+ device_list_insert(dirname2, dent->d_name, HOTPLUG_EVENT_SYSFS_CLASS);
+ }
+ closedir(dir2);
+ }
}
- g_dir_close (dir1);
+ closedir(dir);
}
- g_dir_close (dir);
+}
- g_hash_table_destroy (sysfs_to_bus_map);
- /* free keys and values in this complex hash */
- g_hash_table_foreach (sysfs_to_class_in_devices_map, free_hash_sys_to_class_in_dev, NULL);
- g_hash_table_destroy (sysfs_to_class_in_devices_map);
-
- /* we are guaranteed, per construction, that the len of this list is even */
- for (li = sysfs_other_class_dev; li != NULL; li = g_slist_next (g_slist_next (li))) {
- gchar *sysfs_path;
- gchar *subsystem;
- HotplugEvent *hotplug_event;
+static void queue_events(void)
+{
+ GSList *dev;
- sysfs_path = (gchar *) li->data;
- subsystem = (gchar *) li->next->data;
+ /* queue events for the devices */
+ for (dev = device_list; dev != NULL; dev = g_slist_next (dev)) {
+ HotplugEvent *hotplug_event;
+ struct sysfs_device *sysfs_dev = dev->data;
-#ifdef HAL_COLDPLUG_VERBOSE
- printf ("class: %s (%s) (no device link)\n", sysfs_path, subsystem);
-#endif
- hotplug_event = coldplug_get_hotplug_event (sysfs_path, subsystem);
+ hotplug_event = coldplug_get_hotplug_event (sysfs_dev->path,
+ sysfs_dev->subsystem,
+ sysfs_dev->type);
hotplug_event_enqueue (hotplug_event);
- g_free (li->data);
- g_free (li->next->data);
+ g_free (sysfs_dev->path);
+ g_free (sysfs_dev->subsystem);
}
- g_slist_free (sysfs_other_class_dev);
- /* add block devices */
- g_snprintf (path, HAL_PATH_MAX, "%s/block", get_hal_sysfs_path ());
- if ((dir = g_dir_open (path, 0, &err)) == NULL) {
- HAL_ERROR (("Unable to open %s: %s", path, err->message));
- g_error_free (err);
- goto error;
- }
- while ((f = g_dir_read_name (dir)) != NULL) {
- if (g_str_has_prefix (f, DMPREFIX)) {
- /* defer dm devices */
- sysfs_dm_dev = g_slist_append(sysfs_dm_dev, g_strdup(f));
- continue;
- }
- if (coldplug_synthesize_block_event(f) == FALSE)
- goto error;
- }
- /* process all dm devices last so that their backing devices exist */
- for (li = sysfs_dm_dev; li != NULL; li = g_slist_next (g_slist_next (li))) {
- if (coldplug_synthesize_block_event (li->data) == FALSE)
- goto error;
- g_free (li->data);
- }
- g_slist_free (sysfs_dm_dev);
- g_dir_close (dir);
-
- g_hash_table_destroy (sysfs_to_udev_map);
-
- return TRUE;
-error:
- HAL_ERROR (("Error building the ordered list of sysfs paths"));
- return FALSE;
+ g_slist_free (device_list);
+ device_list = NULL;
}
-static gboolean
-coldplug_synthesize_block_event(const gchar *f)
+static int _device_order (const void *d1, const void *d2)
{
- GDir *dir1;
- HotplugEvent *hotplug_event;
- GError *err = NULL;
- gchar path[HAL_PATH_MAX];
- gchar path1[HAL_PATH_MAX];
- const gchar *f1;
+ const struct sysfs_device *dev1 = d1;
+ const struct sysfs_device *dev2 = d2;
- g_snprintf (path, HAL_PATH_MAX, "%s/block/%s", get_hal_sysfs_path (), f);
-#ifdef HAL_COLDPLUG_VERBOSE
- printf ("block: %s (block)\n", path);
-#endif
- hotplug_event = coldplug_get_hotplug_event (path, "block");
- hotplug_event_enqueue (hotplug_event);
+ /* device mapper needs to be the last events, to have the other block devs already around */
+ if (strstr(dev2->path, "/" DMPREFIX))
+ return -1;
+ if (strstr(dev1->path, "/" DMPREFIX))
+ return 1;
- if ((dir1 = g_dir_open (path, 0, &err)) == NULL) {
- HAL_ERROR (("Unable to open %s: %s", path, err->message));
- g_error_free (err);
- goto error;
- }
- while ((f1 = g_dir_read_name (dir1)) != NULL) {
- if (strncmp (f, f1, strlen (f)) == 0) {
- g_snprintf (path1, HAL_PATH_MAX, "%s/%s", path, f1);
-#ifdef HAL_COLDPLUG_VERBOSE
- printf ("block: %s (block)\n", path1);
-#endif
- hotplug_event = coldplug_get_hotplug_event (path1, "block");
- hotplug_event_enqueue (hotplug_event);
- }
- }
- g_dir_close (dir1);
-
- return TRUE;
-error:
- return FALSE;
+ return strcmp(dev1->path, dev2->path);
}
-static void
-coldplug_compute_visit_device (const gchar *path,
- GHashTable *sysfs_to_bus_map,
- GHashTable *sysfs_to_class_in_devices_map)
+gboolean
+coldplug_synthesize_events (void)
{
- gchar *bus;
- GError *err = NULL;
- GDir *dir;
- const gchar *f;
- /*HStringPair *pair;*/
- GSList *class_devs;
- GSList *i;
-
- bus = g_hash_table_lookup (sysfs_to_bus_map, path);
- if (bus != NULL) {
- HotplugEvent *hotplug_event;
-#ifdef HAL_COLDPLUG_VERBOSE
- printf ("bus: %s (%s)\n", path, bus);
-#endif
- hotplug_event = coldplug_get_hotplug_event (path, bus);
- hotplug_event_enqueue (hotplug_event);
+ if (hal_util_init_sysfs_to_udev_map () == FALSE) {
+ HAL_ERROR (("Unable to get sysfs to dev map"));
+ goto error;
}
- /* we are guaranteed, per construction, that the len of this list is even */
- class_devs = g_hash_table_lookup (sysfs_to_class_in_devices_map, path);
- for (i = class_devs; i != NULL; i = g_slist_next (g_slist_next (i))) {
- gchar *sysfs_path;
- gchar *subsystem;
- HotplugEvent *hotplug_event;
+ scan_bus ();
+ device_list = g_slist_sort (device_list, _device_order);
+ queue_events ();
+
+ scan_class ();
+ device_list = g_slist_sort (device_list, _device_order);
+ queue_events ();
+
+ scan_block ();
+ device_list = g_slist_sort (device_list, _device_order);
+ queue_events ();
- sysfs_path = (gchar *) i->data;
- subsystem = (gchar *) i->next->data;
-#ifdef HAL_COLDPLUG_VERBOSE
- printf ("class: %s (%s) (%s)\n", path, subsystem, sysfs_path);
-#endif
- hotplug_event = coldplug_get_hotplug_event (sysfs_path, subsystem);
- hotplug_event_enqueue (hotplug_event);
- }
-
- /* visit children; dont follow symlinks though.. */
- err = NULL;
- if ((dir = g_dir_open (path, 0, &err)) == NULL) {
- /*HAL_ERROR (("Unable to open directory: %s", path, err->message));*/
- g_error_free (err);
- goto error;
- }
- while ((f = g_dir_read_name (dir)) != NULL) {
- gchar path_child[HAL_PATH_MAX];
- struct stat statbuf;
-
- g_snprintf (path_child, HAL_PATH_MAX, "%s/%s", path, f);
- if (lstat (path_child, &statbuf) == 0) {
- if (!S_ISLNK (statbuf.st_mode)) {
- /* recursion fun */
- coldplug_compute_visit_device (path_child,
- sysfs_to_bus_map,
- sysfs_to_class_in_devices_map);
- }
- }
- }
- g_dir_close (dir);
+ g_hash_table_destroy (sysfs_to_udev_map);
+ return TRUE;
error:
- return;
+ return FALSE;
}
-
diff --git a/hald/linux/hotplug.c b/hald/linux/hotplug.c
index 4eac8b9..5187c97 100644
--- a/hald/linux/hotplug.c
+++ b/hald/linux/hotplug.c
@@ -138,8 +138,13 @@ hotplug_event_begin_sysfs (HotplugEvent
return;
}
+ /* subsystem "block" are all block devices */
+ if (hotplug_event->type == HOTPLUG_EVENT_SYSFS)
+ if (strcmp(hotplug_event->sysfs.subsystem, "block") == 0)
+ hotplug_event->type = HOTPLUG_EVENT_SYSFS_BLOCK;
+
/* get device type from already known device object */
- if (d != NULL) {
+ if (hotplug_event->type == HOTPLUG_EVENT_SYSFS && d != NULL) {
HotplugEventType type;
type = hal_device_property_get_int (d, "linux.hotplug_type");
@@ -164,15 +169,15 @@ hotplug_event_begin_sysfs (HotplugEvent
g_snprintf (subsystem, HAL_PATH_MAX, "%s/subsystem", hotplug_event->sysfs.sysfs_path);
subsystem_target = g_file_read_link (subsystem, NULL);
if (subsystem_target != NULL) {
- if (strstr(subsystem_target, "/bus/") != NULL) {
+ if (strstr(subsystem_target, "/block") != NULL) {
+ HAL_INFO (("%s is a block device (subsystem)", hotplug_event->sysfs.sysfs_path));
+ hotplug_event->type = HOTPLUG_EVENT_SYSFS_BLOCK;
+ } else if (strstr(subsystem_target, "/bus/") != NULL) {
HAL_INFO (("%s is a bus device (subsystem)", hotplug_event->sysfs.sysfs_path));
hotplug_event->type = HOTPLUG_EVENT_SYSFS_BUS;
} else if (strstr(subsystem_target, "/class/") != NULL) {
HAL_INFO (("%s is a class device (subsystem)", hotplug_event->sysfs.sysfs_path));
hotplug_event->type = HOTPLUG_EVENT_SYSFS_CLASS;
- } else if (strstr(subsystem_target, "/block") != NULL) {
- HAL_INFO (("%s is a block device (subsystem)", hotplug_event->sysfs.sysfs_path));
- hotplug_event->type = HOTPLUG_EVENT_SYSFS_BLOCK;
}
g_free (subsystem_target);
}
@@ -206,7 +211,8 @@ hotplug_event_begin_sysfs (HotplugEvent
if (hotplug_event->type == HOTPLUG_EVENT_SYSFS_BUS) {
if (hotplug_event->action == HOTPLUG_ACTION_ADD) {
HalDevice *parent;
- parent = hal_util_find_closest_ancestor (hotplug_event->sysfs.sysfs_path);
+
+ hal_util_find_known_parent (hotplug_event->sysfs.sysfs_path, &parent, NULL);
hotplug_event_begin_add_physdev (hotplug_event->sysfs.subsystem,
hotplug_event->sysfs.sysfs_path,
parent,
@@ -218,53 +224,23 @@ hotplug_event_begin_sysfs (HotplugEvent
}
} else if (hotplug_event->type == HOTPLUG_EVENT_SYSFS_CLASS) {
if (hotplug_event->action == HOTPLUG_ACTION_ADD) {
- gchar *target;
- HalDevice *physdev;
- char physdevpath[HAL_PATH_MAX];
- gchar *sysfs_path_in_devices;
-
- sysfs_path_in_devices = NULL;
+ HalDevice *parent;
+ gchar *parent_path;
/* /sbin/ifrename may be called from a hotplug handler before we process this,
* so if index doesn't match, go ahead and find a new sysfs path
*/
fixup_net_device_for_renaming (hotplug_event);
- g_snprintf (physdevpath, HAL_PATH_MAX, "%s/device", hotplug_event->sysfs.sysfs_path);
- if (((target = g_file_read_link (physdevpath, NULL)) != NULL)) {
- gchar *normalized_target;
-
- normalized_target = hal_util_get_normalized_path (hotplug_event->sysfs.sysfs_path, target);
- g_free (target);
-
- sysfs_path_in_devices = g_strdup (normalized_target);
-
- /* there may be ''holes'' in /sys/devices so try hard to find the closest match */
- do {
- physdev = hal_device_store_match_key_value_string (hald_get_gdl (),
- "linux.sysfs_path_device",
- normalized_target);
- if (physdev != NULL)
- break;
-
- /* go up one directory */
- if (!hal_util_path_ascend (normalized_target))
- break;
- } while (physdev == NULL);
- g_free (normalized_target);
- } else {
- physdev = NULL;
- }
-
+ hal_util_find_known_parent (hotplug_event->sysfs.sysfs_path,
+ &parent, &parent_path);
hotplug_event_begin_add_classdev (hotplug_event->sysfs.subsystem,
hotplug_event->sysfs.sysfs_path,
hotplug_event->sysfs.device_file,
- physdev,
- sysfs_path_in_devices,
+ parent,
+ parent_path,
(void *) hotplug_event);
-
- g_free (sysfs_path_in_devices);
-
+ g_free (parent_path);
} else if (hotplug_event->action == HOTPLUG_ACTION_REMOVE) {
hotplug_event_begin_remove_classdev (hotplug_event->sysfs.subsystem,
hotplug_event->sysfs.sysfs_path,
@@ -272,11 +248,10 @@ hotplug_event_begin_sysfs (HotplugEvent
}
} else if (hotplug_event->type == HOTPLUG_EVENT_SYSFS_BLOCK) {
if (hotplug_event->action == HOTPLUG_ACTION_ADD) {
- HalDevice *parent = NULL;
+ HalDevice *parent;
int range;
gboolean is_partition;
- gboolean is_fakevolume;
-
+
/* it's a partition if and only if it doesn't have the range file...
*
* notably the device mapper partitions do have a range file, but that's
@@ -285,42 +260,13 @@ hotplug_event_begin_sysfs (HotplugEvent
* also, if the sysfs ends with "fakevolume" the hotplug event is synthesized
* from within HAL for partitions on the main block device
*/
- is_fakevolume = FALSE;
- if (strcmp (hal_util_get_last_element (hotplug_event->sysfs.sysfs_path), "fakevolume") == 0) {
- is_fakevolume = TRUE;
- }
- is_partition = TRUE;
- if (is_fakevolume ||
- hal_util_get_int_from_file (hotplug_event->sysfs.sysfs_path, "range", &range, 0)) {
+ if ((strstr (hotplug_event->sysfs.sysfs_path, "/fakevolume") != NULL) ||
+ hal_util_get_int_from_file (hotplug_event->sysfs.sysfs_path, "range", &range, 0))
is_partition = FALSE;
- }
-
- if (is_partition || is_fakevolume) {
- gchar *parent_path;
-
- parent_path = hal_util_get_parent_path (hotplug_event->sysfs.sysfs_path);
-
- parent = hal_device_store_match_key_value_string (hald_get_gdl (),
- "linux.sysfs_path_device",
- parent_path);
- g_free (parent_path);
- } else {
- gchar *target;
- char physdevpath[HAL_PATH_MAX];
-
- g_snprintf (physdevpath, HAL_PATH_MAX, "%s/device", hotplug_event->sysfs.sysfs_path);
- if (((target = g_file_read_link (physdevpath, NULL)) != NULL)) {
- gchar *normalized_target;
-
- normalized_target = hal_util_get_normalized_path (hotplug_event->sysfs.sysfs_path, target);
- g_free (target);
- parent = hal_device_store_match_key_value_string (hald_get_gdl (),
- "linux.sysfs_path_device",
- normalized_target);
- g_free (normalized_target);
- }
- }
+ else
+ is_partition = TRUE;
+ hal_util_find_known_parent (hotplug_event->sysfs.sysfs_path, &parent, NULL);
hotplug_event_begin_add_blockdev (hotplug_event->sysfs.sysfs_path,
hotplug_event->sysfs.device_file,
is_partition,
diff --git a/hald/linux/osspec.c b/hald/linux/osspec.c
index ed762a8..eb5d6b0 100644
--- a/hald/linux/osspec.c
+++ b/hald/linux/osspec.c
@@ -606,40 +606,79 @@ hal_util_set_driver (HalDevice *d, const
return ret;
}
-/** Find the closest ancestor by looking at sysfs paths
- *
- * @param sysfs_path Path into sysfs, e.g. /sys/devices/pci0000:00/0000:00:1d.7/usb1/1-0:1.0
- * @return Parent Hal Device Object or #NULL if there is none
- */
-HalDevice *
-hal_util_find_closest_ancestor (const gchar *sysfs_path)
-{
- gchar buf[512];
- HalDevice *parent;
-
- parent = NULL;
-
- strncpy (buf, sysfs_path, sizeof (buf));
- do {
- char *p;
-
- p = strrchr (buf, '/');
- if (p == NULL)
- break;
- *p = '\0';
-
- parent = hal_device_store_match_key_value_string (hald_get_gdl (),
- "linux.sysfs_path_device",
- buf);
- if (parent != NULL)
+static gboolean get_parent_device(char *path)
+{
+ /* go up one directory */
+ if (!hal_util_path_ascend (path))
+ return FALSE;
+ if (g_str_has_suffix (path, "/class"))
+ return FALSE;
+ if (g_str_has_suffix (path, "/block"))
+ return FALSE;
+ if (g_str_has_suffix (path, "/devices"))
+ return FALSE;
+ return TRUE;
+}
+/* return the first already known parent device */
+gboolean
+hal_util_find_known_parent (const gchar *sysfs_path, HalDevice **parent, gchar **parent_path)
+{
+ gchar *target;
+ HalDevice *parent_dev = NULL;
+ gchar *parent_devpath;
+ char parentdevpath[HAL_PATH_MAX];
+ gboolean retval = FALSE;
+
+ parent_devpath = g_strdup (sysfs_path);
+ while (TRUE) {
+ if (!get_parent_device (parent_devpath))
break;
- } while (TRUE);
-
- return parent;
+ parent_dev = hal_device_store_match_key_value_string (hald_get_gdl (),
+ "linux.sysfs_path_device",
+ parent_devpath);
+ if (parent_dev != NULL)
+ goto out;
+ }
+ g_free (parent_devpath);
+ parent_devpath = NULL;
+
+ /* try if the parent chain is constructed by the device-link */
+ g_snprintf (parentdevpath, HAL_PATH_MAX, "%s/device", sysfs_path);
+ if (((target = g_file_read_link (parentdevpath, NULL)) != NULL)) {
+ parent_devpath = hal_util_get_normalized_path (sysfs_path, target);
+ g_free (target);
+
+ while (TRUE) {
+ parent_dev = hal_device_store_match_key_value_string (hald_get_gdl (),
+ "linux.sysfs_path_device",
+ parent_devpath);
+ if (parent_dev != NULL)
+ goto out;
+
+ /* go up one directory */
+ if (!get_parent_device (parent_devpath))
+ break;
+ }
+ g_free (parent_devpath);
+ parent_devpath = NULL;
+ }
+
+out:
+ if (parent_dev != NULL) {
+ HAL_INFO (("hal_util_find_known_parent: '%s'->'%s'", sysfs_path, parent_devpath));
+ retval = TRUE;
+ }
+ if (parent != NULL)
+ *parent = parent_dev;
+ if (parent_path != NULL)
+ *parent_path = parent_devpath;
+ else
+ g_free (parent_devpath);
+ return retval;
}
-void
+void
osspec_refresh_mount_state_for_block_device (HalDevice *d)
{
blockdev_refresh_mount_state (d);
diff --git a/hald/linux/osspec_linux.h b/hald/linux/osspec_linux.h
index 88d516c..8ecda30 100644
--- a/hald/linux/osspec_linux.h
+++ b/hald/linux/osspec_linux.h
@@ -37,7 +37,7 @@ gboolean hal_util_get_driver_name (const
gboolean hal_util_set_driver (HalDevice *d, const char *property_name, const char *sysfs_path);
-HalDevice *hal_util_find_closest_ancestor (const gchar *sysfs_path);
+gboolean hal_util_find_known_parent (const gchar *sysfs_path, HalDevice **parent, gchar **parent_path);
#endif /* OSSPEC_LINUX_H */
More information about the hal-commit
mailing list