diff options
-rw-r--r-- | man/udev.xml | 12 | ||||
-rw-r--r-- | src/udev/udev-rules.c | 61 |
2 files changed, 71 insertions, 2 deletions
diff --git a/man/udev.xml b/man/udev.xml index 69be5d19c5..fd7df34ff1 100644 --- a/man/udev.xml +++ b/man/udev.xml @@ -194,6 +194,11 @@ value itself contains trailing whitespace. </para> </listitem> + <term><varname>SYSCTL{<replaceable>kernel parameter</replaceable>}</varname></term> + <listitem> + <para>Match a kernel parameter value. + </para> + </listitem> </varlistentry> <varlistentry> @@ -373,6 +378,13 @@ </varlistentry> <varlistentry> + <term><varname>SYSCTL{<replaceable>kernel parameter</replaceable>}</varname></term> + <listitem> + <para>The value that should be written to kernel parameter.</para> + </listitem> + </varlistentry> + + <varlistentry> <term><varname>ENV{<replaceable>key</replaceable>}</varname></term> <listitem> <para>Set a device property value. Property names with a leading <literal>.</literal> diff --git a/src/udev/udev-rules.c b/src/udev/udev-rules.c index 2522bcd24b..f63b87b015 100644 --- a/src/udev/udev-rules.c +++ b/src/udev/udev-rules.c @@ -35,6 +35,7 @@ #include "strbuf.h" #include "strv.h" #include "util.h" +#include "sysctl-util.h" #define PREALLOC_TOKEN 2048 @@ -133,6 +134,7 @@ enum token_type { TK_M_DRIVER, /* val */ TK_M_WAITFOR, /* val */ TK_M_ATTR, /* val, attr */ + TK_M_SYSCTL, /* val, attr */ TK_M_PARENTS_MIN, TK_M_KERNELS, /* val */ @@ -171,6 +173,7 @@ enum token_type { TK_A_NAME, /* val */ TK_A_DEVLINK, /* val */ TK_A_ATTR, /* val, attr */ + TK_A_SYSCTL, /* val, attr */ TK_A_RUN_BUILTIN, /* val, bool */ TK_A_RUN_PROGRAM, /* val, bool */ TK_A_GOTO, /* size_t */ @@ -267,6 +270,7 @@ static const char *token_str(enum token_type type) { [TK_M_DRIVER] = "M DRIVER", [TK_M_WAITFOR] = "M WAITFOR", [TK_M_ATTR] = "M ATTR", + [TK_M_SYSCTL] = "M SYSCTL", [TK_M_PARENTS_MIN] = "M PARENTS_MIN", [TK_M_KERNELS] = "M KERNELS", @@ -305,6 +309,7 @@ static const char *token_str(enum token_type type) { [TK_A_NAME] = "A NAME", [TK_A_DEVLINK] = "A DEVLINK", [TK_A_ATTR] = "A ATTR", + [TK_A_SYSCTL] = "A SYSCTL", [TK_A_RUN_BUILTIN] = "A RUN_BUILTIN", [TK_A_RUN_PROGRAM] = "A RUN_PROGRAM", [TK_A_GOTO] = "A GOTO", @@ -368,9 +373,11 @@ static void dump_token(struct udev_rules *rules, struct token *token) { log_debug("%s %i '%s'", token_str(type), token->key.builtin_cmd, value); break; case TK_M_ATTR: + case TK_M_SYSCTL: case TK_M_ATTRS: case TK_M_ENV: case TK_A_ATTR: + case TK_A_SYSCTL: case TK_A_ENV: log_debug("%s %s '%s' '%s'(%s)", token_str(type), operation_str(op), attr, value, string_glob_str(glob)); @@ -902,8 +909,10 @@ static int rule_add_key(struct rule_tmp *rule_tmp, enum token_type type, break; case TK_M_ENV: case TK_M_ATTR: + case TK_M_SYSCTL: case TK_M_ATTRS: case TK_A_ATTR: + case TK_A_SYSCTL: case TK_A_ENV: case TK_A_SECLABEL: attr = data; @@ -1140,11 +1149,27 @@ static int add_rule(struct udev_rules *rules, char *line, log_error("invalid ATTR operation"); goto invalid; } - if (op < OP_MATCH_MAX) { + if (op < OP_MATCH_MAX) rule_add_key(&rule_tmp, TK_M_ATTR, op, value, attr); - } else { + else rule_add_key(&rule_tmp, TK_A_ATTR, op, value, attr); + continue; + } + + if (startswith(key, "SYSCTL{")) { + attr = get_key_attribute(rules->udev, key + strlen("SYSCTL")); + if (attr == NULL) { + log_error("error parsing SYSCTL attribute"); + goto invalid; + } + if (op == OP_REMOVE) { + log_error("invalid SYSCTL operation"); + goto invalid; } + if (op < OP_MATCH_MAX) + rule_add_key(&rule_tmp, TK_M_SYSCTL, op, value, attr); + else + rule_add_key(&rule_tmp, TK_A_SYSCTL, op, value, attr); continue; } @@ -1980,6 +2005,23 @@ int udev_rules_apply_to_event(struct udev_rules *rules, if (match_attr(rules, event->dev, event, cur) != 0) goto nomatch; break; + case TK_M_SYSCTL: { + char filename[UTIL_PATH_SIZE]; + _cleanup_free_ char *value = NULL; + size_t len; + + udev_event_apply_format(event, rules_str(rules, cur->key.attr_off), filename, sizeof(filename)); + sysctl_normalize(filename); + if (sysctl_read(filename, &value) < 0) + goto nomatch; + + len = strlen(value); + while (len > 0 && isspace(value[--len])) + value[len] = '\0'; + if (match_key(rules, cur, value) != 0) + goto nomatch; + break; + } case TK_M_KERNELS: case TK_M_SUBSYSTEMS: case TK_M_DRIVERS: @@ -2516,6 +2558,21 @@ int udev_rules_apply_to_event(struct udev_rules *rules, } break; } + case TK_A_SYSCTL: { + char filename[UTIL_PATH_SIZE]; + char value[UTIL_NAME_SIZE]; + int r; + + udev_event_apply_format(event, rules_str(rules, cur->key.attr_off), filename, sizeof(filename)); + sysctl_normalize(filename); + udev_event_apply_format(event, rules_str(rules, cur->key.value_off), value, sizeof(value)); + log_debug("SYSCTL '%s' writing '%s' %s:%u", filename, value, + rules_str(rules, rule->rule.filename_off), rule->rule.filename_line); + r = sysctl_write(filename, value); + if (r < 0) + log_error("error writing SYSCTL{%s}='%s': %s", filename, value, strerror(-r)); + break; + } case TK_A_RUN_BUILTIN: case TK_A_RUN_PROGRAM: { struct udev_list_entry *entry; |