summaryrefslogtreecommitdiff
path: root/libudev/libudev-enumerate.c
diff options
context:
space:
mode:
authorLennart Poettering <lennart@poettering.net>2009-07-27 23:24:27 +0200
committerLennart Poettering <lennart@poettering.net>2009-07-28 03:10:05 +0200
commit3bf768245b98479a14190e1e1d32ef5fae3ddf8a (patch)
tree5cf0f2dea81d8174888451cc7c7251f7e724b465 /libudev/libudev-enumerate.c
parent2a827c959a77eb6df9539235c46c96b78a824cf9 (diff)
enumeration: move ALSA control devices to the end of the enumerated devices of each card
Generally ALSA control devices should be the last ones to be processed for ACL changes and similar operations because they can then be used as indicators that ACL management finished for all device nodes of a specific card. This patch simple moves each controlC device behind all the pcmC devices (and similar).
Diffstat (limited to 'libudev/libudev-enumerate.c')
-rw-r--r--libudev/libudev-enumerate.c59
1 files changed, 56 insertions, 3 deletions
diff --git a/libudev/libudev-enumerate.c b/libudev/libudev-enumerate.c
index 96cf060907..986c1fc3d5 100644
--- a/libudev/libudev-enumerate.c
+++ b/libudev/libudev-enumerate.c
@@ -190,7 +190,8 @@ static int syspath_cmp(const void *p1, const void *p2)
return ret;
}
-static int devices_delay(struct udev *udev, const char *syspath)
+/* For devices that should be moved to the absolute end of the list */
+static int devices_delay_end(struct udev *udev, const char *syspath)
{
static const char *delay_device_list[] = {
"/block/md",
@@ -210,6 +211,32 @@ static int devices_delay(struct udev *udev, const char *syspath)
return 0;
}
+/* 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 (strncmp(c, "/controlC", 9) == 0)
+ return c - syspath + 1;
+ }
+
+ return 0;
+}
+
/**
* udev_enumerate_get_list_entry:
* @udev_enumerate: context
@@ -223,7 +250,8 @@ struct udev_list_entry *udev_enumerate_get_list_entry(struct udev_enumerate *ude
if (!udev_enumerate->devices_uptodate) {
unsigned int i;
unsigned int max;
- struct syspath *prev = NULL;
+ struct syspath *prev = NULL, *move_later = NULL;
+ size_t move_later_prefix;
udev_list_cleanup_entries(udev_enumerate->udev, &udev_enumerate->devices_list);
qsort(udev_enumerate->devices, udev_enumerate->devices_cur, sizeof(struct syspath), syspath_cmp);
@@ -240,14 +268,39 @@ struct udev_list_entry *udev_enumerate_get_list_entry(struct udev_enumerate *ude
prev = entry;
/* skip to be delayed devices, and add them to the end of the list */
- if (devices_delay(udev_enumerate->udev, entry->syspath)) {
+ if (devices_delay_end(udev_enumerate->udev, entry->syspath)) {
syspath_add(udev_enumerate, entry->syspath);
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) {
+ move_later_prefix = devices_delay_later(udev_enumerate->udev, entry->syspath);
+
+ if (move_later_prefix > 0) {
+ move_later = entry;
+ continue;
+ }
+ }
+
+ if (move_later &&
+ strncmp(entry->syspath, move_later->syspath, move_later_prefix) != 0) {
+
+ udev_list_entry_add(udev_enumerate->udev, &udev_enumerate->devices_list,
+ move_later->syspath, NULL, 0, 0);
+ move_later = NULL;
+ }
+
udev_list_entry_add(udev_enumerate->udev, &udev_enumerate->devices_list,
entry->syspath, NULL, 0, 0);
}
+
+ if (move_later)
+ udev_list_entry_add(udev_enumerate->udev, &udev_enumerate->devices_list,
+ move_later->syspath, NULL, 0, 0);
+
/* 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];