chiark / gitweb /
events for "bus" and "class" registration must be matched as "subsystem"
[elogind.git] / udev_rules.c
index c0f4cd2077b1f643898eeb7e9e9a97cda5982413..1139c99a7d0e84ff3b8e289a3c6af251d5aabf76 100644 (file)
@@ -79,67 +79,37 @@ static int get_key(char **line, char **key, char **value)
        char *temp;
 
        linepos = *line;
-       if (!linepos)
+       if (linepos == NULL)
                return -1;
 
-       if (strchr(linepos, '\\')) {
-               dbg("escaped characters are not supported, skip");
-               return -1;
-       }
-
        /* skip whitespace */
        while (isspace(linepos[0]))
                linepos++;
 
        /* get the key */
+       temp = strchr(linepos, '=');
+       if (temp == NULL || temp == linepos)
+               return -1;
+       temp[0] = '\0';
        *key = linepos;
-       while (1) {
-               linepos++;
-               if (linepos[0] == '\0')
-                       return -1;
-               if (isspace(linepos[0]))
-                       break;
-               if (linepos[0] == '=')
-                       break;
+       linepos = &temp[1];
+
+       /* get a quoted value */
+       if (linepos[0] == '"' || linepos[0] == '\'') {
+               temp = strchr(&linepos[1], linepos[0]);
+               if (temp != NULL) {
+                       temp[0] = '\0';
+                       *value = &linepos[1];
+                       goto out;
+               }
        }
 
-       /* terminate key */
-       linepos[0] = '\0';
-       linepos++;
-
-       /* skip whitespace */
-       while (isspace(linepos[0]))
-               linepos++;
-
        /* get the value*/
-       if (linepos[0] == '"') {
-               linepos++;
-               temp = strchr(linepos, '"');
-               if (!temp) {
-                       dbg("missing closing quote");
-                       return -1;
-               }
-               dbg("value is quoted");
-               temp[0] = '\0';
-       } else if (linepos[0] == '\'') {
-               linepos++;
-               temp = strchr(linepos, '\'');
-               if (!temp) {
-                       dbg("missing closing quote");
-                       return -1;
-               }
-               dbg("value is quoted");
+       temp = strchr(linepos, '\n');
+       if (temp != NULL)
                temp[0] = '\0';
-       } else if (linepos[0] == '\0') {
-               dbg("value is empty");
-       } else {
-               temp = linepos;
-               while (temp[0] && !isspace(temp[0]))
-                       temp++;
-               temp[0] = '\0';
-       }
        *value = linepos;
-
+out:
        return 0;
 }
 
@@ -217,7 +187,7 @@ static int import_file_into_env(struct udevice *udev, const char *filename)
 
 static int import_program_into_env(struct udevice *udev, const char *program)
 {
-       char result[1024];
+       char result[2048];
        size_t reslen;
 
        if (run_program(program, udev->dev->subsystem, result, sizeof(result), &reslen, (udev_log_priority >= LOG_INFO)) != 0)
@@ -236,7 +206,7 @@ static int import_parent_into_env(struct udevice *udev, const char *filter)
                struct name_entry *name_loop;
 
                dbg("found parent '%s', get the node name", dev_parent->devpath);
-               udev_parent = udev_device_init();
+               udev_parent = udev_device_init(NULL);
                if (udev_parent == NULL)
                        return -1;
                /* import the udev_db of the parent */
@@ -289,7 +259,7 @@ static int wait_for_sysfs(struct udevice *udev, const char *file, int timeout)
                        info("file '%s' appeared after %i loops", filepath, (timeout * WAIT_LOOP_PER_SECOND) - loop-1);
                        return 0;
                }
-               /* make sure the device does not have disappeared in the meantime */
+               /* make sure, the device did not disappear in the meantime */
                if (stat(devicepath, &stats) != 0) {
                        info("device disappeared while waiting for '%s'", filepath);
                        return -2;
@@ -496,15 +466,15 @@ found:
                                if (value == NULL)
                                        break;
 
-                               /* strip trailing whitespace and replace untrusted characters of sysfs value */
+                               /* strip trailing whitespace, and replace unwanted characters */
                                size = strlcpy(temp2, value, sizeof(temp2));
                                if (size >= sizeof(temp2))
                                        size = sizeof(temp2)-1;
                                while (size > 0 && isspace(temp2[size-1]))
                                        temp2[--size] = '\0';
-                               count = replace_untrusted_chars(temp2);
+                               count = replace_chars(temp2, ALLOWED_CHARS_INPUT);
                                if (count > 0)
-                                       info("%i untrusted character(s) replaced" , count);
+                                       info("%i character(s) replaced" , count);
                                strlcat(string, temp2, maxsize);
                                dbg("substitute sysfs value '%s'", temp2);
                        }
@@ -518,7 +488,7 @@ found:
                                        struct udevice *udev_parent;
 
                                        dbg("found parent '%s', get the node name", dev_parent->devpath);
-                                       udev_parent = udev_device_init();
+                                       udev_parent = udev_device_init(NULL);
                                        if (udev_parent != NULL) {
                                                /* lookup the name in the udev_db with the DEVPATH of the parent */
                                                if (udev_db_get_device(udev_parent, dev_parent->devpath) == 0) {
@@ -532,7 +502,7 @@ found:
                        }
                        break;
                case SUBST_TEMP_NODE:
-                       if (udev->tmp_node[0] == '\0') {
+                       if (udev->tmp_node[0] == '\0' && major(udev->devt) > 0) {
                                dbg("create temporary device node for callout");
                                snprintf(udev->tmp_node, sizeof(udev->tmp_node), "%s/.tmp-%u-%u",
                                         udev_root, major(udev->devt), minor(udev->devt));
@@ -584,18 +554,18 @@ static char *key_pair_name(struct udev_rule *rule, struct key_pair *pair)
 
 static int match_key(const char *key_name, struct udev_rule *rule, struct key *key, const char *val)
 {
-       int match;
        char value[PATH_SIZE];
        char *key_value;
        char *pos;
+       int match = 0;
 
        if (key->operation != KEY_OP_MATCH &&
            key->operation != KEY_OP_NOMATCH)
                return 0;
 
+       /* look for a matching string, parts are separated by '|' */
        strlcpy(value, rule->buf + key->val_off, sizeof(value));
        key_value = value;
-
        dbg("key %s value='%s'", key_name, key_value);
        while (key_value) {
                pos = strchr(key_value, '|');
@@ -603,19 +573,23 @@ static int match_key(const char *key_name, struct udev_rule *rule, struct key *k
                        pos[0] = '\0';
                        pos++;
                }
+
                dbg("match %s '%s' <-> '%s'", key_name, key_value, val);
                match = (fnmatch(key_value, val, 0) == 0);
-               if (match && (key->operation != KEY_OP_NOMATCH)) {
-                       dbg("%s is true (matching value)", key_name);
-                       return 0;
-               }
-               if (!match && (key->operation == KEY_OP_NOMATCH)) {
-                       dbg("%s is true (non-matching value)", key_name);
-                       return 0;
-               }
+               if (match)
+                       break;
+
                key_value = pos;
        }
-       dbg("%s is false", key_name);
+
+       if (match && (key->operation == KEY_OP_MATCH)) {
+               dbg("%s is true (matching value)", key_name);
+               return 0;
+       }
+       if (!match && (key->operation == KEY_OP_NOMATCH)) {
+               dbg("%s is true (non-matching value)", key_name);
+               return 0;
+       }
        return -1;
 }
 
@@ -777,9 +751,9 @@ try_parent:
 
                        dbg("PROGRAM matches");
                        remove_trailing_chars(result, '\n');
-                       count = replace_untrusted_chars(result);
+                       count = replace_chars(result, ALLOWED_CHARS_INPUT);
                        if (count)
-                               info("%i untrusted character(s) replaced" , count);
+                               info("%i character(s) replaced" , count);
                        dbg("result is '%s'", result);
                        strlcpy(udev->program_result, result, sizeof(udev->program_result));
                        dbg("PROGRAM returned successful");
@@ -827,22 +801,27 @@ try_parent:
                        char temp_value[NAME_SIZE];
                        const char *key_name = key_pair_name(rule, pair);
                        const char *value = key_val(rule, &pair->key);
-                       char *key_value;
 
                        /* make sure we don't write to the same string we possibly read from */
                        strlcpy(temp_value, value, sizeof(temp_value));
                        udev_rules_apply_format(udev, temp_value, NAME_SIZE);
 
-                       key_value = name_list_key_add(&udev->env_list, key_name, temp_value);
-                       if (key_value == NULL)
-                               break;
+                       if (temp_value[0] == '\0') {
+                               name_list_key_remove(&udev->env_list, key_name);
+                               unsetenv(key_name);
+                               info("unset ENV '%s'", key_name);
+                       } else {
+                               char *key_value = name_list_key_add(&udev->env_list, key_name, temp_value);
 
-                       putenv(key_value);
-                       dbg("export ENV '%s'", key_value);
+                               if (key_value == NULL)
+                                       break;
+                               putenv(key_value);
+                               info("set ENV '%s'", key_value);
+                       }
                }
        }
 
-       /* if we have ATTR assignements write value to sysfs file */
+       /* if we have ATTR assignments, write value to sysfs file */
        for (i = 0; i < rule->attr.count; i++) {
                struct key_pair *pair = &rule->attr.keys[i];
 
@@ -861,8 +840,9 @@ try_parent:
                        info("writing '%s' to sysfs file '%s'", value, attr);
                        f = fopen(attr, "w");
                        if (f != NULL) {
-                               if (fprintf(f, "%s", value) <= 0)
-                                       err("error writing ATTR{%s}: %s", attr, strerror(errno));
+                               if (!udev->test_run)
+                                       if (fprintf(f, "%s", value) <= 0)
+                                               err("error writing ATTR{%s}: %s", attr, strerror(errno));
                                fclose(f);
                        } else
                                err("error opening ATTR{%s} for writing: %s", attr, strerror(errno));
@@ -909,7 +889,7 @@ int udev_rules_get_name(struct udev_rules *rules, struct udevice *udev)
                                udev->ignore_remove = 1;
                                dbg("remove event should be ignored");
                        }
-                       if (rule->link_priority) {
+                       if (rule->link_priority != 0) {
                                udev->link_priority = rule->link_priority;
                                info("link_priority=%i", udev->link_priority);
                        }
@@ -954,14 +934,13 @@ int udev_rules_get_name(struct udev_rules *rules, struct udevice *udev)
                                        info("reset symlink list");
                                        name_list_cleanup(&udev->symlink_list);
                                }
+                               /* allow  multiple symlinks separated by spaces */
                                strlcpy(temp, key_val(rule, &rule->symlink), sizeof(temp));
                                udev_rules_apply_format(udev, temp, sizeof(temp));
-                               count = replace_untrusted_chars(temp);
+                               count = replace_chars(temp, ALLOWED_CHARS_FILE " ");
                                if (count)
-                                       info("%i untrusted character(s) replaced" , count);
+                                       info("%i character(s) replaced" , count);
                                dbg("rule applied, added symlink(s) '%s'", temp);
-
-                               /* add multiple symlinks separated by spaces */
                                pos = temp;
                                while (isspace(pos[0]))
                                        pos++;
@@ -990,9 +969,9 @@ int udev_rules_get_name(struct udev_rules *rules, struct udevice *udev)
                                name_set = 1;
                                strlcpy(udev->name, key_val(rule, &rule->name), sizeof(udev->name));
                                udev_rules_apply_format(udev, udev->name, sizeof(udev->name));
-                               count = replace_untrusted_chars(udev->name);
+                               count = replace_chars(udev->name, ALLOWED_CHARS_FILE);
                                if (count)
-                                       info("%i untrusted character(s) replaced", count);
+                                       info("%i character(s) replaced", count);
 
                                info("rule applied, '%s' becomes '%s'", udev->dev->kernel, udev->name);
                                if (strcmp(udev->dev->subsystem, "net") != 0)