chiark / gitweb /
update RELEASE-NOTES
[elogind.git] / udev_rules.c
index 48397ac1c7bf3b9a6a74069b46ebff8683629f35..41855eb9d7d0a63b50e24ae9ad42c2f8d09f7fd7 100644 (file)
@@ -31,6 +31,7 @@
 #include <unistd.h>
 #include <errno.h>
 #include <sys/wait.h>
+#include <sys/stat.h>
 
 #include "libsysfs/sysfs/libsysfs.h"
 #include "list.h"
@@ -335,6 +336,28 @@ attr_found:
        return 0;
 }
 
+#define WAIT_LOOP_PER_SECOND                   20
+static int wait_for_sysfs(struct udevice *udev, const char *file, int timeout)
+{
+       char filename[PATH_SIZE];
+       struct stat stats;
+       int loop = timeout * WAIT_LOOP_PER_SECOND;
+
+       snprintf(filename, sizeof(filename), "%s%s/%s", sysfs_path, udev->devpath, file);
+       filename[sizeof(filename)-1] = '\0';
+       dbg("wait %i sec for '%s'", timeout, filename);
+
+       while (--loop) {
+               if (stat(filename, &stats) == 0) {
+                       dbg("file appeared after %i loops", (timeout * WAIT_LOOP_PER_SECOND) - loop-1);
+                       return 0;
+               }
+               usleep(1000 * 1000 / WAIT_LOOP_PER_SECOND);
+       }
+       dbg("waiting for '%s' failed", filename);
+       return -1;
+}
+
 static void apply_format(struct udevice *udev, char *string, size_t maxsize,
                         struct sysfs_class_device *class_dev, struct sysfs_device *sysfs_device)
 {
@@ -622,15 +645,15 @@ static int match_key(const char *key_name, struct udev_rule *rule, struct key *k
        dbg("check for %s '%s' <-> '%s'", key_name, key_value, val);
        match = (strcmp_pattern(key_value, val) == 0);
        if (match && (key->operation != KEY_OP_NOMATCH)) {
-               dbg("%s key is matching (matching value)", key_name);
+               dbg("%s is matching (matching value)", key_name);
                return 0;
        }
        if (!match && (key->operation == KEY_OP_NOMATCH)) {
-               dbg("%s key is matching, (non matching value)", key_name);
+               dbg("%s is matching, (non matching value)", key_name);
                return 0;
        }
 
-       dbg("%s key is not matching", key_name);
+       dbg("%s is not matching", key_name);
        return -1;
 }
 
@@ -681,6 +704,22 @@ static int match_rule(struct udevice *udev, struct udev_rule *rule,
                dbg("all %i ENV keys matched", rule->env.count);
        }
 
+       if (rule->wait_for_sysfs.operation != KEY_OP_UNSET) {
+               int match;
+
+               match = (wait_for_sysfs(udev, key_val(rule, &rule->wait_for_sysfs), 3) == 0);
+               if (match && (rule->wait_for_sysfs.operation != KEY_OP_NOMATCH)) {
+                       dbg("WAIT_FOR_SYSFS is matching (matching value)");
+                       return 0;
+               }
+               if (!match && (rule->wait_for_sysfs.operation == KEY_OP_NOMATCH)) {
+                       dbg("WAIT_FOR_SYSFS is matching, (non matching value)");
+                       return 0;
+               }
+               dbg("WAIT_FOR_SYSFS is not matching");
+               return -1;
+       }
+
        /* walk up the chain of physical devices and find a match */
        while (1) {
                /* check for matching driver */
@@ -819,6 +858,7 @@ int udev_rules_get_name(struct udev_rules *rules, struct udevice *udev, struct s
        struct sysfs_class_device *class_dev_parent;
        struct sysfs_device *sysfs_device = NULL;
        struct udev_rule *rule;
+       int name_set = 0;
 
        dbg("class_dev->name='%s'", class_dev->name);
 
@@ -850,7 +890,7 @@ int udev_rules_get_name(struct udev_rules *rules, struct udevice *udev, struct s
                if (rule == NULL)
                        break;
 
-               if (udev->name_set && rule->name.operation != KEY_OP_UNSET) {
+               if (name_set && rule->name.operation != KEY_OP_UNSET) {
                        dbg("node name already set, rule ignored");
                        continue;
                }
@@ -932,7 +972,7 @@ int udev_rules_get_name(struct udev_rules *rules, struct udevice *udev, struct s
 
                        /* set name, later rules with name set will be ignored */
                        if (rule->name.operation != KEY_OP_UNSET) {
-                               udev->name_set = 1;
+                               name_set = 1;
                                strlcpy(udev->name, key_val(rule, &rule->name), sizeof(udev->name));
                                apply_format(udev, udev->name, sizeof(udev->name), class_dev, sysfs_device);
 
@@ -970,7 +1010,7 @@ int udev_rules_get_name(struct udev_rules *rules, struct udevice *udev, struct s
                }
        }
 
-       if (udev->name[0] == '\0') {
+       if (!name_set) {
                strlcpy(udev->name, udev->kernel_name, sizeof(udev->name));
                info("no rule found, will use kernel name '%s'", udev->name);
        }