diff options
author | Yu Watanabe <watanabe.yu+github@gmail.com> | 2024-01-05 12:08:26 +0100 |
---|---|---|
committer | Yu Watanabe <watanabe.yu+github@gmail.com> | 2024-01-09 20:33:51 +0100 |
commit | 046286e863f20b2d0fa7eb9a5a7ac26aa399b3fe (patch) | |
tree | fc66f85479b610c0c7befdd6794852e21407a12d /src/udev | |
parent | udev: split out check that udev property can be updated (diff) | |
download | systemd-046286e863f20b2d0fa7eb9a5a7ac26aa399b3fe.tar.xz systemd-046286e863f20b2d0fa7eb9a5a7ac26aa399b3fe.zip |
udev/net: introduce [Link] Property=, ImportProperty=, and UnsetProperty= settings
The applied order is equivalent to Environment=, PassEnvironment=, and
UnsetEnvironment= for [Service] or so.
Diffstat (limited to 'src/udev')
-rw-r--r-- | src/udev/net/link-config-gperf.gperf | 3 | ||||
-rw-r--r-- | src/udev/net/link-config.c | 177 | ||||
-rw-r--r-- | src/udev/net/link-config.h | 8 | ||||
-rw-r--r-- | src/udev/udev-builtin-net_setup_link.c | 2 | ||||
-rw-r--r-- | src/udev/udevadm-test-builtin.c | 11 |
5 files changed, 198 insertions, 3 deletions
diff --git a/src/udev/net/link-config-gperf.gperf b/src/udev/net/link-config-gperf.gperf index 240f16e251..42d7cc7ee2 100644 --- a/src/udev/net/link-config-gperf.gperf +++ b/src/udev/net/link-config-gperf.gperf @@ -38,6 +38,9 @@ Match.Credential, config_parse_net_condition, Match.Architecture, config_parse_net_condition, CONDITION_ARCHITECTURE, offsetof(LinkConfig, conditions) Match.Firmware, config_parse_net_condition, CONDITION_FIRMWARE, offsetof(LinkConfig, conditions) Link.Description, config_parse_string, 0, offsetof(LinkConfig, description) +Link.Property, config_parse_udev_property, 0, offsetof(LinkConfig, properties) +Link.ImportProperty, config_parse_udev_property_name, 0, offsetof(LinkConfig, import_properties) +Link.UnsetProperty, config_parse_udev_property_name, 0, offsetof(LinkConfig, unset_properties) Link.MACAddressPolicy, config_parse_mac_address_policy, 0, offsetof(LinkConfig, mac_address_policy) Link.MACAddress, config_parse_hw_addr, 0, offsetof(LinkConfig, hw_addr) Link.NamePolicy, config_parse_name_policy, 0, offsetof(LinkConfig, name_policy) diff --git a/src/udev/net/link-config.c b/src/udev/net/link-config.c index c9c4e9c927..a8b2cc23a2 100644 --- a/src/udev/net/link-config.c +++ b/src/udev/net/link-config.c @@ -15,6 +15,7 @@ #include "creds-util.h" #include "device-private.h" #include "device-util.h" +#include "env-util.h" #include "escape.h" #include "ethtool-util.h" #include "fd-util.h" @@ -31,6 +32,7 @@ #include "path-util.h" #include "proc-cmdline.h" #include "random-util.h" +#include "specifier.h" #include "stat-util.h" #include "string-table.h" #include "string-util.h" @@ -38,6 +40,12 @@ #include "udev-builtin.h" #include "utf8.h" +static const Specifier link_specifier_table[] = { + COMMON_SYSTEM_SPECIFIERS, + COMMON_TMP_SPECIFIERS, + {} +}; + struct LinkConfigContext { LIST_HEAD(LinkConfig, configs); int ethtool_fd; @@ -55,6 +63,9 @@ static LinkConfig* link_config_free(LinkConfig *config) { condition_free_list(config->conditions); free(config->description); + strv_free(config->properties); + strv_free(config->import_properties); + strv_free(config->unset_properties); free(config->name_policy); free(config->name); strv_free(config->alternative_names); @@ -365,18 +376,20 @@ Link *link_free(Link *link) { return NULL; sd_device_unref(link->device); + sd_device_unref(link->device_db_clone); free(link->kind); strv_free(link->altnames); return mfree(link); } -int link_new(LinkConfigContext *ctx, sd_netlink **rtnl, sd_device *device, Link **ret) { +int link_new(LinkConfigContext *ctx, sd_netlink **rtnl, sd_device *device, sd_device *device_db_clone, Link **ret) { _cleanup_(link_freep) Link *link = NULL; int r; assert(ctx); assert(rtnl); assert(device); + assert(device_db_clone); assert(ret); link = new(Link, 1); @@ -385,6 +398,7 @@ int link_new(LinkConfigContext *ctx, sd_netlink **rtnl, sd_device *device, Link *link = (Link) { .device = sd_device_ref(device), + .device_db_clone = sd_device_ref(device_db_clone), }; r = sd_device_get_sysname(device, &link->ifname); @@ -932,6 +946,31 @@ static int link_apply_udev_properties(Link *link, bool test) { config = ASSERT_PTR(link->config); device = ASSERT_PTR(link->device); + /* 1. apply ImportProperty=. */ + STRV_FOREACH(p, config->import_properties) + (void) udev_builtin_import_property(device, link->device_db_clone, test, *p); + + /* 2. apply Property=. */ + STRV_FOREACH(p, config->properties) { + _cleanup_free_ char *key = NULL; + const char *eq; + + eq = strchr(*p, '='); + if (!eq) + continue; + + key = strndup(*p, eq - *p); + if (!key) + return log_oom(); + + (void) udev_builtin_add_property(device, test, key, eq + 1); + } + + /* 3. apply UnsetProperty=. */ + STRV_FOREACH(p, config->unset_properties) + (void) udev_builtin_add_property(device, test, *p, NULL); + + /* 4. set the default properties. */ (void) udev_builtin_add_property(device, test, "ID_NET_LINK_FILE", config->filename); _cleanup_free_ char *joined = NULL; @@ -988,6 +1027,142 @@ int link_apply_config(LinkConfigContext *ctx, sd_netlink **rtnl, Link *link, boo return 0; } +int config_parse_udev_property( + const char *unit, + const char *filename, + unsigned line, + const char *section, + unsigned section_line, + const char *lvalue, + int ltype, + const char *rvalue, + void *data, + void *userdata) { + + char ***properties = ASSERT_PTR(data); + int r; + + assert(filename); + assert(lvalue); + assert(rvalue); + + if (isempty(rvalue)) { + /* Empty assignment resets the list */ + *properties = strv_free(*properties); + return 0; + } + + for (const char *p = rvalue;; ) { + _cleanup_free_ char *word = NULL, *resolved = NULL, *key = NULL; + const char *eq; + + r = extract_first_word(&p, &word, NULL, EXTRACT_CUNESCAPE|EXTRACT_UNQUOTE); + if (r == -ENOMEM) + return log_oom(); + if (r < 0) { + log_syntax(unit, LOG_WARNING, filename, line, r, + "Invalid syntax, ignoring assignment: %s", rvalue); + return 0; + } + if (r == 0) + return 0; + + r = specifier_printf(word, SIZE_MAX, link_specifier_table, NULL, NULL, &resolved); + if (r < 0) { + log_syntax(unit, LOG_WARNING, filename, line, r, + "Failed to resolve specifiers in %s, ignoring assignment: %m", word); + continue; + } + + /* The restriction for udev property is not clear. Let's apply the one for environment variable here. */ + if (!env_assignment_is_valid(resolved)) { + log_syntax(unit, LOG_WARNING, filename, line, 0, + "Invalid udev property, ignoring assignment: %s", word); + continue; + } + + assert_se(eq = strchr(resolved, '=')); + key = strndup(resolved, eq - resolved); + if (!key) + return log_oom(); + + if (!device_property_can_set(key)) { + log_syntax(unit, LOG_WARNING, filename, line, 0, + "Invalid udev property name '%s', ignoring assignment: %s", key, resolved); + continue; + } + + r = strv_env_replace_consume(properties, TAKE_PTR(resolved)); + if (r < 0) + return log_error_errno(r, "Failed to update properties: %m"); + } +} + +int config_parse_udev_property_name( + const char *unit, + const char *filename, + unsigned line, + const char *section, + unsigned section_line, + const char *lvalue, + int ltype, + const char *rvalue, + void *data, + void *userdata) { + + char ***properties = ASSERT_PTR(data); + int r; + + assert(filename); + assert(lvalue); + assert(rvalue); + + if (isempty(rvalue)) { + /* Empty assignment resets the list */ + *properties = strv_free(*properties); + return 0; + } + + for (const char *p = rvalue;; ) { + _cleanup_free_ char *word = NULL, *resolved = NULL; + + r = extract_first_word(&p, &word, NULL, EXTRACT_CUNESCAPE|EXTRACT_UNQUOTE); + if (r == -ENOMEM) + return log_oom(); + if (r < 0) { + log_syntax(unit, LOG_WARNING, filename, line, r, + "Invalid syntax, ignoring assignment: %s", rvalue); + return 0; + } + if (r == 0) + return 0; + + r = specifier_printf(word, SIZE_MAX, link_specifier_table, NULL, NULL, &resolved); + if (r < 0) { + log_syntax(unit, LOG_WARNING, filename, line, r, + "Failed to resolve specifiers in %s, ignoring assignment: %m", word); + continue; + } + + /* The restriction for udev property is not clear. Let's apply the one for environment variable here. */ + if (!env_name_is_valid(resolved)) { + log_syntax(unit, LOG_WARNING, filename, line, 0, + "Invalid udev property name, ignoring assignment: %s", resolved); + continue; + } + + if (!device_property_can_set(resolved)) { + log_syntax(unit, LOG_WARNING, filename, line, 0, + "Invalid udev property name, ignoring assignment: %s", resolved); + continue; + } + + r = strv_consume(properties, TAKE_PTR(resolved)); + if (r < 0) + return log_error_errno(r, "Failed to update properties: %m"); + } +} + int config_parse_ifalias( const char *unit, const char *filename, diff --git a/src/udev/net/link-config.h b/src/udev/net/link-config.h index 06666a23ba..98cadc212e 100644 --- a/src/udev/net/link-config.h +++ b/src/udev/net/link-config.h @@ -31,6 +31,7 @@ typedef struct Link { LinkConfig *config; sd_device *device; + sd_device *device_db_clone; sd_device_action_t action; char *kind; @@ -51,6 +52,9 @@ struct LinkConfig { LIST_HEAD(Condition, conditions); char *description; + char **properties; + char **import_properties; + char **unset_properties; struct hw_addr_data hw_addr; MACAddressPolicy mac_address_policy; NamePolicy *name_policy; @@ -95,7 +99,7 @@ int link_load_one(LinkConfigContext *ctx, const char *filename); int link_config_load(LinkConfigContext *ctx); bool link_config_should_reload(LinkConfigContext *ctx); -int link_new(LinkConfigContext *ctx, sd_netlink **rtnl, sd_device *device, Link **ret); +int link_new(LinkConfigContext *ctx, sd_netlink **rtnl, sd_device *device, sd_device *device_db_clone, Link **ret); Link *link_free(Link *link); DEFINE_TRIVIAL_CLEANUP_FUNC(Link*, link_free); @@ -108,6 +112,8 @@ MACAddressPolicy mac_address_policy_from_string(const char *p) _pure_; /* gperf lookup function */ const struct ConfigPerfItem* link_config_gperf_lookup(const char *key, GPERF_LEN_TYPE length); +CONFIG_PARSER_PROTOTYPE(config_parse_udev_property); +CONFIG_PARSER_PROTOTYPE(config_parse_udev_property_name); CONFIG_PARSER_PROTOTYPE(config_parse_ifalias); CONFIG_PARSER_PROTOTYPE(config_parse_rx_tx_queues); CONFIG_PARSER_PROTOTYPE(config_parse_txqueuelen); diff --git a/src/udev/udev-builtin-net_setup_link.c b/src/udev/udev-builtin-net_setup_link.c index 59a0043422..fc614443ef 100644 --- a/src/udev/udev-builtin-net_setup_link.c +++ b/src/udev/udev-builtin-net_setup_link.c @@ -41,7 +41,7 @@ static int builtin_net_setup_link(UdevEvent *event, int argc, char **argv, bool return 0; } - r = link_new(ctx, &event->rtnl, dev, &link); + r = link_new(ctx, &event->rtnl, dev, event->dev_db_clone, &link); if (r == -ENODEV) { log_device_debug_errno(dev, r, "Link vanished while getting information, ignoring."); return 0; diff --git a/src/udev/udevadm-test-builtin.c b/src/udev/udevadm-test-builtin.c index ed71eaa3fa..fdbdb6f59a 100644 --- a/src/udev/udevadm-test-builtin.c +++ b/src/udev/udevadm-test-builtin.c @@ -6,6 +6,8 @@ #include <stdio.h> #include <stdlib.h> +#include "device-private.h" +#include "device-util.h" #include "log.h" #include "udev-builtin.h" #include "udevadm.h" @@ -104,6 +106,15 @@ int builtin_main(int argc, char *argv[], void *userdata) { goto finish; } + if (arg_action != SD_DEVICE_REMOVE) { + /* For net_setup_link */ + r = device_clone_with_db(dev, &event->dev_db_clone); + if (r < 0) { + log_device_error_errno(dev, r, "Failed to clone device: %m"); + goto finish; + } + } + r = udev_builtin_run(event, cmd, arg_command, true); if (r < 0) { log_debug_errno(r, "Builtin command '%s' fails: %m", arg_command); |