chiark / gitweb /
update NEWS
[elogind.git] / udev / udev-rules.c
index 742d88b3d59fb7d543e0f91f9055c3ee1fa0a37a..aa750219daaa8dc5c513c0f3323e90a417bfe936 100644 (file)
@@ -198,7 +198,6 @@ struct token {
                        union {
                                unsigned int attr_off;
                                int devlink_unique;
-                               int fail_on_error;
                                unsigned int rule_goto;
                                mode_t  mode;
                                uid_t uid;
@@ -365,7 +364,7 @@ static void dump_token(struct udev_rules *rules, struct token *token)
                    token_str(type), operation_str(op), value, string_glob_str(glob));
                break;
        case TK_M_IMPORT_BUILTIN:
-               dbg(rules->udev, "%s %i\n", token_str(type), token->key.builtin_cmd);
+               dbg(rules->udev, "%s %i '%s'\n", token_str(type), token->key.builtin_cmd, value);
                break;
        case TK_M_ATTR:
        case TK_M_ATTRS:
@@ -1040,6 +1039,7 @@ static int rule_add_key(struct rule_tmp *rule_tmp, enum token_type type,
                token->key.value_off = add_string(rule_tmp->rules, value);
                break;
        case TK_M_IMPORT_BUILTIN:
+               token->key.value_off = add_string(rule_tmp->rules, value);
                token->key.builtin_cmd = *(enum udev_builtin_cmd *)data;
                break;
        case TK_M_ENV:
@@ -1066,7 +1066,6 @@ static int rule_add_key(struct rule_tmp *rule_tmp, enum token_type type,
                break;
        case TK_A_RUN:
                token->key.value_off = add_string(rule_tmp->rules, value);
-               token->key.fail_on_error = *(int *)data;
                break;
        case TK_A_INOTIFY_WATCH:
        case TK_A_DEVLINK_PRIO:
@@ -1191,9 +1190,6 @@ static int add_rule(struct udev_rules *rules, char *line,
        char *linepos;
        char *attr;
        struct rule_tmp rule_tmp;
-       bool bus_warn = false;
-       bool sysfs_warn = false;
-       bool id_warn = false;
 
        memset(&rule_tmp, 0x00, sizeof(struct rule_tmp));
        rule_tmp.rules = rules;
@@ -1287,21 +1283,6 @@ static int add_rule(struct udev_rules *rules, char *line,
                        continue;
                }
 
-               if (strcmp(key, "ID") == 0) {
-                       if (!id_warn) {
-                               id_warn = true;
-                               err(rules->udev, "ID= will be removed in a future udev version, "
-                                   "please use KERNEL= to match the event device, or KERNELS= "
-                                   "to match a parent device, in %s:%u\n", filename, lineno);
-                       }
-                       if (op > OP_MATCH_MAX) {
-                               err(rules->udev, "invalid KERNELS operation\n");
-                               goto invalid;
-                       }
-                       rule_add_key(&rule_tmp, TK_M_KERNELS, op, value, NULL);
-                       continue;
-               }
-
                if (strcmp(key, "SUBSYSTEMS") == 0) {
                        if (op > OP_MATCH_MAX) {
                                err(rules->udev, "invalid SUBSYSTEMS operation\n");
@@ -1311,21 +1292,6 @@ static int add_rule(struct udev_rules *rules, char *line,
                        continue;
                }
 
-               if (strcmp(key, "BUS") == 0) {
-                       if (!bus_warn) {
-                               bus_warn = true;
-                               err(rules->udev, "BUS= will be removed in a future udev version, "
-                                   "please use SUBSYSTEM= to match the event device, or SUBSYSTEMS= "
-                                   "to match a parent device, in %s:%u\n", filename, lineno);
-                       }
-                       if (op > OP_MATCH_MAX) {
-                               err(rules->udev, "invalid SUBSYSTEMS operation\n");
-                               goto invalid;
-                       }
-                       rule_add_key(&rule_tmp, TK_M_SUBSYSTEMS, op, value, NULL);
-                       continue;
-               }
-
                if (strcmp(key, "DRIVERS") == 0) {
                        if (op > OP_MATCH_MAX) {
                                err(rules->udev, "invalid DRIVERS operation\n");
@@ -1364,26 +1330,6 @@ static int add_rule(struct udev_rules *rules, char *line,
                        continue;
                }
 
-               if (strncmp(key, "SYSFS{", sizeof("SYSFS{")-1) == 0) {
-                       if (!sysfs_warn) {
-                               sysfs_warn = true;
-                               err(rules->udev, "SYSFS{}= will be removed in a future udev version, "
-                                   "please use ATTR{}= to match the event device, or ATTRS{}= "
-                                   "to match a parent device, in %s:%u\n", filename, lineno);
-                       }
-                       if (op > OP_MATCH_MAX) {
-                               err(rules->udev, "invalid ATTRS operation\n");
-                               goto invalid;
-                       }
-                       attr = get_key_attribute(rules->udev, key + sizeof("ATTRS")-1);
-                       if (attr == NULL) {
-                               err(rules->udev, "error parsing ATTRS attribute\n");
-                               goto invalid;
-                       }
-                       rule_add_key(&rule_tmp, TK_M_ATTRS, op, value, attr);
-                       continue;
-               }
-
                if (strncmp(key, "ENV{", sizeof("ENV{")-1) == 0) {
                        attr = get_key_attribute(rules->udev, key + sizeof("ENV")-1);
                        if (attr == NULL) {
@@ -1451,18 +1397,13 @@ static int add_rule(struct udev_rules *rules, char *line,
                        if (strstr(attr, "program")) {
                                /* find known built-in command */
                                if (value[0] != '/') {
-                                       char file[UTIL_PATH_SIZE];
-                                       char *pos;
                                        enum udev_builtin_cmd cmd;
 
-                                       util_strscpy(file, sizeof(file), value);
-                                       pos = strchr(file, ' ');
-                                       if (pos)
-                                               pos[0] = '\0';
-                                       cmd = udev_builtin_lookup(file);
+                                       cmd = udev_builtin_lookup(value);
                                        if (cmd < UDEV_BUILTIN_MAX) {
-                                               info(rules->udev, "IMPORT found builtin '%s', replacing %s:%u\n", file, filename, lineno);
-                                               rule_add_key(&rule_tmp, TK_M_IMPORT_BUILTIN, op, NULL, &cmd);
+                                               info(rules->udev, "IMPORT found builtin '%s', replacing %s:%u\n",
+                                                    value, filename, lineno);
+                                               rule_add_key(&rule_tmp, TK_M_IMPORT_BUILTIN, op, value, &cmd);
                                                continue;
                                        }
                                }
@@ -1473,7 +1414,7 @@ static int add_rule(struct udev_rules *rules, char *line,
 
                                dbg(rules->udev, "IMPORT execute builtin\n");
                                if (cmd < UDEV_BUILTIN_MAX)
-                                       rule_add_key(&rule_tmp, TK_M_IMPORT_BUILTIN, op, NULL, &cmd);
+                                       rule_add_key(&rule_tmp, TK_M_IMPORT_BUILTIN, op, value, &cmd);
                                else
                                        err(rules->udev, "IMPORT{builtin}: '%s' unknown %s:%u\n", value, filename, lineno);
                        } else if (strstr(attr, "file")) {
@@ -1509,13 +1450,8 @@ static int add_rule(struct udev_rules *rules, char *line,
                        continue;
                }
 
-               if (strncmp(key, "RUN", sizeof("RUN")-1) == 0) {
-                       int flag = 0;
-
-                       attr = get_key_attribute(rules->udev, key + sizeof("RUN")-1);
-                       if (attr != NULL && strstr(attr, "fail_event_on_error"))
-                               flag = 1;
-                       rule_add_key(&rule_tmp, TK_A_RUN, op, value, &flag);
+               if (strcmp(key, "RUN") == 0) {
+                       rule_add_key(&rule_tmp, TK_A_RUN, op, value, NULL);
                        continue;
                }
 
@@ -1672,7 +1608,9 @@ static int add_rule(struct udev_rules *rules, char *line,
 
                        continue;
                }
+
                err(rules->udev, "unknown key '%s' in %s:%u\n", key, filename, lineno);
+               goto invalid;
        }
 
        /* add rule token */
@@ -1856,13 +1794,13 @@ struct udev_rules *udev_rules_new(struct udev *udev, int resolve_names)
        if (udev_get_rules_path(udev) == NULL) {
                char filename[UTIL_PATH_SIZE];
 
-               /* /lib/udev -- default/package rules */
+               /* /usr/lib/udev -- system rules */
                add_matching_files(udev, &file_list, LIBEXECDIR "/rules.d", ".rules");
 
-               /* /etc/udev -- system-specific/user/admin rules */
+               /* /etc/udev -- local administration rules */
                add_matching_files(udev, &file_list, SYSCONFDIR "/udev/rules.d", ".rules");
 
-               /* /run/udev -- throw-away/temporary rules */
+               /* /run/udev -- runtime rules */
                util_strscpyl(filename, sizeof(filename), udev_get_run_path(udev), "/rules.d", NULL);
                add_matching_files(udev, &file_list, filename, ".rules");
        } else {
@@ -1952,16 +1890,17 @@ struct udev_rules *udev_rules_new(struct udev *udev, int resolve_names)
        return rules;
 }
 
-void udev_rules_unref(struct udev_rules *rules)
+struct udev_rules *udev_rules_unref(struct udev_rules *rules)
 {
        if (rules == NULL)
-               return;
+               return NULL;
        free(rules->tokens);
        free(rules->buf);
        free(rules->trie_nodes);
        free(rules->uids);
        free(rules->gids);
        free(rules);
+       return NULL;
 }
 
 static int match_key(struct udev_rules *rules, struct token *token, const char *val)
@@ -2331,7 +2270,7 @@ int udev_rules_apply_to_event(struct udev_rules *rules, struct udev_event *event
 
                                util_remove_trailing_chars(result, '\n');
                                if (esc == ESCAPE_UNSET || esc == ESCAPE_REPLACE) {
-                                       count = udev_util_replace_chars(result, UDEV_ALLOWED_CHARS_INPUT);
+                                       count = util_replace_chars(result, UDEV_ALLOWED_CHARS_INPUT);
                                        if (count > 0)
                                                info(event->udev, "%i character(s) replaced\n" , count);
                                }
@@ -2366,25 +2305,32 @@ int udev_rules_apply_to_event(struct udev_rules *rules, struct udev_event *event
                        break;
                }
                case TK_M_IMPORT_BUILTIN: {
-                       /* check if we ran already */
-                       if (event->builtin_run & (1 << cur->key.builtin_cmd)) {
-                               info(event->udev, "IMPORT builtin skip '%s' %s:%u\n",
-                                    udev_builtin_name(cur->key.builtin_cmd),
-                                    &rules->buf[rule->rule.filename_off],
-                                    rule->rule.filename_line);
-                               /* return the result from earlier run */
-                               if (event->builtin_ret & (1 << cur->key.builtin_cmd))
+                       char command[UTIL_PATH_SIZE];
+
+                       if (udev_builtin_run_once(cur->key.builtin_cmd)) {
+                               /* check if we ran already */
+                               if (event->builtin_run & (1 << cur->key.builtin_cmd)) {
+                                       info(event->udev, "IMPORT builtin skip '%s' %s:%u\n",
+                                            udev_builtin_name(cur->key.builtin_cmd),
+                                            &rules->buf[rule->rule.filename_off],
+                                            rule->rule.filename_line);
+                                       /* return the result from earlier run */
+                                       if (event->builtin_ret & (1 << cur->key.builtin_cmd))
                                        if (cur->key.op != OP_NOMATCH)
-                                               goto nomatch;
-                               break;
+                                                       goto nomatch;
+                                       break;
+                               }
+                               /* mark as ran */
+                               event->builtin_run |= (1 << cur->key.builtin_cmd);
                        }
-                       /* mark as ran */
-                       event->builtin_run |= (1 << cur->key.builtin_cmd);
+
+                       udev_event_apply_format(event, &rules->buf[cur->key.value_off], command, sizeof(command));
                        info(event->udev, "IMPORT builtin '%s' %s:%u\n",
                             udev_builtin_name(cur->key.builtin_cmd),
                             &rules->buf[rule->rule.filename_off],
                             rule->rule.filename_line);
-                       if (udev_builtin_run(event->dev, cur->key.builtin_cmd, false) != 0) {
+
+                       if (udev_builtin_run(event->dev, cur->key.builtin_cmd, command, false) != 0) {
                                /* remember failure */
                                info(rules->udev, "IMPORT builtin '%s' returned non-zero\n",
                                     udev_builtin_name(cur->key.builtin_cmd));
@@ -2572,6 +2518,7 @@ int udev_rules_apply_to_event(struct udev_rules *rules, struct udev_event *event
                             rule->rule.filename_line);
                        break;
                case TK_A_STATIC_NODE:
+                       event->static_node = true;
                        break;
                case TK_A_ENV: {
                        const char *name = &rules->buf[cur->key.attr_off];
@@ -2621,7 +2568,7 @@ int udev_rules_apply_to_event(struct udev_rules *rules, struct udev_event *event
                                event->name_final = true;
                        udev_event_apply_format(event, name, name_str, sizeof(name_str));
                        if (esc == ESCAPE_UNSET || esc == ESCAPE_REPLACE) {
-                               count = udev_util_replace_chars(name_str, "/");
+                               count = util_replace_chars(name_str, "/");
                                if (count > 0)
                                        info(event->udev, "%i character(s) replaced\n", count);
                        }
@@ -2651,9 +2598,9 @@ int udev_rules_apply_to_event(struct udev_rules *rules, struct udev_event *event
                        /* allow  multiple symlinks separated by spaces */
                        udev_event_apply_format(event, &rules->buf[cur->key.value_off], temp, sizeof(temp));
                        if (esc == ESCAPE_UNSET)
-                               count = udev_util_replace_chars(temp, "/ ");
+                               count = util_replace_chars(temp, "/ ");
                        else if (esc == ESCAPE_REPLACE)
-                               count = udev_util_replace_chars(temp, "/");
+                               count = util_replace_chars(temp, "/");
                        if (count > 0)
                                info(event->udev, "%i character(s) replaced\n" , count);
                        dbg(event->udev, "rule applied, added symlink(s) '%s'\n", temp);
@@ -2705,17 +2652,13 @@ int udev_rules_apply_to_event(struct udev_rules *rules, struct udev_event *event
                        break;
                }
                case TK_A_RUN: {
-                       struct udev_list_entry *list_entry;
-
                        if (cur->key.op == OP_ASSIGN || cur->key.op == OP_ASSIGN_FINAL)
                                udev_list_cleanup(&event->run_list);
                        info(event->udev, "RUN '%s' %s:%u\n",
                             &rules->buf[cur->key.value_off],
                             &rules->buf[rule->rule.filename_off],
                             rule->rule.filename_line);
-                       list_entry = udev_list_entry_add(&event->run_list, &rules->buf[cur->key.value_off], NULL);
-                       if (cur->key.fail_on_error)
-                               udev_list_entry_set_num(list_entry, true);
+                       udev_list_entry_add(&event->run_list, &rules->buf[cur->key.value_off], NULL);
                        break;
                }
                case TK_A_GOTO:
@@ -2793,10 +2736,15 @@ void udev_rules_apply_static_dev_perms(struct udev_rules *rules)
                                goto next;
                        if (!S_ISBLK(stats.st_mode) && !S_ISCHR(stats.st_mode))
                                goto next;
-
-                       if (mode == 0 && gid > 0)
-                               mode = 0660;
-                       if (mode != (stats.st_mode & 0777)) {
+                       if (mode == 0) {
+                               if (gid > 0)
+                                       mode = 0660;
+                               else
+                                       mode = 0600;
+                       }
+                       /* set sticky bit, so we do not remove the node on module unload */
+                       mode |= 01000;
+                       if (mode != (stats.st_mode & 01777)) {
                                chmod(filename, mode);
                                info(rules->udev, "chmod '%s' %#o\n", filename, mode);
                        }