From fc53809803cd2bc2434e312b19a18fa36776da12 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Wed, 12 Jun 2024 05:50:40 +0200 Subject: Adding upstream version 256. Signed-off-by: Daniel Baumann --- src/udev/ata_id/ata_id.c | 14 +- src/udev/cdrom_id/cdrom_id.c | 6 +- src/udev/dmi_memory_id/dmi_memory_id.c | 8 +- src/udev/fido_id/fido_id.c | 6 +- src/udev/meson.build | 4 +- src/udev/net/link-config-gperf.gperf | 4 + src/udev/net/link-config.c | 359 +++++++++++++++++++++++++++++++-- src/udev/net/link-config.h | 14 +- src/udev/scsi_id/scsi.h | 12 +- src/udev/scsi_id/scsi_id.c | 19 +- src/udev/test-udev-format.c | 10 +- src/udev/test-udev-rule-runner.c | 12 +- src/udev/test-udev-spawn.c | 10 +- src/udev/udev-builtin-blkid.c | 70 +++---- src/udev/udev-builtin-btrfs.c | 6 +- src/udev/udev-builtin-hwdb.c | 42 ++-- src/udev/udev-builtin-input_id.c | 89 ++++---- src/udev/udev-builtin-keyboard.c | 7 +- src/udev/udev-builtin-kmod.c | 34 ++-- src/udev/udev-builtin-net_driver.c | 4 +- src/udev/udev-builtin-net_id.c | 191 ++++++++---------- src/udev/udev-builtin-net_setup_link.c | 47 +++-- src/udev/udev-builtin-path_id.c | 98 ++++----- src/udev/udev-builtin-uaccess.c | 7 +- src/udev/udev-builtin-usb_id.c | 58 +++--- src/udev/udev-builtin.c | 35 +++- src/udev/udev-builtin.h | 11 +- src/udev/udev-event.c | 146 +++++++++----- src/udev/udev-event.h | 30 ++- src/udev/udev-format.c | 6 +- src/udev/udev-format.h | 1 - src/udev/udev-manager.c | 90 ++++++--- src/udev/udev-manager.h | 1 + src/udev/udev-node.c | 7 +- src/udev/udev-rules.c | 121 +++++------ src/udev/udev-rules.h | 5 +- src/udev/udev-spawn.c | 94 +++++---- src/udev/udev-spawn.h | 7 +- src/udev/udev-watch.c | 5 +- src/udev/udev-worker.c | 37 ++-- src/udev/udev-worker.h | 3 + src/udev/udevadm-control.c | 111 ++++++---- src/udev/udevadm-hwdb.c | 2 +- src/udev/udevadm-info.c | 2 +- src/udev/udevadm-lock.c | 4 +- src/udev/udevadm-monitor.c | 2 +- src/udev/udevadm-test-builtin.c | 18 +- src/udev/udevadm-test.c | 94 +++++++-- src/udev/udevadm-wait.c | 2 +- src/udev/udevadm.c | 2 +- src/udev/udevd.c | 87 ++------ src/udev/v4l_id/v4l_id.c | 10 - 52 files changed, 1287 insertions(+), 777 deletions(-) (limited to 'src/udev') diff --git a/src/udev/ata_id/ata_id.c b/src/udev/ata_id/ata_id.c index 4dd7e54..6baf139 100644 --- a/src/udev/ata_id/ata_id.c +++ b/src/udev/ata_id/ata_id.c @@ -86,14 +86,14 @@ static int disk_scsi_inquiry_command( if (io_hdr.status != 0 || io_hdr.host_status != 0 || io_hdr.driver_status != 0) - return log_debug_errno(SYNTHETIC_ERRNO(EIO), "ioctl v3 failed"); + return log_debug_errno(SYNTHETIC_ERRNO(EIO), "ioctl v3 failed."); } else { /* even if the ioctl succeeds, we need to check the return value */ if (io_v4.device_status != 0 || io_v4.transport_status != 0 || io_v4.driver_status != 0) - return log_debug_errno(SYNTHETIC_ERRNO(EIO), "ioctl v4 failed"); + return log_debug_errno(SYNTHETIC_ERRNO(EIO), "ioctl v4 failed."); } return 0; @@ -160,7 +160,7 @@ static int disk_identify_command( } else { if (!((sense[0] & 0x7f) == 0x72 && desc[0] == 0x9 && desc[1] == 0x0c) && !((sense[0] & 0x7f) == 0x70 && sense[12] == 0x00 && sense[13] == 0x1d)) - return log_debug_errno(SYNTHETIC_ERRNO(EIO), "ioctl v4 failed: %m"); + return log_debug_errno(SYNTHETIC_ERRNO(EIO), "ioctl v4 failed."); } return 0; @@ -232,7 +232,7 @@ static int disk_identify_packet_device_command( return log_debug_errno(errno, "ioctl v3 failed: %m"); } else { if ((sense[0] & 0x7f) != 0x72 || desc[0] != 0x9 || desc[1] != 0x0c) - return log_debug_errno(SYNTHETIC_ERRNO(EIO), "ioctl v4 failed: %m"); + return log_debug_errno(SYNTHETIC_ERRNO(EIO), "ioctl v4 failed."); } return 0; @@ -413,10 +413,8 @@ static int run(int argc, char *argv[]) { uint16_t word; int r, peripheral_device_type = -1; - log_set_target(LOG_TARGET_AUTO); - udev_parse_config(); - log_parse_environment(); - log_open(); + (void) udev_parse_config(); + log_setup(); r = parse_argv(argc, argv); if (r <= 0) diff --git a/src/udev/cdrom_id/cdrom_id.c b/src/udev/cdrom_id/cdrom_id.c index 9285dd8..195fadc 100644 --- a/src/udev/cdrom_id/cdrom_id.c +++ b/src/udev/cdrom_id/cdrom_id.c @@ -959,10 +959,8 @@ static int run(int argc, char *argv[]) { _cleanup_(context_clear) Context c = CONTEXT_EMPTY; int r; - log_set_target(LOG_TARGET_AUTO); - udev_parse_config(); - log_parse_environment(); - log_open(); + (void) udev_parse_config(); + log_setup(); r = parse_argv(argc, argv); if (r <= 0) diff --git a/src/udev/dmi_memory_id/dmi_memory_id.c b/src/udev/dmi_memory_id/dmi_memory_id.c index 3f89cc7..9823df0 100644 --- a/src/udev/dmi_memory_id/dmi_memory_id.c +++ b/src/udev/dmi_memory_id/dmi_memory_id.c @@ -96,7 +96,7 @@ static const char *dmi_string(const struct dmi_header *dm, uint8_t s) { return "Not Specified"; bp += dm->length; - for (;s > 1 && !isempty(bp); s--) + for (; s > 1 && !isempty(bp); s--) bp += strlen(bp) + 1; if (isempty(bp)) @@ -685,10 +685,8 @@ static int run(int argc, char* const* argv) { size_t size; int r; - log_set_target(LOG_TARGET_AUTO); - udev_parse_config(); - log_parse_environment(); - log_open(); + (void) udev_parse_config(); + log_setup(); r = parse_argv(argc, argv); if (r <= 0) diff --git a/src/udev/fido_id/fido_id.c b/src/udev/fido_id/fido_id.c index e01f37d..6c4b099 100644 --- a/src/udev/fido_id/fido_id.c +++ b/src/udev/fido_id/fido_id.c @@ -70,10 +70,8 @@ static int run(int argc, char **argv) { ssize_t desc_len; int r; - log_set_target(LOG_TARGET_AUTO); - udev_parse_config(); - log_parse_environment(); - log_open(); + (void) udev_parse_config(); + log_setup(); r = parse_argv(argc, argv); if (r <= 0) diff --git a/src/udev/meson.build b/src/udev/meson.build index 824ec47..3535551 100644 --- a/src/udev/meson.build +++ b/src/udev/meson.build @@ -114,7 +114,7 @@ libudevd_core = static_library( include_directories : includes + include_directories('net'), link_with : udev_link_with, dependencies : [libblkid, - libkmod, + libkmod_cflags, userspace], build_by_default : false) @@ -205,6 +205,7 @@ executables += [ }, udev_test_template + { 'sources' : files('net/test-link-config-tables.c'), + 'include_directories' : includes + include_directories('.'), 'suite' : 'udev', }, udev_test_template + { @@ -240,6 +241,7 @@ executables += [ }, udev_fuzz_template + { 'sources' : files('net/fuzz-link-parser.c'), + 'include_directories' : includes + include_directories('.'), }, udev_fuzz_template + { 'sources' : files('fuzz-udev-rule-parse-value.c'), diff --git a/src/udev/net/link-config-gperf.gperf b/src/udev/net/link-config-gperf.gperf index 240f16e..b77759d 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) @@ -105,6 +108,7 @@ Link.RxMaxCoalescedHighFrames, config_parse_coalesce_u32, Link.TxCoalesceHighSec, config_parse_coalesce_sec, 0, offsetof(LinkConfig, coalesce.tx_coalesce_usecs_high) Link.TxMaxCoalescedHighFrames, config_parse_coalesce_u32, 0, offsetof(LinkConfig, coalesce.tx_max_coalesced_frames_high) Link.CoalescePacketRateSampleIntervalSec, config_parse_coalesce_sec, 0, offsetof(LinkConfig, coalesce.rate_sample_interval) +Link.ReceivePacketSteeringCPUMask, config_parse_rps_cpu_mask, 0, offsetof(LinkConfig, rps_cpu_mask) Link.MDI, config_parse_mdi, 0, offsetof(LinkConfig, mdi) Link.SR-IOVVirtualFunctions, config_parse_sr_iov_num_vfs, 0, offsetof(LinkConfig, sr_iov_num_vfs) SR-IOV.VirtualFunction, config_parse_sr_iov_uint32, 0, offsetof(LinkConfig, sr_iov_by_section) diff --git a/src/udev/net/link-config.c b/src/udev/net/link-config.c index 910ec27..647cdee 100644 --- a/src/udev/net/link-config.c +++ b/src/udev/net/link-config.c @@ -15,6 +15,8 @@ #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" #include "fileio.h" @@ -30,12 +32,20 @@ #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" #include "strv.h" +#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; @@ -53,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); @@ -60,6 +73,7 @@ static LinkConfig* link_config_free(LinkConfig *config) { free(config->alias); free(config->wol_password_file); erase_and_free(config->wol_password); + cpu_set_free(config->rps_cpu_mask); ordered_hashmap_free_with_destructor(config->sr_iov_by_section, sr_iov_free); @@ -363,18 +377,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); @@ -383,6 +399,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); @@ -466,7 +483,7 @@ int link_get_config(LinkConfigContext *ctx, Link *link) { return -ENOENT; } -static int link_apply_ethtool_settings(Link *link, int *ethtool_fd) { +static int link_apply_ethtool_settings(Link *link, int *ethtool_fd, EventMode mode) { LinkConfig *config; const char *name; int r; @@ -475,6 +492,11 @@ static int link_apply_ethtool_settings(Link *link, int *ethtool_fd) { assert(link->config); assert(ethtool_fd); + if (mode != EVENT_UDEV_WORKER) { + log_link_debug(link, "Running in test mode, skipping application of ethtool settings."); + return 0; + } + config = link->config; name = link->ifname; @@ -667,7 +689,7 @@ finalize: return 0; } -static int link_apply_rtnl_settings(Link *link, sd_netlink **rtnl) { +static int link_apply_rtnl_settings(Link *link, sd_netlink **rtnl, EventMode mode) { struct hw_addr_data hw_addr = {}; LinkConfig *config; int r; @@ -676,6 +698,11 @@ static int link_apply_rtnl_settings(Link *link, sd_netlink **rtnl) { assert(link->config); assert(rtnl); + if (mode != EVENT_UDEV_WORKER) { + log_link_debug(link, "Running in test mode, skipping application of rtnl settings."); + return 0; + } + config = link->config; (void) link_generate_new_hw_addr(link, &hw_addr); @@ -725,7 +752,7 @@ static int link_generate_new_name(Link *link) { device = link->device; if (link->action != SD_DEVICE_ADD) { - log_link_debug(link, "Skipping to apply Name= and NamePolicy= on '%s' uevent.", + log_link_debug(link, "Not applying Name= and NamePolicy= on '%s' uevent.", device_action_to_string(link->action)); goto no_rename; } @@ -805,7 +832,7 @@ static int link_generate_alternative_names(Link *link) { assert(!link->altnames); if (link->action != SD_DEVICE_ADD) { - log_link_debug(link, "Skipping to apply AlternativeNames= and AlternativeNamesPolicy= on '%s' uevent.", + log_link_debug(link, "Not applying AlternativeNames= and AlternativeNamesPolicy= on '%s' uevent.", device_action_to_string(link->action)); return 0; } @@ -879,7 +906,7 @@ static int sr_iov_configure(Link *link, sd_netlink **rtnl, SRIOV *sr_iov) { return 0; } -static int link_apply_sr_iov_config(Link *link, sd_netlink **rtnl) { +static int link_apply_sr_iov_config(Link *link, sd_netlink **rtnl, EventMode mode) { SRIOV *sr_iov; uint32_t n; int r; @@ -888,6 +915,11 @@ static int link_apply_sr_iov_config(Link *link, sd_netlink **rtnl) { assert(link->config); assert(link->device); + if (mode != EVENT_UDEV_WORKER) { + log_link_debug(link, "Running in test mode, skipping application of SR-IOV settings."); + return 0; + } + r = sr_iov_set_num_vfs(link->device, link->config->sr_iov_num_vfs, link->config->sr_iov_by_section); if (r < 0) log_link_warning_errno(link, r, "Failed to set the number of SR-IOV virtual functions, ignoring: %m"); @@ -921,26 +953,122 @@ static int link_apply_sr_iov_config(Link *link, sd_netlink **rtnl) { return 0; } -int link_apply_config(LinkConfigContext *ctx, sd_netlink **rtnl, Link *link) { +static int link_apply_rps_cpu_mask(Link *link, EventMode mode) { + _cleanup_free_ char *mask_str = NULL; + LinkConfig *config; int r; - assert(ctx); - assert(rtnl); assert(link); + config = ASSERT_PTR(link->config); - if (!IN_SET(link->action, SD_DEVICE_ADD, SD_DEVICE_BIND, SD_DEVICE_MOVE)) { - log_link_debug(link, "Skipping to apply .link settings on '%s' uevent.", - device_action_to_string(link->action)); + if (mode != EVENT_UDEV_WORKER) { + log_link_debug(link, "Running in test mode, skipping application of RPS setting."); + return 0; + } - link->new_name = link->ifname; + /* Skip if the config is not specified. */ + if (!config->rps_cpu_mask) return 0; + + mask_str = cpu_set_to_mask_string(config->rps_cpu_mask); + if (!mask_str) + return log_oom(); + + log_link_debug(link, "Applying RPS CPU mask: %s", mask_str); + + /* Currently, this will set CPU mask to all rx queue of matched device. */ + FOREACH_DEVICE_SYSATTR(link->device, attr) { + const char *c; + + c = path_startswith(attr, "queues/"); + if (!c) + continue; + + c = startswith(c, "rx-"); + if (!c) + continue; + + c += strcspn(c, "/"); + + if (!path_equal(c, "/rps_cpus")) + continue; + + r = sd_device_set_sysattr_value(link->device, attr, mask_str); + if (r < 0) + log_link_warning_errno(link, r, "Failed to write %s sysfs attribute, ignoring: %m", attr); + } + + return 0; +} + +static int link_apply_udev_properties(Link *link, EventMode mode) { + LinkConfig *config; + sd_device *device; + + assert(link); + + 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, mode, *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, mode, key, eq + 1); + } + + /* 3. apply UnsetProperty=. */ + STRV_FOREACH(p, config->unset_properties) + (void) udev_builtin_add_property(device, mode, *p, NULL); + + /* 4. set the default properties. */ + (void) udev_builtin_add_property(device, mode, "ID_NET_LINK_FILE", config->filename); + + _cleanup_free_ char *joined = NULL; + STRV_FOREACH(d, config->dropins) { + _cleanup_free_ char *escaped = NULL; + + escaped = xescape(*d, ":"); + if (!escaped) + return log_oom(); + + if (!strextend_with_separator(&joined, ":", escaped)) + return log_oom(); } - r = link_apply_ethtool_settings(link, &ctx->ethtool_fd); + (void) udev_builtin_add_property(device, mode, "ID_NET_LINK_FILE_DROPINS", joined); + + if (link->new_name) + (void) udev_builtin_add_property(device, mode, "ID_NET_NAME", link->new_name); + + return 0; +} + +int link_apply_config(LinkConfigContext *ctx, sd_netlink **rtnl, Link *link, EventMode mode) { + int r; + + assert(ctx); + assert(rtnl); + assert(link); + + r = link_apply_ethtool_settings(link, &ctx->ethtool_fd, mode); if (r < 0) return r; - r = link_apply_rtnl_settings(link, rtnl); + r = link_apply_rtnl_settings(link, rtnl, mode); if (r < 0) return r; @@ -952,11 +1080,151 @@ int link_apply_config(LinkConfigContext *ctx, sd_netlink **rtnl, Link *link) { if (r < 0) return r; - r = link_apply_sr_iov_config(link, rtnl); + r = link_apply_sr_iov_config(link, rtnl, mode); if (r < 0) return r; - return 0; + r = link_apply_rps_cpu_mask(link, mode); + if (r < 0) + return r; + + return link_apply_udev_properties(link, mode); +} + +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( @@ -1110,6 +1378,63 @@ int config_parse_wol_password( return 0; } +int config_parse_rps_cpu_mask( + 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) { + + _cleanup_(cpu_set_freep) CPUSet *allocated = NULL; + CPUSet *mask, **rps_cpu_mask = ASSERT_PTR(data); + int r; + + assert(filename); + assert(lvalue); + assert(rvalue); + + if (isempty(rvalue)) { + *rps_cpu_mask = cpu_set_free(*rps_cpu_mask); + return 0; + } + + if (*rps_cpu_mask) + mask = *rps_cpu_mask; + else { + allocated = new0(CPUSet, 1); + if (!allocated) + return log_oom(); + + mask = allocated; + } + + if (streq(rvalue, "disable")) + cpu_set_reset(mask); + + else if (streq(rvalue, "all")) { + r = cpu_mask_add_all(mask); + if (r < 0) { + log_syntax(unit, LOG_WARNING, filename, line, r, + "Failed to create CPU affinity mask representing \"all\" cpus, ignoring: %m"); + return 0; + } + } else { + r = parse_cpu_set_extend(rvalue, mask, /* warn= */ true, unit, filename, line, lvalue); + if (r < 0) + return 0; + } + + if (allocated) + *rps_cpu_mask = TAKE_PTR(allocated); + + return 0; +} + static const char* const mac_address_policy_table[_MAC_ADDRESS_POLICY_MAX] = { [MAC_ADDRESS_POLICY_PERSISTENT] = "persistent", [MAC_ADDRESS_POLICY_RANDOM] = "random", diff --git a/src/udev/net/link-config.h b/src/udev/net/link-config.h index bab9d12..103343f 100644 --- a/src/udev/net/link-config.h +++ b/src/udev/net/link-config.h @@ -6,11 +6,13 @@ #include "condition.h" #include "conf-parser.h" +#include "cpu-set-util.h" #include "ethtool-util.h" #include "hashmap.h" #include "list.h" #include "net-condition.h" #include "netif-naming-scheme.h" +#include "udev-event.h" typedef struct LinkConfigContext LinkConfigContext; typedef struct LinkConfig LinkConfig; @@ -31,6 +33,7 @@ typedef struct Link { LinkConfig *config; sd_device *device; + sd_device *device_db_clone; sd_device_action_t action; char *kind; @@ -51,6 +54,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; @@ -80,6 +86,7 @@ struct LinkConfig { int autoneg_flow_control; netdev_coalesce_param coalesce; uint8_t mdi; + CPUSet *rps_cpu_mask; uint32_t sr_iov_num_vfs; OrderedHashmap *sr_iov_by_section; @@ -95,12 +102,12 @@ 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); int link_get_config(LinkConfigContext *ctx, Link *link); -int link_apply_config(LinkConfigContext *ctx, sd_netlink **rtnl, Link *link); +int link_apply_config(LinkConfigContext *ctx, sd_netlink **rtnl, Link *link, EventMode mode); const char *mac_address_policy_to_string(MACAddressPolicy p) _const_; MACAddressPolicy mac_address_policy_from_string(const char *p) _pure_; @@ -108,6 +115,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); @@ -115,3 +124,4 @@ CONFIG_PARSER_PROTOTYPE(config_parse_wol_password); CONFIG_PARSER_PROTOTYPE(config_parse_mac_address_policy); CONFIG_PARSER_PROTOTYPE(config_parse_name_policy); CONFIG_PARSER_PROTOTYPE(config_parse_alternative_names_policy); +CONFIG_PARSER_PROTOTYPE(config_parse_rps_cpu_mask); diff --git a/src/udev/scsi_id/scsi.h b/src/udev/scsi_id/scsi.h index ee3e401..ebb8ae9 100644 --- a/src/udev/scsi_id/scsi.h +++ b/src/udev/scsi_id/scsi.h @@ -1,17 +1,7 @@ /* SPDX-License-Identifier: GPL-2.0-or-later */ #pragma once -/* - * scsi.h - * - * General scsi and linux scsi specific defines and structs. - * - * Copyright (C) IBM Corp. 2003 - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation version 2 of the License. - */ +/* Copyright (C) IBM Corp. 2003 */ #include diff --git a/src/udev/scsi_id/scsi_id.c b/src/udev/scsi_id/scsi_id.c index 6308c52..b63a46a 100644 --- a/src/udev/scsi_id/scsi_id.c +++ b/src/udev/scsi_id/scsi_id.c @@ -84,6 +84,13 @@ static void set_type(unsigned type_num, char *to, size_t len) { case 0xf: type = "optical"; break; + case 0x14: + /* + * Use "zbc" here to be brief and consistent with "lsscsi" command. + * Other tools, e.g., "sg3_utils" would say "host managed zoned block". + */ + type = "zbc"; + break; default: type = "generic"; break; @@ -144,7 +151,7 @@ static int get_file_options(const char *vendor, const char *model, if (*buf == '#') continue; - r = extract_many_words(&buf, "=\",\n", 0, &key, &value, NULL); + r = extract_many_words(&buf, "=\",\n", 0, &key, &value); if (r < 2) return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Error parsing config file line %d '%s'", lineno, buffer); @@ -152,7 +159,7 @@ static int get_file_options(const char *vendor, const char *model, vendor_in = TAKE_PTR(value); key = mfree(key); - r = extract_many_words(&buf, "=\",\n", 0, &key, &value, NULL); + r = extract_many_words(&buf, "=\",\n", 0, &key, &value); if (r < 2) return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Error parsing config file line %d '%s'", lineno, buffer); @@ -160,7 +167,7 @@ static int get_file_options(const char *vendor, const char *model, model_in = TAKE_PTR(value); key = mfree(key); - r = extract_many_words(&buf, "=\",\n", 0, &key, &value, NULL); + r = extract_many_words(&buf, "=\",\n", 0, &key, &value); if (r < 2) return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Error parsing config file line %d '%s'", lineno, buffer); } @@ -473,10 +480,8 @@ int main(int argc, char **argv) { char maj_min_dev[MAX_PATH_LEN]; int newargc; - log_set_target(LOG_TARGET_AUTO); - udev_parse_config(); - log_parse_environment(); - log_open(); + (void) udev_parse_config(); + log_setup(); /* * Get config file options. diff --git a/src/udev/test-udev-format.c b/src/udev/test-udev-format.c index d8e3808..7eacb6b 100644 --- a/src/udev/test-udev-format.c +++ b/src/udev/test-udev-format.c @@ -1,5 +1,6 @@ /* SPDX-License-Identifier: LGPL-2.1-or-later */ +#include "mountpoint-util.h" #include "string-util.h" #include "tests.h" #include "udev-format.h" @@ -34,4 +35,11 @@ TEST(udev_resolve_subsys_kernel) { test_udev_resolve_subsys_kernel_one("[net/lo]/address", true, 0, "00:00:00:00:00:00"); } -DEFINE_TEST_MAIN(LOG_DEBUG); +static int intro(void) { + if (path_is_mount_point("/sys") <= 0) + return log_tests_skipped("/sys is not mounted"); + + return EXIT_SUCCESS; +} + +DEFINE_TEST_MAIN_WITH_INTRO(LOG_DEBUG, intro); diff --git a/src/udev/test-udev-rule-runner.c b/src/udev/test-udev-rule-runner.c index 72296b3..10da645 100644 --- a/src/udev/test-udev-rule-runner.c +++ b/src/udev/test-udev-rule-runner.c @@ -12,6 +12,7 @@ #include #include "device-private.h" +#include "device-util.h" #include "fs-util.h" #include "log.h" #include "main-func.h" @@ -141,16 +142,15 @@ static int run(int argc, char *argv[]) { if (r < 0) return log_debug_errno(r, "Failed to open device '%s'", devpath); - assert_se(event = udev_event_new(dev, 0, NULL, log_get_max_level())); + assert_se(event = udev_event_new(dev, NULL, EVENT_TEST_RULE_RUNNER)); - assert_se(sigprocmask_many(SIG_BLOCK, NULL, SIGTERM, SIGINT, SIGHUP, SIGCHLD, -1) >= 0); + assert_se(sigprocmask_many(SIG_BLOCK, NULL, SIGTERM, SIGINT, SIGHUP, SIGCHLD) >= 0); /* do what devtmpfs usually provides us */ if (sd_device_get_devname(dev, &devname) >= 0) { - const char *subsystem; mode_t mode = 0600; - if (sd_device_get_subsystem(dev, &subsystem) >= 0 && streq(subsystem, "block")) + if (device_in_subsystem(dev, "block")) mode |= S_IFBLK; else mode |= S_IFCHR; @@ -169,8 +169,8 @@ static int run(int argc, char *argv[]) { } } - udev_event_execute_rules(event, -1, 3 * USEC_PER_SEC, SIGKILL, NULL, rules); - udev_event_execute_run(event, 3 * USEC_PER_SEC, SIGKILL); + udev_event_execute_rules(event, rules); + udev_event_execute_run(event); return 0; } diff --git a/src/udev/test-udev-spawn.c b/src/udev/test-udev-spawn.c index 4f43fac..7cbccf3 100644 --- a/src/udev/test-udev-spawn.c +++ b/src/udev/test-udev-spawn.c @@ -1,5 +1,6 @@ /* SPDX-License-Identifier: LGPL-2.1-or-later */ +#include "mountpoint-util.h" #include "path-util.h" #include "signal-util.h" #include "strv.h" @@ -16,8 +17,8 @@ static void test_event_spawn_core(bool with_pidfd, const char *cmd, char *result assert_se(setenv("SYSTEMD_PIDFD", yes_no(with_pidfd), 1) >= 0); assert_se(sd_device_new_from_syspath(&dev, "/sys/class/net/lo") >= 0); - assert_se(event = udev_event_new(dev, 0, NULL, LOG_DEBUG)); - assert_se(udev_event_spawn(event, 5 * USEC_PER_SEC, SIGKILL, false, cmd, result_buf, buf_size, NULL) == 0); + assert_se(event = udev_event_new(dev, NULL, EVENT_TEST_SPAWN)); + assert_se(udev_event_spawn(event, false, cmd, result_buf, buf_size, NULL) == 0); assert_se(unsetenv("SYSTEMD_PIDFD") >= 0); } @@ -80,6 +81,9 @@ static void test2(void) { int main(int argc, char *argv[]) { _cleanup_free_ char *self = NULL; + if (path_is_mount_point("/sys") <= 0) + return log_tests_skipped("/sys is not mounted"); + if (argc > 1) { if (streq(argv[1], "test1")) test1(); @@ -93,7 +97,7 @@ int main(int argc, char *argv[]) { test_setup_logging(LOG_DEBUG); - assert_se(sigprocmask_many(SIG_BLOCK, NULL, SIGCHLD, -1) >= 0); + assert_se(sigprocmask_many(SIG_BLOCK, NULL, SIGCHLD) >= 0); test_event_spawn_cat(true, SIZE_MAX); test_event_spawn_cat(false, SIZE_MAX); diff --git a/src/udev/udev-builtin-blkid.c b/src/udev/udev-builtin-blkid.c index 11419a3..4d13035 100644 --- a/src/udev/udev-builtin-blkid.c +++ b/src/udev/udev-builtin-blkid.c @@ -34,95 +34,95 @@ #include "strxcpyx.h" #include "udev-builtin.h" -static void print_property(sd_device *dev, bool test, const char *name, const char *value) { +static void print_property(sd_device *dev, EventMode mode, const char *name, const char *value) { char s[256]; s[0] = '\0'; if (streq(name, "TYPE")) { - udev_builtin_add_property(dev, test, "ID_FS_TYPE", value); + udev_builtin_add_property(dev, mode, "ID_FS_TYPE", value); } else if (streq(name, "USAGE")) { - udev_builtin_add_property(dev, test, "ID_FS_USAGE", value); + udev_builtin_add_property(dev, mode, "ID_FS_USAGE", value); } else if (streq(name, "VERSION")) { - udev_builtin_add_property(dev, test, "ID_FS_VERSION", value); + udev_builtin_add_property(dev, mode, "ID_FS_VERSION", value); } else if (streq(name, "UUID")) { blkid_safe_string(value, s, sizeof(s)); - udev_builtin_add_property(dev, test, "ID_FS_UUID", s); + udev_builtin_add_property(dev, mode, "ID_FS_UUID", s); blkid_encode_string(value, s, sizeof(s)); - udev_builtin_add_property(dev, test, "ID_FS_UUID_ENC", s); + udev_builtin_add_property(dev, mode, "ID_FS_UUID_ENC", s); } else if (streq(name, "UUID_SUB")) { blkid_safe_string(value, s, sizeof(s)); - udev_builtin_add_property(dev, test, "ID_FS_UUID_SUB", s); + udev_builtin_add_property(dev, mode, "ID_FS_UUID_SUB", s); blkid_encode_string(value, s, sizeof(s)); - udev_builtin_add_property(dev, test, "ID_FS_UUID_SUB_ENC", s); + udev_builtin_add_property(dev, mode, "ID_FS_UUID_SUB_ENC", s); } else if (streq(name, "LABEL")) { blkid_safe_string(value, s, sizeof(s)); - udev_builtin_add_property(dev, test, "ID_FS_LABEL", s); + udev_builtin_add_property(dev, mode, "ID_FS_LABEL", s); blkid_encode_string(value, s, sizeof(s)); - udev_builtin_add_property(dev, test, "ID_FS_LABEL_ENC", s); + udev_builtin_add_property(dev, mode, "ID_FS_LABEL_ENC", s); } else if (STR_IN_SET(name, "FSSIZE", "FSLASTBLOCK", "FSBLOCKSIZE")) { strscpyl(s, sizeof(s), "ID_FS_", name + 2, NULL); - udev_builtin_add_property(dev, test, s, value); + udev_builtin_add_property(dev, mode, s, value); } else if (streq(name, "PTTYPE")) { - udev_builtin_add_property(dev, test, "ID_PART_TABLE_TYPE", value); + udev_builtin_add_property(dev, mode, "ID_PART_TABLE_TYPE", value); } else if (streq(name, "PTUUID")) { - udev_builtin_add_property(dev, test, "ID_PART_TABLE_UUID", value); + udev_builtin_add_property(dev, mode, "ID_PART_TABLE_UUID", value); } else if (streq(name, "PART_ENTRY_NAME")) { blkid_encode_string(value, s, sizeof(s)); - udev_builtin_add_property(dev, test, "ID_PART_ENTRY_NAME", s); + udev_builtin_add_property(dev, mode, "ID_PART_ENTRY_NAME", s); } else if (streq(name, "PART_ENTRY_TYPE")) { blkid_encode_string(value, s, sizeof(s)); - udev_builtin_add_property(dev, test, "ID_PART_ENTRY_TYPE", s); + udev_builtin_add_property(dev, mode, "ID_PART_ENTRY_TYPE", s); } else if (startswith(name, "PART_ENTRY_")) { strscpyl(s, sizeof(s), "ID_", name, NULL); - udev_builtin_add_property(dev, test, s, value); + udev_builtin_add_property(dev, mode, s, value); } else if (streq(name, "SYSTEM_ID")) { blkid_encode_string(value, s, sizeof(s)); - udev_builtin_add_property(dev, test, "ID_FS_SYSTEM_ID", s); + udev_builtin_add_property(dev, mode, "ID_FS_SYSTEM_ID", s); } else if (streq(name, "PUBLISHER_ID")) { blkid_encode_string(value, s, sizeof(s)); - udev_builtin_add_property(dev, test, "ID_FS_PUBLISHER_ID", s); + udev_builtin_add_property(dev, mode, "ID_FS_PUBLISHER_ID", s); } else if (streq(name, "APPLICATION_ID")) { blkid_encode_string(value, s, sizeof(s)); - udev_builtin_add_property(dev, test, "ID_FS_APPLICATION_ID", s); + udev_builtin_add_property(dev, mode, "ID_FS_APPLICATION_ID", s); } else if (streq(name, "BOOT_SYSTEM_ID")) { blkid_encode_string(value, s, sizeof(s)); - udev_builtin_add_property(dev, test, "ID_FS_BOOT_SYSTEM_ID", s); + udev_builtin_add_property(dev, mode, "ID_FS_BOOT_SYSTEM_ID", s); } else if (streq(name, "VOLUME_ID")) { blkid_encode_string(value, s, sizeof(s)); - udev_builtin_add_property(dev, test, "ID_FS_VOLUME_ID", s); + udev_builtin_add_property(dev, mode, "ID_FS_VOLUME_ID", s); } else if (streq(name, "LOGICAL_VOLUME_ID")) { blkid_encode_string(value, s, sizeof(s)); - udev_builtin_add_property(dev, test, "ID_FS_LOGICAL_VOLUME_ID", s); + udev_builtin_add_property(dev, mode, "ID_FS_LOGICAL_VOLUME_ID", s); } else if (streq(name, "VOLUME_SET_ID")) { blkid_encode_string(value, s, sizeof(s)); - udev_builtin_add_property(dev, test, "ID_FS_VOLUME_SET_ID", s); + udev_builtin_add_property(dev, mode, "ID_FS_VOLUME_SET_ID", s); } else if (streq(name, "DATA_PREPARER_ID")) { blkid_encode_string(value, s, sizeof(s)); - udev_builtin_add_property(dev, test, "ID_FS_DATA_PREPARER_ID", s); + udev_builtin_add_property(dev, mode, "ID_FS_DATA_PREPARER_ID", s); } } -static int find_gpt_root(sd_device *dev, blkid_probe pr, bool test) { +static int find_gpt_root(sd_device *dev, blkid_probe pr, EventMode mode) { #if defined(SD_GPT_ROOT_NATIVE) && ENABLE_EFI @@ -201,7 +201,7 @@ static int find_gpt_root(sd_device *dev, blkid_probe pr, bool test) { /* We found the ESP/XBOOTLDR on this disk, and also found a root partition, nice! Let's export its * UUID */ if (found_esp_or_xbootldr && !sd_id128_is_null(root_id)) - udev_builtin_add_property(dev, test, "ID_PART_GPT_AUTO_ROOT_UUID", SD_ID128_TO_UUID_STRING(root_id)); + udev_builtin_add_property(dev, mode, "ID_PART_GPT_AUTO_ROOT_UUID", SD_ID128_TO_UUID_STRING(root_id)); #endif return 0; @@ -315,7 +315,7 @@ notloop: return 0; } -static int builtin_blkid(UdevEvent *event, int argc, char *argv[], bool test) { +static int builtin_blkid(UdevEvent *event, int argc, char *argv[]) { sd_device *dev = ASSERT_PTR(ASSERT_PTR(event)->dev); const char *devnode, *root_partition = NULL, *data, *name; _cleanup_(blkid_free_probep) blkid_probe pr = NULL; @@ -368,7 +368,7 @@ static int builtin_blkid(UdevEvent *event, int argc, char *argv[], bool test) { if (r < 0) return log_device_error_errno(dev, r, "Failed to parse '%s' as an integer: %m", optarg); if (offset < 0) - return log_device_error_errno(dev, SYNTHETIC_ERRNO(EINVAL), "Invalid offset %"PRIi64": %m", offset); + return log_device_error_errno(dev, SYNTHETIC_ERRNO(EINVAL), "Invalid offset %"PRIi64".", offset); break; case 'R': noraid = true; @@ -422,7 +422,7 @@ static int builtin_blkid(UdevEvent *event, int argc, char *argv[], bool test) { if (blkid_probe_get_value(pr, i, &name, &data, NULL) < 0) continue; - print_property(dev, test, name, data); + print_property(dev, event->event_mode, name, data); /* Is this a disk with GPT partition table? */ if (streq(name, "PTTYPE") && streq(data, "gpt")) @@ -431,11 +431,11 @@ static int builtin_blkid(UdevEvent *event, int argc, char *argv[], bool test) { /* Is this a partition that matches the root partition * property inherited from the parent? */ if (root_partition && streq(name, "PART_ENTRY_UUID") && streq(data, root_partition)) - udev_builtin_add_property(dev, test, "ID_PART_GPT_AUTO_ROOT", "1"); + udev_builtin_add_property(dev, event->event_mode, "ID_PART_GPT_AUTO_ROOT", "1"); } if (is_gpt) - find_gpt_root(dev, pr, test); + find_gpt_root(dev, pr, event->event_mode); r = read_loopback_backing_inode( dev, @@ -446,8 +446,8 @@ static int builtin_blkid(UdevEvent *event, int argc, char *argv[], bool test) { if (r < 0) log_device_debug_errno(dev, r, "Failed to read loopback backing inode, ignoring: %m"); else if (r > 0) { - udev_builtin_add_propertyf(dev, test, "ID_LOOP_BACKING_DEVICE", DEVNUM_FORMAT_STR, DEVNUM_FORMAT_VAL(backing_devno)); - udev_builtin_add_propertyf(dev, test, "ID_LOOP_BACKING_INODE", "%" PRIu64, (uint64_t) backing_inode); + udev_builtin_add_propertyf(dev, event->event_mode, "ID_LOOP_BACKING_DEVICE", DEVNUM_FORMAT_STR, DEVNUM_FORMAT_VAL(backing_devno)); + udev_builtin_add_propertyf(dev, event->event_mode, "ID_LOOP_BACKING_INODE", "%" PRIu64, (uint64_t) backing_inode); if (backing_fname) { /* In the worst case blkid_encode_string() will blow up to 4x the string @@ -458,8 +458,8 @@ static int builtin_blkid(UdevEvent *event, int argc, char *argv[], bool test) { assert(strlen(backing_fname) < ELEMENTSOF(encoded) / 4); blkid_encode_string(backing_fname, encoded, ELEMENTSOF(encoded)); - udev_builtin_add_property(dev, test, "ID_LOOP_BACKING_FILENAME", backing_fname); - udev_builtin_add_property(dev, test, "ID_LOOP_BACKING_FILENAME_ENC", encoded); + udev_builtin_add_property(dev, event->event_mode, "ID_LOOP_BACKING_FILENAME", backing_fname); + udev_builtin_add_property(dev, event->event_mode, "ID_LOOP_BACKING_FILENAME_ENC", encoded); } } diff --git a/src/udev/udev-builtin-btrfs.c b/src/udev/udev-builtin-btrfs.c index 9b12aeb..fe030d0 100644 --- a/src/udev/udev-builtin-btrfs.c +++ b/src/udev/udev-builtin-btrfs.c @@ -12,7 +12,7 @@ #include "strxcpyx.h" #include "udev-builtin.h" -static int builtin_btrfs(UdevEvent *event, int argc, char *argv[], bool test) { +static int builtin_btrfs(UdevEvent *event, int argc, char *argv[]) { sd_device *dev = ASSERT_PTR(ASSERT_PTR(event)->dev); struct btrfs_ioctl_vol_args args = {}; _cleanup_close_ int fd = -EBADF; @@ -27,7 +27,7 @@ static int builtin_btrfs(UdevEvent *event, int argc, char *argv[], bool test) { /* Driver not installed? Then we aren't ready. This is useful in initrds that lack * btrfs.ko. After the host transition (where btrfs.ko will hopefully become * available) the device can be retriggered and will then be considered ready. */ - udev_builtin_add_property(dev, test, "ID_BTRFS_READY", "0"); + udev_builtin_add_property(dev, event->event_mode, "ID_BTRFS_READY", "0"); return 0; } @@ -39,7 +39,7 @@ static int builtin_btrfs(UdevEvent *event, int argc, char *argv[], bool test) { if (r < 0) return log_device_debug_errno(dev, errno, "Failed to call BTRFS_IOC_DEVICES_READY: %m"); - udev_builtin_add_property(dev, test, "ID_BTRFS_READY", one_zero(r == 0)); + udev_builtin_add_property(dev, event->event_mode, "ID_BTRFS_READY", one_zero(r == 0)); return 0; } diff --git a/src/udev/udev-builtin-hwdb.c b/src/udev/udev-builtin-hwdb.c index 19e07e7..e33a7fe 100644 --- a/src/udev/udev-builtin-hwdb.c +++ b/src/udev/udev-builtin-hwdb.c @@ -17,9 +17,13 @@ static sd_hwdb *hwdb; -int udev_builtin_hwdb_lookup(sd_device *dev, - const char *prefix, const char *modalias, - const char *filter, bool test) { +int udev_builtin_hwdb_lookup( + sd_device *dev, + const char *prefix, + const char *modalias, + const char *filter, + EventMode mode) { + _cleanup_free_ char *lookup = NULL; const char *key, *value; int n = 0, r; @@ -38,7 +42,7 @@ int udev_builtin_hwdb_lookup(sd_device *dev, if (filter && fnmatch(filter, key, FNM_NOESCAPE) != 0) continue; - r = udev_builtin_add_property(dev, test, key, value); + r = udev_builtin_add_property(dev, mode, key, value); if (r < 0) return r; n++; @@ -64,9 +68,14 @@ static const char *modalias_usb(sd_device *dev, char *s, size_t size) { return s; } -static int udev_builtin_hwdb_search(sd_device *dev, sd_device *srcdev, - const char *subsystem, const char *prefix, - const char *filter, bool test) { +static int udev_builtin_hwdb_search( + sd_device *dev, + sd_device *srcdev, + const char *subsystem, + const char *prefix, + const char *filter, + EventMode mode) { + char s[LINE_MAX]; bool last = false; int r = 0; @@ -77,20 +86,15 @@ static int udev_builtin_hwdb_search(sd_device *dev, sd_device *srcdev, srcdev = dev; for (sd_device *d = srcdev; d; ) { - const char *dsubsys, *devtype, *modalias = NULL; - - if (sd_device_get_subsystem(d, &dsubsys) < 0) - goto next; + const char *modalias = NULL; /* look only at devices of a specific subsystem */ - if (subsystem && !streq(dsubsys, subsystem)) + if (subsystem && !device_in_subsystem(d, subsystem)) goto next; (void) sd_device_get_property_value(d, "MODALIAS", &modalias); - if (streq(dsubsys, "usb") && - sd_device_get_devtype(d, &devtype) >= 0 && - streq(devtype, "usb_device")) { + if (device_in_subsystem(d, "usb") && device_is_devtype(d, "usb_device")) { /* if the usb_device does not have a modalias, compose one */ if (!modalias) modalias = modalias_usb(d, s, sizeof(s)); @@ -104,7 +108,7 @@ static int udev_builtin_hwdb_search(sd_device *dev, sd_device *srcdev, log_device_debug(dev, "hwdb modalias key: \"%s\"", modalias); - r = udev_builtin_hwdb_lookup(dev, prefix, modalias, filter, test); + r = udev_builtin_hwdb_lookup(dev, prefix, modalias, filter, mode); if (r > 0) break; @@ -118,7 +122,7 @@ next: return r; } -static int builtin_hwdb(UdevEvent *event, int argc, char *argv[], bool test) { +static int builtin_hwdb(UdevEvent *event, int argc, char *argv[]) { static const struct option options[] = { { "filter", required_argument, NULL, 'f' }, { "device", required_argument, NULL, 'd' }, @@ -165,7 +169,7 @@ static int builtin_hwdb(UdevEvent *event, int argc, char *argv[], bool test) { /* query a specific key given as argument */ if (argv[optind]) { - r = udev_builtin_hwdb_lookup(dev, prefix, argv[optind], filter, test); + r = udev_builtin_hwdb_lookup(dev, prefix, argv[optind], filter, event->event_mode); if (r < 0) return log_device_debug_errno(dev, r, "Failed to look up hwdb: %m"); if (r == 0) @@ -180,7 +184,7 @@ static int builtin_hwdb(UdevEvent *event, int argc, char *argv[], bool test) { return log_device_debug_errno(dev, r, "Failed to create sd_device object '%s': %m", device); } - r = udev_builtin_hwdb_search(dev, srcdev, subsystem, prefix, filter, test); + r = udev_builtin_hwdb_search(dev, srcdev, subsystem, prefix, filter, event->event_mode); if (r < 0) return log_device_debug_errno(dev, r, "Failed to look up hwdb: %m"); if (r == 0) diff --git a/src/udev/udev-builtin-input_id.c b/src/udev/udev-builtin-input_id.c index 295e8d2..6f75d9d 100644 --- a/src/udev/udev-builtin-input_id.c +++ b/src/udev/udev-builtin-input_id.c @@ -44,7 +44,7 @@ static int abs_size_mm(const struct input_absinfo *absinfo) { return (absinfo->maximum - absinfo->minimum) / absinfo->resolution; } -static void extract_info(sd_device *dev, bool test) { +static void extract_info(sd_device *dev, EventMode mode) { char width[DECIMAL_STR_MAX(int)], height[DECIMAL_STR_MAX(int)]; struct input_absinfo xabsinfo = {}, yabsinfo = {}; _cleanup_close_ int fd = -EBADF; @@ -63,8 +63,8 @@ static void extract_info(sd_device *dev, bool test) { xsprintf(width, "%d", abs_size_mm(&xabsinfo)); xsprintf(height, "%d", abs_size_mm(&yabsinfo)); - udev_builtin_add_property(dev, test, "ID_INPUT_WIDTH_MM", width); - udev_builtin_add_property(dev, test, "ID_INPUT_HEIGHT_MM", height); + udev_builtin_add_property(dev, mode, "ID_INPUT_WIDTH_MM", width); + udev_builtin_add_property(dev, mode, "ID_INPUT_HEIGHT_MM", height); } /* @@ -73,9 +73,13 @@ static void extract_info(sd_device *dev, bool test) { * @param attr sysfs attribute name (e. g. "capabilities/key") * @param bitmask: Output array which has a sizeof of bitmask_size */ -static void get_cap_mask(sd_device *pdev, const char* attr, - unsigned long *bitmask, size_t bitmask_size, - bool test) { +static void get_cap_mask( + sd_device *pdev, + const char* attr, + unsigned long *bitmask, + size_t bitmask_size, + EventMode mode) { + const char *v; char text[4096]; unsigned i; @@ -110,7 +114,7 @@ static void get_cap_mask(sd_device *pdev, const char* attr, else log_device_debug(pdev, "Ignoring %s block %lX which is larger than maximum size", attr, val); - if (test && DEBUG_LOGGING) { + if (mode == EVENT_UDEVADM_TEST_BUILTIN && DEBUG_LOGGING) { log_device_debug(pdev, "%s decoded bit map:", attr); val = bitmask_size / sizeof (unsigned long); @@ -144,14 +148,16 @@ static struct input_id get_input_id(sd_device *dev) { } /* pointer devices */ -static bool test_pointers(sd_device *dev, - const struct input_id *id, - const unsigned long* bitmask_ev, - const unsigned long* bitmask_abs, - const unsigned long* bitmask_key, - const unsigned long* bitmask_rel, - const unsigned long* bitmask_props, - bool test) { +static bool test_pointers( + sd_device *dev, + const struct input_id *id, + const unsigned long* bitmask_ev, + const unsigned long* bitmask_abs, + const unsigned long* bitmask_key, + const unsigned long* bitmask_rel, + const unsigned long* bitmask_props, + EventMode mode) { + bool has_abs_coordinates = false; bool has_rel_coordinates = false; bool has_mt_coordinates = false; @@ -186,7 +192,7 @@ static bool test_pointers(sd_device *dev, is_accelerometer = true; if (is_accelerometer) { - udev_builtin_add_property(dev, test, "ID_INPUT_ACCELEROMETER", "1"); + udev_builtin_add_property(dev, mode, "ID_INPUT_ACCELEROMETER", "1"); return true; } @@ -309,28 +315,29 @@ static bool test_pointers(sd_device *dev, } if (is_pointing_stick) - udev_builtin_add_property(dev, test, "ID_INPUT_POINTINGSTICK", "1"); + udev_builtin_add_property(dev, mode, "ID_INPUT_POINTINGSTICK", "1"); if (is_mouse || is_abs_mouse) - udev_builtin_add_property(dev, test, "ID_INPUT_MOUSE", "1"); + udev_builtin_add_property(dev, mode, "ID_INPUT_MOUSE", "1"); if (is_touchpad) - udev_builtin_add_property(dev, test, "ID_INPUT_TOUCHPAD", "1"); + udev_builtin_add_property(dev, mode, "ID_INPUT_TOUCHPAD", "1"); if (is_touchscreen) - udev_builtin_add_property(dev, test, "ID_INPUT_TOUCHSCREEN", "1"); + udev_builtin_add_property(dev, mode, "ID_INPUT_TOUCHSCREEN", "1"); if (is_joystick) - udev_builtin_add_property(dev, test, "ID_INPUT_JOYSTICK", "1"); + udev_builtin_add_property(dev, mode, "ID_INPUT_JOYSTICK", "1"); if (is_tablet) - udev_builtin_add_property(dev, test, "ID_INPUT_TABLET", "1"); + udev_builtin_add_property(dev, mode, "ID_INPUT_TABLET", "1"); if (is_tablet_pad) - udev_builtin_add_property(dev, test, "ID_INPUT_TABLET_PAD", "1"); + udev_builtin_add_property(dev, mode, "ID_INPUT_TABLET_PAD", "1"); return is_tablet || is_mouse || is_abs_mouse || is_touchpad || is_touchscreen || is_joystick || is_pointing_stick; } /* key like devices */ -static bool test_key(sd_device *dev, - const unsigned long* bitmask_ev, - const unsigned long* bitmask_key, - bool test) { +static bool test_key( + sd_device *dev, + const unsigned long* bitmask_ev, + const unsigned long* bitmask_key, + EventMode mode) { bool found = false; @@ -357,19 +364,19 @@ static bool test_key(sd_device *dev, } if (found) - udev_builtin_add_property(dev, test, "ID_INPUT_KEY", "1"); + udev_builtin_add_property(dev, mode, "ID_INPUT_KEY", "1"); /* the first 32 bits are ESC, numbers, and Q to D; if we have all of * those, consider it a full keyboard; do not test KEY_RESERVED, though */ if (FLAGS_SET(bitmask_key[0], 0xFFFFFFFE)) { - udev_builtin_add_property(dev, test, "ID_INPUT_KEYBOARD", "1"); + udev_builtin_add_property(dev, mode, "ID_INPUT_KEYBOARD", "1"); return true; } return found; } -static int builtin_input_id(UdevEvent *event, int argc, char *argv[], bool test) { +static int builtin_input_id(UdevEvent *event, int argc, char *argv[]) { sd_device *pdev, *dev = ASSERT_PTR(ASSERT_PTR(event)->dev); unsigned long bitmask_ev[NBITS(EV_MAX)]; unsigned long bitmask_abs[NBITS(ABS_MAX)]; @@ -400,28 +407,28 @@ static int builtin_input_id(UdevEvent *event, int argc, char *argv[], bool test) /* Use this as a flag that input devices were detected, so that this * program doesn't need to be called more than once per device */ - udev_builtin_add_property(dev, test, "ID_INPUT", "1"); - get_cap_mask(pdev, "capabilities/ev", bitmask_ev, sizeof(bitmask_ev), test); - get_cap_mask(pdev, "capabilities/abs", bitmask_abs, sizeof(bitmask_abs), test); - get_cap_mask(pdev, "capabilities/rel", bitmask_rel, sizeof(bitmask_rel), test); - get_cap_mask(pdev, "capabilities/key", bitmask_key, sizeof(bitmask_key), test); - get_cap_mask(pdev, "properties", bitmask_props, sizeof(bitmask_props), test); + udev_builtin_add_property(dev, event->event_mode, "ID_INPUT", "1"); + get_cap_mask(pdev, "capabilities/ev", bitmask_ev, sizeof(bitmask_ev), event->event_mode); + get_cap_mask(pdev, "capabilities/abs", bitmask_abs, sizeof(bitmask_abs), event->event_mode); + get_cap_mask(pdev, "capabilities/rel", bitmask_rel, sizeof(bitmask_rel), event->event_mode); + get_cap_mask(pdev, "capabilities/key", bitmask_key, sizeof(bitmask_key), event->event_mode); + get_cap_mask(pdev, "properties", bitmask_props, sizeof(bitmask_props), event->event_mode); is_pointer = test_pointers(dev, &id, bitmask_ev, bitmask_abs, bitmask_key, bitmask_rel, - bitmask_props, test); - is_key = test_key(dev, bitmask_ev, bitmask_key, test); + bitmask_props, event->event_mode); + is_key = test_key(dev, bitmask_ev, bitmask_key, event->event_mode); /* Some evdev nodes have only a scrollwheel */ if (!is_pointer && !is_key && test_bit(EV_REL, bitmask_ev) && (test_bit(REL_WHEEL, bitmask_rel) || test_bit(REL_HWHEEL, bitmask_rel))) - udev_builtin_add_property(dev, test, "ID_INPUT_KEY", "1"); + udev_builtin_add_property(dev, event->event_mode, "ID_INPUT_KEY", "1"); if (test_bit(EV_SW, bitmask_ev)) - udev_builtin_add_property(dev, test, "ID_INPUT_SWITCH", "1"); + udev_builtin_add_property(dev, event->event_mode, "ID_INPUT_SWITCH", "1"); } if (sd_device_get_sysname(dev, &sysname) >= 0 && startswith(sysname, "event")) - extract_info(dev, test); + extract_info(dev, event->event_mode); return 0; } diff --git a/src/udev/udev-builtin-keyboard.c b/src/udev/udev-builtin-keyboard.c index 3903bc4..e1e6de0 100644 --- a/src/udev/udev-builtin-keyboard.c +++ b/src/udev/udev-builtin-keyboard.c @@ -159,7 +159,7 @@ static int set_trackpoint_sensitivity(sd_device *dev, const char *value) { return 0; } -static int builtin_keyboard(UdevEvent *event, int argc, char *argv[], bool test) { +static int builtin_keyboard(UdevEvent *event, int argc, char *argv[]) { sd_device *dev = ASSERT_PTR(ASSERT_PTR(event)->dev); unsigned release[1024]; unsigned release_count = 0; @@ -167,6 +167,11 @@ static int builtin_keyboard(UdevEvent *event, int argc, char *argv[], bool test) const char *node; int has_abs = -1, r; + if (event->event_mode != EVENT_UDEV_WORKER) { + log_device_debug(dev, "Running in test mode, skipping execution of 'keyboard' builtin command."); + return 0; + } + r = sd_device_get_devname(dev, &node); if (r < 0) return log_device_error_errno(dev, r, "Failed to get device name: %m"); diff --git a/src/udev/udev-builtin-kmod.c b/src/udev/udev-builtin-kmod.c index 3ab5c48..f4aa480 100644 --- a/src/udev/udev-builtin-kmod.c +++ b/src/udev/udev-builtin-kmod.c @@ -18,14 +18,15 @@ static struct kmod_ctx *ctx = NULL; -_printf_(6,0) static void udev_kmod_log(void *data, int priority, const char *file, int line, const char *fn, const char *format, va_list args) { - log_internalv(priority, 0, file, line, fn, format, args); -} - -static int builtin_kmod(UdevEvent *event, int argc, char *argv[], bool test) { +static int builtin_kmod(UdevEvent *event, int argc, char *argv[]) { sd_device *dev = ASSERT_PTR(ASSERT_PTR(event)->dev); int r; + if (event->event_mode != EVENT_UDEV_WORKER) { + log_device_debug(dev, "Running in test mode, skipping execution of 'kmod' builtin command."); + return 0; + } + if (!ctx) return 0; @@ -39,7 +40,7 @@ static int builtin_kmod(UdevEvent *event, int argc, char *argv[], bool test) { r = sd_device_get_property_value(dev, "MODALIAS", &modalias); if (r < 0) - return log_device_warning_errno(dev, r, "Failed to read property \"MODALIAS\"."); + return log_device_warning_errno(dev, r, "Failed to read property \"MODALIAS\": %m"); (void) module_load_and_warn(ctx, modalias, /* verbose = */ false); } else @@ -51,23 +52,28 @@ static int builtin_kmod(UdevEvent *event, int argc, char *argv[], bool test) { /* called at udev startup and reload */ static int builtin_kmod_init(void) { + int r; + if (ctx) return 0; - ctx = kmod_new(NULL, NULL); - if (!ctx) - return -ENOMEM; - log_debug("Loading kernel module index."); - kmod_set_log_fn(ctx, udev_kmod_log, NULL); - kmod_load_resources(ctx); + + r = module_setup_context(&ctx); + if (r < 0) + return log_error_errno(r, "Failed to initialize libkmod context: %m"); + return 0; } /* called on udev shutdown and reload request */ static void builtin_kmod_exit(void) { log_debug("Unload kernel module index."); - ctx = kmod_unref(ctx); + + if (!ctx) + return; + + ctx = sym_kmod_unref(ctx); } /* called every couple of seconds during event activity; 'true' if config has changed */ @@ -75,7 +81,7 @@ static bool builtin_kmod_should_reload(void) { if (!ctx) return false; - if (kmod_validate_resources(ctx) != KMOD_RESOURCES_OK) { + if (sym_kmod_validate_resources(ctx) != KMOD_RESOURCES_OK) { log_debug("Kernel module index needs reloading."); return true; } diff --git a/src/udev/udev-builtin-net_driver.c b/src/udev/udev-builtin-net_driver.c index f1642a4..90a9e8d 100644 --- a/src/udev/udev-builtin-net_driver.c +++ b/src/udev/udev-builtin-net_driver.c @@ -9,7 +9,7 @@ #include "string-util.h" #include "udev-builtin.h" -static int builtin_net_driver_set_driver(UdevEvent *event, int argc, char **argv, bool test) { +static int builtin_net_driver_set_driver(UdevEvent *event, int argc, char **argv) { sd_device *dev = ASSERT_PTR(ASSERT_PTR(event)->dev); _cleanup_close_ int ethtool_fd = -EBADF; _cleanup_free_ char *driver = NULL; @@ -32,7 +32,7 @@ static int builtin_net_driver_set_driver(UdevEvent *event, int argc, char **argv if (r < 0) return log_device_warning_errno(dev, r, "Failed to get driver for '%s': %m", sysname); - return udev_builtin_add_property(event->dev, test, "ID_NET_DRIVER", driver); + return udev_builtin_add_property(event->dev, event->event_mode, "ID_NET_DRIVER", driver); } const UdevBuiltin udev_builtin_net_driver = { diff --git a/src/udev/udev-builtin-net_id.c b/src/udev/udev-builtin-net_id.c index 91b4008..384a1f3 100644 --- a/src/udev/udev-builtin-net_id.c +++ b/src/udev/udev-builtin-net_id.c @@ -12,9 +12,10 @@ * When the code here is changed, man/systemd.net-naming-scheme.xml must be updated too. */ +/* Make sure the net/if.h header is included before any linux/ one */ +#include #include #include -#include #include #include #include @@ -49,12 +50,7 @@ static sd_device *device_skip_virtio(sd_device *dev) { * safely ignore any virtio buses. see * http://lists.linuxfoundation.org/pipermail/virtualization/2015-August/030331.html */ while (dev) { - const char *subsystem; - - if (sd_device_get_subsystem(dev, &subsystem) < 0) - break; - - if (!streq(subsystem, "virtio")) + if (!device_in_subsystem(dev, "virtio")) break; if (sd_device_get_parent(dev, &dev) < 0) @@ -86,22 +82,15 @@ static int get_matching_parent( return -ENODEV; } - if (!strv_isempty(parent_subsystems)) { - const char *subsystem; - - /* check if our direct parent is in an expected subsystem. */ - r = sd_device_get_subsystem(parent, &subsystem); - if (r < 0) - return r; - - if (!strv_contains(parent_subsystems, subsystem)) - return -ENODEV; - } - - if (ret) - *ret = parent; + /* check if our direct parent is in an expected subsystem. */ + STRV_FOREACH(s, parent_subsystems) + if (device_in_subsystem(parent, *s)) { + if (ret) + *ret = parent; + return 0; + } - return 0; + return -ENODEV; } static int get_first_syspath_component(sd_device *dev, const char *prefix, char **ret) { @@ -188,7 +177,7 @@ static int get_dev_port(sd_device *dev, bool fallback_to_dev_id, unsigned *ret) /* Get kernel provided port index for the case when multiple ports on a single PCI function. */ - r = device_get_sysattr_unsigned(dev, "dev_port", &v); + r = device_get_sysattr_unsigned_filtered(dev, "dev_port", &v); if (r < 0) return r; if (r > 0) { @@ -204,7 +193,7 @@ static int get_dev_port(sd_device *dev, bool fallback_to_dev_id, unsigned *ret) if (fallback_to_dev_id) { unsigned iftype; - r = device_get_sysattr_unsigned(dev, "type", &iftype); + r = device_get_sysattr_unsigned_filtered(dev, "type", &iftype); if (r < 0) return r; @@ -212,7 +201,7 @@ static int get_dev_port(sd_device *dev, bool fallback_to_dev_id, unsigned *ret) } if (fallback_to_dev_id) - return device_get_sysattr_unsigned(dev, "dev_id", ret); + return device_get_sysattr_unsigned_filtered(dev, "dev_id", ret); /* Otherwise, return the original index 0. */ *ret = 0; @@ -229,7 +218,7 @@ static int get_port_specifier(sd_device *dev, bool fallback_to_dev_id, char **re assert(ret); /* First, try to use the kernel provided front panel port name for multiple port PCI device. */ - r = sd_device_get_sysattr_value(dev, "phys_port_name", &phys_port_name); + r = device_get_sysattr_value_filtered(dev, "phys_port_name", &phys_port_name); if (r >= 0 && !isempty(phys_port_name)) { if (naming_scheme_has(NAMING_SR_IOV_R)) { int vf_id = -1; @@ -292,10 +281,10 @@ static int pci_get_onboard_index(sd_device *dev, unsigned *ret) { assert(ret); /* ACPI _DSM — device specific method for naming a PCI or PCI Express device */ - r = device_get_sysattr_unsigned(dev, "acpi_index", &idx); + r = device_get_sysattr_unsigned_filtered(dev, "acpi_index", &idx); if (r < 0) /* SMBIOS type 41 — Onboard Devices Extended Information */ - r = device_get_sysattr_unsigned(dev, "index", &idx); + r = device_get_sysattr_unsigned_filtered(dev, "index", &idx); if (r < 0) return log_device_debug_errno(dev, r, "Could not obtain onboard index: %m"); @@ -310,7 +299,7 @@ static int pci_get_onboard_index(sd_device *dev, unsigned *ret) { return 0; } -static int names_pci_onboard(sd_device *dev, sd_device *pci_dev, const char *prefix, const char *suffix, bool test) { +static int names_pci_onboard(sd_device *dev, sd_device *pci_dev, const char *prefix, const char *suffix, EventMode mode) { _cleanup_free_ char *port = NULL; unsigned idx = 0; /* avoid false maybe-uninitialized warning */ int r; @@ -330,7 +319,7 @@ static int names_pci_onboard(sd_device *dev, sd_device *pci_dev, const char *pre char str[ALTIFNAMSIZ]; if (snprintf_ok(str, sizeof str, "%so%u%s%s", prefix, idx, strempty(port), strempty(suffix))) - udev_builtin_add_property(dev, test, "ID_NET_NAME_ONBOARD", str); + udev_builtin_add_property(dev, mode, "ID_NET_NAME_ONBOARD", str); log_device_debug(dev, "Onboard index identifier: index=%u port=%s %s %s", idx, strna(port), @@ -339,7 +328,7 @@ static int names_pci_onboard(sd_device *dev, sd_device *pci_dev, const char *pre return 0; } -static int names_pci_onboard_label(sd_device *dev, sd_device *pci_dev, const char *prefix, bool test) { +static int names_pci_onboard_label(sd_device *dev, sd_device *pci_dev, const char *prefix, EventMode mode) { const char *label; int r; @@ -347,7 +336,7 @@ static int names_pci_onboard_label(sd_device *dev, sd_device *pci_dev, const cha assert(prefix); /* retrieve on-board label from firmware */ - r = sd_device_get_sysattr_value(pci_dev, "label", &label); + r = device_get_sysattr_value_filtered(pci_dev, "label", &label); if (r < 0) return log_device_debug_errno(pci_dev, r, "Failed to get PCI onboard label: %m"); @@ -355,7 +344,7 @@ static int names_pci_onboard_label(sd_device *dev, sd_device *pci_dev, const cha if (snprintf_ok(str, sizeof str, "%s%s", naming_scheme_has(NAMING_LABEL_NOPREFIX) ? "" : prefix, label)) - udev_builtin_add_property(dev, test, "ID_NET_LABEL_ONBOARD", str); + udev_builtin_add_property(dev, mode, "ID_NET_LABEL_ONBOARD", str); log_device_debug(dev, "Onboard label from PCI device: %s", label); return 0; @@ -392,7 +381,7 @@ static int is_pci_multifunction(sd_device *dev) { static bool is_pci_ari_enabled(sd_device *dev) { assert(dev); - return device_get_sysattr_bool(dev, "ari_enabled") > 0; + return device_get_sysattr_bool_filtered(dev, "ari_enabled") > 0; } static bool is_pci_bridge(sd_device *dev) { @@ -400,7 +389,7 @@ static bool is_pci_bridge(sd_device *dev) { assert(dev); - if (sd_device_get_sysattr_value(dev, "modalias", &v) < 0) + if (device_get_sysattr_value_filtered(dev, "modalias", &v) < 0) return false; if (!startswith(v, "pci:")) @@ -442,7 +431,7 @@ static int parse_hotplug_slot_from_function_id(sd_device *dev, int slots_dirfd, return 0; } - if (sd_device_get_sysattr_value(dev, "function_id", &attr) < 0) { + if (device_get_sysattr_value_filtered(dev, "function_id", &attr) < 0) { *ret = 0; return 0; } @@ -505,7 +494,7 @@ static int pci_get_hotplug_slot_from_address( if (!path) return log_oom_debug(); - if (sd_device_get_sysattr_value(pci, path, &address) < 0) + if (device_get_sysattr_value_filtered(pci, path, &address) < 0) continue; /* match slot address with device by stripping the function */ @@ -625,7 +614,7 @@ static int get_pci_slot_specifiers( return 0; } -static int names_pci_slot(sd_device *dev, sd_device *pci_dev, const char *prefix, const char *suffix, bool test) { +static int names_pci_slot(sd_device *dev, sd_device *pci_dev, const char *prefix, const char *suffix, EventMode mode) { _cleanup_free_ char *domain = NULL, *bus_and_slot = NULL, *func = NULL, *port = NULL; uint32_t hotplug_slot = 0; /* avoid false maybe-uninitialized warning */ char str[ALTIFNAMSIZ]; @@ -646,7 +635,7 @@ static int names_pci_slot(sd_device *dev, sd_device *pci_dev, const char *prefix /* compose a name based on the raw kernel's PCI bus, slot numbers */ if (snprintf_ok(str, sizeof str, "%s%s%s%s%s%s", prefix, strempty(domain), bus_and_slot, strempty(func), strempty(port), strempty(suffix))) - udev_builtin_add_property(dev, test, "ID_NET_NAME_PATH", str); + udev_builtin_add_property(dev, mode, "ID_NET_NAME_PATH", str); log_device_debug(dev, "PCI path identifier: domain=%s bus_and_slot=%s func=%s port=%s %s %s", strna(domain), bus_and_slot, strna(func), strna(port), @@ -662,7 +651,7 @@ static int names_pci_slot(sd_device *dev, sd_device *pci_dev, const char *prefix if (snprintf_ok(str, sizeof str, "%s%ss%"PRIu32"%s%s%s", prefix, strempty(domain), hotplug_slot, strempty(func), strempty(port), strempty(suffix))) - udev_builtin_add_property(dev, test, "ID_NET_NAME_SLOT", str); + udev_builtin_add_property(dev, mode, "ID_NET_NAME_SLOT", str); log_device_debug(dev, "Slot identifier: domain=%s slot=%"PRIu32" func=%s port=%s %s %s", strna(domain), hotplug_slot, strna(func), strna(port), @@ -671,7 +660,7 @@ static int names_pci_slot(sd_device *dev, sd_device *pci_dev, const char *prefix return 0; } -static int names_vio(sd_device *dev, const char *prefix, bool test) { +static int names_vio(sd_device *dev, const char *prefix, EventMode mode) { _cleanup_free_ char *s = NULL; unsigned slotid; int r; @@ -710,13 +699,13 @@ static int names_vio(sd_device *dev, const char *prefix, bool test) { char str[ALTIFNAMSIZ]; if (snprintf_ok(str, sizeof str, "%sv%u", prefix, slotid)) - udev_builtin_add_property(dev, test, "ID_NET_NAME_SLOT", str); + udev_builtin_add_property(dev, mode, "ID_NET_NAME_SLOT", str); log_device_debug(dev, "Vio slot identifier: slotid=%u %s %s", slotid, special_glyph(SPECIAL_GLYPH_ARROW_RIGHT), str + strlen(prefix)); return 0; } -static int names_platform(sd_device *dev, const char *prefix, bool test) { +static int names_platform(sd_device *dev, const char *prefix, EventMode mode) { _cleanup_free_ char *p = NULL; const char *validchars; char *vendor, *model_str, *instance_str; @@ -743,15 +732,15 @@ static int names_platform(sd_device *dev, const char *prefix, bool test) { * The Vendor (3 or 4 char), followed by hexadecimal model number : instance id. */ if (r == 10 && p[7] == ':') { /* 3 char vendor string */ - vendor = strndupa(p, 3); - model_str = strndupa(p + 3, 4); - instance_str = strndupa(p + 8, 2); + vendor = strndupa_safe(p, 3); + model_str = strndupa_safe(p + 3, 4); + instance_str = strndupa_safe(p + 8, 2); validchars = UPPERCASE_LETTERS; } else if (r == 11 && p[8] == ':') { /* 4 char vendor string */ - vendor = strndupa(p, 4); - model_str = strndupa(p + 4, 4); - instance_str = strndupa(p + 9, 2); + vendor = strndupa_safe(p, 4); + model_str = strndupa_safe(p + 4, 4); + instance_str = strndupa_safe(p + 9, 2); validchars = UPPERCASE_LETTERS DIGITS; } else return -EOPNOTSUPP; @@ -772,13 +761,13 @@ static int names_platform(sd_device *dev, const char *prefix, bool test) { char str[ALTIFNAMSIZ]; if (snprintf_ok(str, sizeof str, "%sa%s%xi%u", prefix, vendor, model, instance)) - udev_builtin_add_property(dev, test, "ID_NET_NAME_PATH", str); + udev_builtin_add_property(dev, mode, "ID_NET_NAME_PATH", str); log_device_debug(dev, "Platform identifier: vendor=%s model=%x instance=%u %s %s", vendor, model, instance, special_glyph(SPECIAL_GLYPH_ARROW_RIGHT), str + strlen(prefix)); return 0; } -static int names_devicetree(sd_device *dev, const char *prefix, bool test) { +static int names_devicetree(sd_device *dev, const char *prefix, EventMode mode) { _cleanup_(sd_device_unrefp) sd_device *aliases_dev = NULL, *ofnode_dev = NULL, *devicetree_dev = NULL; const char *ofnode_path, *ofnode_syspath, *devicetree_syspath; sd_device *parent; @@ -825,7 +814,7 @@ static int names_devicetree(sd_device *dev, const char *prefix, bool test) { ofnode_path = path_startswith(ofnode_syspath, devicetree_syspath); if (!ofnode_path) return log_device_debug_errno(ofnode_dev, SYNTHETIC_ERRNO(EINVAL), - "The device '%s' is not a child device of '%s': %m", + "The device '%s' is not a child device of '%s'.", ofnode_syspath, devicetree_syspath); /* Get back our leading / to match the contents of the aliases */ @@ -845,7 +834,7 @@ static int names_devicetree(sd_device *dev, const char *prefix, bool test) { if (!alias_index) continue; - if (sd_device_get_sysattr_value(aliases_dev, alias, &alias_path) < 0) + if (device_get_sysattr_value_filtered(aliases_dev, alias, &alias_path) < 0) continue; if (!path_equal(ofnode_path, alias_path)) @@ -864,13 +853,13 @@ static int names_devicetree(sd_device *dev, const char *prefix, bool test) { } /* ...but make sure we don't have an alias conflict */ - if (i == 0 && sd_device_get_sysattr_value(aliases_dev, conflict, NULL) >= 0) + if (i == 0 && device_get_sysattr_value_filtered(aliases_dev, conflict, NULL) >= 0) return log_device_debug_errno(dev, SYNTHETIC_ERRNO(EEXIST), - "Ethernet alias conflict: ethernet and ethernet0 both exist"); + "Ethernet alias conflict: ethernet and ethernet0 both exist."); char str[ALTIFNAMSIZ]; if (snprintf_ok(str, sizeof str, "%sd%u", prefix, i)) - udev_builtin_add_property(dev, test, "ID_NET_NAME_ONBOARD", str); + udev_builtin_add_property(dev, mode, "ID_NET_NAME_ONBOARD", str); log_device_debug(dev, "devicetree identifier: alias_index=%u %s \"%s\"", i, special_glyph(SPECIAL_GLYPH_ARROW_RIGHT), str + strlen(prefix)); return 0; @@ -879,7 +868,7 @@ static int names_devicetree(sd_device *dev, const char *prefix, bool test) { return -ENOENT; } -static int names_pci(sd_device *dev, const char *prefix, bool test) { +static int names_pci(sd_device *dev, const char *prefix, EventMode mode) { _cleanup_(sd_device_unrefp) sd_device *physfn_pcidev = NULL; _cleanup_free_ char *virtfn_suffix = NULL; sd_device *parent; @@ -896,10 +885,10 @@ static int names_pci(sd_device *dev, const char *prefix, bool test) { get_virtfn_info(parent, &physfn_pcidev, &virtfn_suffix) >= 0) parent = physfn_pcidev; else - (void) names_pci_onboard_label(dev, parent, prefix, test); + (void) names_pci_onboard_label(dev, parent, prefix, mode); - (void) names_pci_onboard(dev, parent, prefix, virtfn_suffix, test); - (void) names_pci_slot(dev, parent, prefix, virtfn_suffix, test); + (void) names_pci_onboard(dev, parent, prefix, virtfn_suffix, mode); + (void) names_pci_slot(dev, parent, prefix, virtfn_suffix, mode); return 0; } @@ -962,7 +951,7 @@ static int get_usb_specifier(sd_device *dev, char **ret) { return 0; } -static int names_usb(sd_device *dev, const char *prefix, bool test) { +static int names_usb(sd_device *dev, const char *prefix, EventMode mode) { _cleanup_free_ char *suffix = NULL; sd_device *usbdev, *pcidev; int r; @@ -983,7 +972,7 @@ static int names_usb(sd_device *dev, const char *prefix, bool test) { /* If the USB bus is on PCI bus, then suffix the USB specifier to the name based on the PCI bus. */ r = sd_device_get_parent_with_subsystem_devtype(usbdev, "pci", NULL, &pcidev); if (r >= 0) - return names_pci_slot(dev, pcidev, prefix, suffix, test); + return names_pci_slot(dev, pcidev, prefix, suffix, mode); if (r != -ENOENT || !naming_scheme_has(NAMING_USB_HOST)) return log_device_debug_errno(usbdev, r, "Failed to get parent PCI bus: %m"); @@ -991,7 +980,7 @@ static int names_usb(sd_device *dev, const char *prefix, bool test) { /* Otherwise, e.g. on-chip asics that have USB ports, use the USB specifier as is. */ char str[ALTIFNAMSIZ]; if (snprintf_ok(str, sizeof str, "%s%s", prefix, suffix)) - udev_builtin_add_property(dev, test, "ID_NET_NAME_PATH", str); + udev_builtin_add_property(dev, mode, "ID_NET_NAME_PATH", str); return 0; } @@ -1026,7 +1015,7 @@ static int get_bcma_specifier(sd_device *dev, char **ret) { return 0; } -static int names_bcma(sd_device *dev, const char *prefix, bool test) { +static int names_bcma(sd_device *dev, const char *prefix, EventMode mode) { _cleanup_free_ char *suffix = NULL; sd_device *bcmadev, *pcidev; int r; @@ -1046,10 +1035,10 @@ static int names_bcma(sd_device *dev, const char *prefix, bool test) { if (r < 0) return r; - return names_pci_slot(dev, pcidev, prefix, suffix, test); + return names_pci_slot(dev, pcidev, prefix, suffix, mode); } -static int names_ccw(sd_device *dev, const char *prefix, bool test) { +static int names_ccw(sd_device *dev, const char *prefix, EventMode mode) { sd_device *cdev; const char *bus_id; size_t bus_id_start, bus_id_len; @@ -1091,14 +1080,14 @@ static int names_ccw(sd_device *dev, const char *prefix, bool test) { /* Use the CCW bus-ID as network device name */ char str[ALTIFNAMSIZ]; if (snprintf_ok(str, sizeof str, "%sc%s", prefix, bus_id)) - udev_builtin_add_property(dev, test, "ID_NET_NAME_PATH", str); + udev_builtin_add_property(dev, mode, "ID_NET_NAME_PATH", str); log_device_debug(dev, "CCW identifier: ccw_busid=%s %s \"%s\"", bus_id, special_glyph(SPECIAL_GLYPH_ARROW_RIGHT), str + strlen(prefix)); return 0; } /* IEEE Organizationally Unique Identifier vendor string */ -static int ieee_oui(sd_device *dev, const struct hw_addr_data *hw_addr, bool test) { +static int ieee_oui(sd_device *dev, const struct hw_addr_data *hw_addr, EventMode mode) { char str[32]; assert(dev); @@ -1121,10 +1110,10 @@ static int ieee_oui(sd_device *dev, const struct hw_addr_data *hw_addr, bool tes hw_addr->bytes[4], hw_addr->bytes[5]); - return udev_builtin_hwdb_lookup(dev, NULL, str, NULL, test); + return udev_builtin_hwdb_lookup(dev, NULL, str, NULL, mode); } -static int names_mac(sd_device *dev, const char *prefix, bool test) { +static int names_mac(sd_device *dev, const char *prefix, EventMode mode) { unsigned iftype, assign_type; struct hw_addr_data hw_addr; const char *s; @@ -1133,7 +1122,7 @@ static int names_mac(sd_device *dev, const char *prefix, bool test) { assert(dev); assert(prefix); - r = device_get_sysattr_unsigned(dev, "type", &iftype); + r = device_get_sysattr_unsigned_filtered(dev, "type", &iftype); if (r < 0) return log_device_debug_errno(dev, r, "Failed to read 'type' attribute: %m"); @@ -1145,7 +1134,7 @@ static int names_mac(sd_device *dev, const char *prefix, bool test) { "Not generating MAC name for infiniband device."); /* check for NET_ADDR_PERM, skip random MAC addresses */ - r = device_get_sysattr_unsigned(dev, "addr_assign_type", &assign_type); + r = device_get_sysattr_unsigned_filtered(dev, "addr_assign_type", &assign_type); if (r < 0) return log_device_debug_errno(dev, r, "Failed to read/parse addr_assign_type: %m"); @@ -1153,7 +1142,7 @@ static int names_mac(sd_device *dev, const char *prefix, bool test) { return log_device_debug_errno(dev, SYNTHETIC_ERRNO(EINVAL), "addr_assign_type=%u, MAC address is not permanent.", assign_type); - r = sd_device_get_sysattr_value(dev, "address", &s); + r = device_get_sysattr_value_filtered(dev, "address", &s); if (r < 0) return log_device_debug_errno(dev, r, "Failed to read 'address' attribute: %m"); @@ -1168,16 +1157,16 @@ static int names_mac(sd_device *dev, const char *prefix, bool test) { char str[ALTIFNAMSIZ]; xsprintf(str, "%sx%s", prefix, HW_ADDR_TO_STR_FULL(&hw_addr, HW_ADDR_TO_STRING_NO_COLON)); - udev_builtin_add_property(dev, test, "ID_NET_NAME_MAC", str); + udev_builtin_add_property(dev, mode, "ID_NET_NAME_MAC", str); log_device_debug(dev, "MAC address identifier: hw_addr=%s %s %s", HW_ADDR_TO_STR(&hw_addr), special_glyph(SPECIAL_GLYPH_ARROW_RIGHT), str + strlen(prefix)); - (void) ieee_oui(dev, &hw_addr, test); + (void) ieee_oui(dev, &hw_addr, mode); return 0; } -static int names_netdevsim(sd_device *dev, const char *prefix, bool test) { +static int names_netdevsim(sd_device *dev, const char *prefix, EventMode mode) { sd_device *netdevsimdev; const char *sysnum, *phys_port_name; unsigned addr; @@ -1203,7 +1192,7 @@ static int names_netdevsim(sd_device *dev, const char *prefix, bool test) { if (r < 0) return log_device_debug_errno(netdevsimdev, r, "Failed to parse device sysnum: %m"); - r = sd_device_get_sysattr_value(dev, "phys_port_name", &phys_port_name); + r = device_get_sysattr_value_filtered(dev, "phys_port_name", &phys_port_name); if (r < 0) return log_device_debug_errno(dev, r, "Failed to get 'phys_port_name' attribute: %m"); if (isempty(phys_port_name)) @@ -1212,13 +1201,13 @@ static int names_netdevsim(sd_device *dev, const char *prefix, bool test) { char str[ALTIFNAMSIZ]; if (snprintf_ok(str, sizeof str, "%si%un%s", prefix, addr, phys_port_name)) - udev_builtin_add_property(dev, test, "ID_NET_NAME_PATH", str); + udev_builtin_add_property(dev, mode, "ID_NET_NAME_PATH", str); log_device_debug(dev, "Netdevsim identifier: address=%u, port_name=%s %s %s", addr, phys_port_name, special_glyph(SPECIAL_GLYPH_ARROW_RIGHT), str + strlen(prefix)); return 0; } -static int names_xen(sd_device *dev, const char *prefix, bool test) { +static int names_xen(sd_device *dev, const char *prefix, EventMode mode) { _cleanup_free_ char *vif = NULL; const char *p; unsigned id; @@ -1243,7 +1232,7 @@ static int names_xen(sd_device *dev, const char *prefix, bool test) { p = startswith(vif, "vif-"); if (!p) - return log_device_debug_errno(dev, SYNTHETIC_ERRNO(EINVAL), "Invalid vif name: %s: %m", vif); + return log_device_debug_errno(dev, SYNTHETIC_ERRNO(EINVAL), "Invalid vif name: %s.", vif); r = safe_atou_full(p, SAFE_ATO_REFUSE_PLUS_MINUS | SAFE_ATO_REFUSE_LEADING_ZERO | SAFE_ATO_REFUSE_LEADING_WHITESPACE | 10, &id); @@ -1252,7 +1241,7 @@ static int names_xen(sd_device *dev, const char *prefix, bool test) { char str[ALTIFNAMSIZ]; if (snprintf_ok(str, sizeof str, "%sX%u", prefix, id)) - udev_builtin_add_property(dev, test, "ID_NET_NAME_SLOT", str); + udev_builtin_add_property(dev, mode, "ID_NET_NAME_SLOT", str); log_device_debug(dev, "Xen identifier: id=%u %s %s", id, special_glyph(SPECIAL_GLYPH_ARROW_RIGHT), str + strlen(prefix)); return 0; @@ -1265,22 +1254,16 @@ static int get_ifname_prefix(sd_device *dev, const char **ret) { assert(dev); assert(ret); - r = device_get_sysattr_unsigned(dev, "type", &iftype); + r = device_get_sysattr_unsigned_filtered(dev, "type", &iftype); if (r < 0) return r; /* handle only ARPHRD_ETHER, ARPHRD_SLIP and ARPHRD_INFINIBAND devices */ switch (iftype) { case ARPHRD_ETHER: { - const char *s = NULL; - - r = sd_device_get_devtype(dev, &s); - if (r < 0 && r != -ENOENT) - return r; - - if (streq_ptr(s, "wlan")) + if (device_is_devtype(dev, "wlan")) *ret = "wl"; - else if (streq_ptr(s, "wwan")) + else if (device_is_devtype(dev, "wwan")) *ret = "ww"; else *ret = "en"; @@ -1311,14 +1294,14 @@ static int device_is_stacked(sd_device *dev) { if (r < 0) return r; - r = device_get_sysattr_int(dev, "iflink", &iflink); + r = device_get_sysattr_int_filtered(dev, "iflink", &iflink); if (r < 0) return r; return ifindex != iflink; } -static int builtin_net_id(UdevEvent *event, int argc, char *argv[], bool test) { +static int builtin_net_id(UdevEvent *event, int argc, char *argv[]) { sd_device *dev = ASSERT_PTR(ASSERT_PTR(event)->dev); const char *prefix; int r; @@ -1336,18 +1319,18 @@ static int builtin_net_id(UdevEvent *event, int argc, char *argv[], bool test) { return 0; } - udev_builtin_add_property(dev, test, "ID_NET_NAMING_SCHEME", naming_scheme()->name); - - (void) names_mac(dev, prefix, test); - (void) names_devicetree(dev, prefix, test); - (void) names_ccw(dev, prefix, test); - (void) names_vio(dev, prefix, test); - (void) names_platform(dev, prefix, test); - (void) names_netdevsim(dev, prefix, test); - (void) names_xen(dev, prefix, test); - (void) names_pci(dev, prefix, test); - (void) names_usb(dev, prefix, test); - (void) names_bcma(dev, prefix, test); + udev_builtin_add_property(dev, event->event_mode, "ID_NET_NAMING_SCHEME", naming_scheme()->name); + + (void) names_mac(dev, prefix, event->event_mode); + (void) names_devicetree(dev, prefix, event->event_mode); + (void) names_ccw(dev, prefix, event->event_mode); + (void) names_vio(dev, prefix, event->event_mode); + (void) names_platform(dev, prefix, event->event_mode); + (void) names_netdevsim(dev, prefix, event->event_mode); + (void) names_xen(dev, prefix, event->event_mode); + (void) names_pci(dev, prefix, event->event_mode); + (void) names_usb(dev, prefix, event->event_mode); + (void) names_bcma(dev, prefix, event->event_mode); return 0; } diff --git a/src/udev/udev-builtin-net_setup_link.c b/src/udev/udev-builtin-net_setup_link.c index a308a21..8cfcaa9 100644 --- a/src/udev/udev-builtin-net_setup_link.c +++ b/src/udev/udev-builtin-net_setup_link.c @@ -1,8 +1,8 @@ /* SPDX-License-Identifier: LGPL-2.1-or-later */ #include "alloc-util.h" +#include "device-private.h" #include "device-util.h" -#include "escape.h" #include "errno-util.h" #include "link-config.h" #include "log.h" @@ -12,16 +12,36 @@ static LinkConfigContext *ctx = NULL; -static int builtin_net_setup_link(UdevEvent *event, int argc, char **argv, bool test) { +static int builtin_net_setup_link(UdevEvent *event, int argc, char **argv) { sd_device *dev = ASSERT_PTR(ASSERT_PTR(event)->dev); _cleanup_(link_freep) Link *link = NULL; - _cleanup_free_ char *joined = NULL; int r; if (argc > 1) return log_device_error_errno(dev, SYNTHETIC_ERRNO(EINVAL), "This program takes no arguments."); - r = link_new(ctx, &event->rtnl, dev, &link); + sd_device_action_t action; + r = sd_device_get_action(dev, &action); + if (r < 0) + return log_device_error_errno(dev, r, "Failed to get action: %m"); + + if (!IN_SET(action, SD_DEVICE_ADD, SD_DEVICE_BIND, SD_DEVICE_MOVE)) { + log_device_debug(dev, "Not applying .link settings on '%s' uevent.", + device_action_to_string(action)); + + /* Import previously assigned .link file name. */ + (void) udev_builtin_import_property(dev, event->dev_db_clone, event->event_mode, "ID_NET_LINK_FILE"); + (void) udev_builtin_import_property(dev, event->dev_db_clone, event->event_mode, "ID_NET_LINK_FILE_DROPINS"); + + /* Set ID_NET_NAME= with the current interface name. */ + const char *value; + if (sd_device_get_sysname(dev, &value) >= 0) + (void) udev_builtin_add_property(dev, event->event_mode, "ID_NET_NAME", value); + + return 0; + } + + 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; @@ -39,31 +59,14 @@ static int builtin_net_setup_link(UdevEvent *event, int argc, char **argv, bool return log_device_error_errno(dev, r, "Failed to get link config: %m"); } - r = link_apply_config(ctx, &event->rtnl, link); + r = link_apply_config(ctx, &event->rtnl, link, event->event_mode); if (r == -ENODEV) log_device_debug_errno(dev, r, "Link vanished while applying configuration, ignoring."); else if (r < 0) log_device_warning_errno(dev, r, "Could not apply link configuration, ignoring: %m"); - udev_builtin_add_property(dev, test, "ID_NET_LINK_FILE", link->config->filename); - if (link->new_name) - udev_builtin_add_property(dev, test, "ID_NET_NAME", link->new_name); - event->altnames = TAKE_PTR(link->altnames); - STRV_FOREACH(d, link->config->dropins) { - _cleanup_free_ char *escaped = NULL; - - escaped = xescape(*d, ":"); - if (!escaped) - return log_oom(); - - if (!strextend_with_separator(&joined, ":", escaped)) - return log_oom(); - } - - udev_builtin_add_property(dev, test, "ID_NET_LINK_FILE_DROPINS", joined); - return 0; } diff --git a/src/udev/udev-builtin-path_id.c b/src/udev/udev-builtin-path_id.c index 467c9a6..a23b32d 100644 --- a/src/udev/udev-builtin-path_id.c +++ b/src/udev/udev-builtin-path_id.c @@ -95,12 +95,7 @@ static sd_device *skip_subsystem(sd_device *dev, const char *subsys) { */ for (parent = dev; ; ) { - const char *subsystem; - - if (sd_device_get_subsystem(parent, &subsystem) < 0) - break; - - if (!streq(subsystem, subsys)) + if (!device_in_subsystem(parent, subsys)) break; dev = parent; @@ -191,7 +186,7 @@ static sd_device *handle_scsi_sas(sd_device *parent, char **path) { return NULL; /* Check if we are simple disk */ - if (strncmp(phy_count, "1", 2) != 0) + if (!streq(phy_count, "1")) return handle_scsi_sas_wide_port(parent, path); /* Get connected phy */ @@ -417,10 +412,9 @@ static sd_device *handle_scsi_hyperv(sd_device *parent, char **path, size_t guid } static sd_device *handle_scsi(sd_device *parent, char **path, char **compat_path, bool *supported_parent) { - const char *devtype, *id, *name; + const char *id, *name; - if (sd_device_get_devtype(parent, &devtype) < 0 || - !streq(devtype, "scsi_device")) + if (!device_is_devtype(parent, "scsi_device")) return parent; /* firewire */ @@ -532,12 +526,10 @@ static int get_usb_revision(sd_device *dev) { } static sd_device *handle_usb(sd_device *parent, char **path) { - const char *devtype, *str, *port; + const char *str, *port; int r; - if (sd_device_get_devtype(parent, &devtype) < 0) - return parent; - if (!STR_IN_SET(devtype, "usb_interface", "usb_device")) + if (!device_is_devtype(parent, "usb_interface") && !device_is_devtype(parent, "usb_device")) return parent; if (sd_device_get_sysname(parent, &str) < 0) @@ -632,7 +624,7 @@ static int find_real_nvme_parent(sd_device *dev, sd_device **ret) { return -ENXIO; end += strspn(end, DIGITS); - sysname = strndupa(sysname, end - sysname); + sysname = strndupa_safe(sysname, end - sysname); r = sd_device_new_from_subsystem_sysname(&nvme, "nvme", sysname); if (r < 0) @@ -650,9 +642,8 @@ static int find_real_nvme_parent(sd_device *dev, sd_device **ret) { return 0; } -static void add_id_with_usb_revision(sd_device *dev, bool test, char *path) { +static void add_id_with_usb_revision(sd_device *dev, EventMode mode, char *path) { char *p; - int r; assert(dev); assert(path); @@ -668,18 +659,15 @@ static void add_id_with_usb_revision(sd_device *dev, bool test, char *path) { if (p[1] != '-') return; - r = udev_builtin_add_property(dev, test, "ID_PATH_WITH_USB_REVISION", path); - if (r < 0) - log_device_debug_errno(dev, r, "Failed to add ID_PATH_WITH_USB_REVISION property, ignoring: %m"); + (void) udev_builtin_add_property(dev, mode, "ID_PATH_WITH_USB_REVISION", path); /* Drop the USB revision specifier for backward compatibility. */ memmove(p - 1, p + 1, strlen(p + 1) + 1); } -static void add_id_tag(sd_device *dev, bool test, const char *path) { +static void add_id_tag(sd_device *dev, EventMode mode, const char *path) { char tag[UDEV_NAME_SIZE]; size_t i = 0; - int r; /* compose valid udev tag name */ for (const char *p = path; *p; p++) { @@ -705,115 +693,111 @@ static void add_id_tag(sd_device *dev, bool test, const char *path) { i--; tag[i] = '\0'; - r = udev_builtin_add_property(dev, test, "ID_PATH_TAG", tag); - if (r < 0) - log_device_debug_errno(dev, r, "Failed to add ID_PATH_TAG property, ignoring: %m"); + (void) udev_builtin_add_property(dev, mode, "ID_PATH_TAG", tag); } -static int builtin_path_id(UdevEvent *event, int argc, char *argv[], bool test) { +static int builtin_path_id(UdevEvent *event, int argc, char *argv[]) { sd_device *dev = ASSERT_PTR(ASSERT_PTR(event)->dev); _cleanup_(sd_device_unrefp) sd_device *dev_other_branch = NULL; _cleanup_free_ char *path = NULL, *compat_path = NULL; bool supported_transport = false, supported_parent = false; - const char *subsystem; int r; /* walk up the chain of devices and compose path */ for (sd_device *parent = dev; parent; ) { - const char *subsys, *sysname; + const char *sysname; - if (sd_device_get_subsystem(parent, &subsys) < 0 || - sd_device_get_sysname(parent, &sysname) < 0) { + if (sd_device_get_sysname(parent, &sysname) < 0) { ; - } else if (streq(subsys, "scsi_tape")) { + } else if (device_in_subsystem(parent, "scsi_tape")) { handle_scsi_tape(parent, &path); - } else if (streq(subsys, "scsi")) { + } else if (device_in_subsystem(parent, "scsi")) { parent = handle_scsi(parent, &path, &compat_path, &supported_parent); supported_transport = true; - } else if (streq(subsys, "cciss")) { + } else if (device_in_subsystem(parent, "cciss")) { parent = handle_cciss(parent, &path); supported_transport = true; - } else if (streq(subsys, "usb")) { + } else if (device_in_subsystem(parent, "usb")) { parent = handle_usb(parent, &path); supported_transport = true; - } else if (streq(subsys, "bcma")) { + } else if (device_in_subsystem(parent, "bcma")) { parent = handle_bcma(parent, &path); supported_transport = true; - } else if (streq(subsys, "serio")) { + } else if (device_in_subsystem(parent, "serio")) { const char *sysnum; if (sd_device_get_sysnum(parent, &sysnum) >= 0 && sysnum) { path_prepend(&path, "serio-%s", sysnum); parent = skip_subsystem(parent, "serio"); } - } else if (streq(subsys, "pci")) { + } else if (device_in_subsystem(parent, "pci")) { path_prepend(&path, "pci-%s", sysname); if (compat_path) path_prepend(&compat_path, "pci-%s", sysname); parent = skip_subsystem(parent, "pci"); supported_parent = true; - } else if (streq(subsys, "platform")) { + } else if (device_in_subsystem(parent, "platform")) { path_prepend(&path, "platform-%s", sysname); if (compat_path) path_prepend(&compat_path, "platform-%s", sysname); parent = skip_subsystem(parent, "platform"); supported_transport = true; supported_parent = true; - } else if (streq(subsys, "amba")) { + } else if (device_in_subsystem(parent, "amba")) { path_prepend(&path, "amba-%s", sysname); if (compat_path) path_prepend(&compat_path, "amba-%s", sysname); parent = skip_subsystem(parent, "amba"); supported_transport = true; supported_parent = true; - } else if (streq(subsys, "acpi")) { + } else if (device_in_subsystem(parent, "acpi")) { path_prepend(&path, "acpi-%s", sysname); if (compat_path) path_prepend(&compat_path, "acpi-%s", sysname); parent = skip_subsystem(parent, "acpi"); supported_parent = true; - } else if (streq(subsys, "xen")) { + } else if (device_in_subsystem(parent, "xen")) { path_prepend(&path, "xen-%s", sysname); if (compat_path) path_prepend(&compat_path, "xen-%s", sysname); parent = skip_subsystem(parent, "xen"); supported_parent = true; - } else if (streq(subsys, "virtio")) { + } else if (device_in_subsystem(parent, "virtio")) { parent = skip_subsystem(parent, "virtio"); supported_transport = true; - } else if (streq(subsys, "scm")) { + } else if (device_in_subsystem(parent, "scm")) { path_prepend(&path, "scm-%s", sysname); if (compat_path) path_prepend(&compat_path, "scm-%s", sysname); parent = skip_subsystem(parent, "scm"); supported_transport = true; supported_parent = true; - } else if (streq(subsys, "ccw")) { + } else if (device_in_subsystem(parent, "ccw")) { path_prepend(&path, "ccw-%s", sysname); if (compat_path) path_prepend(&compat_path, "ccw-%s", sysname); parent = skip_subsystem(parent, "ccw"); supported_transport = true; supported_parent = true; - } else if (streq(subsys, "ccwgroup")) { + } else if (device_in_subsystem(parent, "ccwgroup")) { path_prepend(&path, "ccwgroup-%s", sysname); if (compat_path) path_prepend(&compat_path, "ccwgroup-%s", sysname); parent = skip_subsystem(parent, "ccwgroup"); supported_transport = true; supported_parent = true; - } else if (streq(subsys, "ap")) { + } else if (device_in_subsystem(parent, "ap")) { parent = handle_ap(parent, &path); supported_transport = true; supported_parent = true; - } else if (streq(subsys, "iucv")) { + } else if (device_in_subsystem(parent, "iucv")) { path_prepend(&path, "iucv-%s", sysname); if (compat_path) path_prepend(&compat_path, "iucv-%s", sysname); parent = skip_subsystem(parent, "iucv"); supported_transport = true; supported_parent = true; - } else if (STR_IN_SET(subsys, "nvme", "nvme-subsystem")) { + } else if (device_in_subsystem(parent, "nvme") || device_in_subsystem(parent, "nvme-subsystem")) { const char *nsid; if (sd_device_get_sysattr_value(dev, "nsid", &nsid) >= 0) { @@ -821,7 +805,7 @@ static int builtin_path_id(UdevEvent *event, int argc, char *argv[], bool test) if (compat_path) path_prepend(&compat_path, "nvme-%s", nsid); - if (streq(subsys, "nvme-subsystem")) { + if (device_in_subsystem(parent, "nvme-subsystem")) { r = find_real_nvme_parent(dev, &dev_other_branch); if (r < 0) return r; @@ -833,7 +817,7 @@ static int builtin_path_id(UdevEvent *event, int argc, char *argv[], bool test) supported_parent = true; supported_transport = true; } - } else if (streq(subsys, "spi")) { + } else if (device_in_subsystem(parent, "spi")) { const char *sysnum; if (sd_device_get_sysnum(parent, &sysnum) >= 0 && sysnum) { @@ -864,18 +848,14 @@ static int builtin_path_id(UdevEvent *event, int argc, char *argv[], bool test) * devices do not expose their buses and do not provide a unique * and predictable name that way. */ - if (sd_device_get_subsystem(dev, &subsystem) >= 0 && - streq(subsystem, "block") && - !supported_transport) + if (device_in_subsystem(dev, "block") && !supported_transport) return -ENOENT; - add_id_with_usb_revision(dev, test, path); + add_id_with_usb_revision(dev, event->event_mode, path); - r = udev_builtin_add_property(dev, test, "ID_PATH", path); - if (r < 0) - log_device_debug_errno(dev, r, "Failed to add ID_PATH property, ignoring: %m"); + (void) udev_builtin_add_property(dev, event->event_mode, "ID_PATH", path); - add_id_tag(dev, test, path); + add_id_tag(dev, event->event_mode, path); /* * Compatible link generation for ATA devices @@ -883,7 +863,7 @@ static int builtin_path_id(UdevEvent *event, int argc, char *argv[], bool test) * ID_PATH_ATA_COMPAT */ if (compat_path) - udev_builtin_add_property(dev, test, "ID_PATH_ATA_COMPAT", compat_path); + (void) udev_builtin_add_property(dev, event->event_mode, "ID_PATH_ATA_COMPAT", compat_path); return 0; } diff --git a/src/udev/udev-builtin-uaccess.c b/src/udev/udev-builtin-uaccess.c index da42ef5..805d048 100644 --- a/src/udev/udev-builtin-uaccess.c +++ b/src/udev/udev-builtin-uaccess.c @@ -17,13 +17,18 @@ #include "log.h" #include "udev-builtin.h" -static int builtin_uaccess(UdevEvent *event, int argc, char *argv[], bool test) { +static int builtin_uaccess(UdevEvent *event, int argc, char *argv[]) { sd_device *dev = ASSERT_PTR(ASSERT_PTR(event)->dev); const char *path = NULL, *seat; bool changed_acl = false; uid_t uid; int r; + if (event->event_mode != EVENT_UDEV_WORKER) { + log_device_debug(dev, "Running in test mode, skipping execution of 'uaccess' builtin command."); + return 0; + } + umask(0022); /* don't muck around with ACLs when the system is not running systemd */ diff --git a/src/udev/udev-builtin-usb_id.c b/src/udev/udev-builtin-usb_id.c index 8e83c9c..2413f9c 100644 --- a/src/udev/udev-builtin-usb_id.c +++ b/src/udev/udev-builtin-usb_id.c @@ -224,7 +224,7 @@ static int dev_if_packed_info(sd_device *dev, char *ifs_str, size_t len) { * 6.) If the device supplies a serial number, this number * is concatenated with the identification with an underscore '_'. */ -static int builtin_usb_id(UdevEvent *event, int argc, char *argv[], bool test) { +static int builtin_usb_id(UdevEvent *event, int argc, char *argv[]) { sd_device *dev = ASSERT_PTR(ASSERT_PTR(event)->dev); char vendor_str[64] = ""; char vendor_str_enc[256]; @@ -248,7 +248,7 @@ static int builtin_usb_id(UdevEvent *event, int argc, char *argv[], bool test) { size_t l; char *s; - const char *syspath, *sysname, *devtype, *interface_syspath; + const char *syspath, *sysname, *interface_syspath; int r; r = sd_device_get_syspath(dev, &syspath); @@ -260,7 +260,7 @@ static int builtin_usb_id(UdevEvent *event, int argc, char *argv[], bool test) { return r; /* shortcut, if we are called directly for a "usb_device" type */ - if (sd_device_get_devtype(dev, &devtype) >= 0 && streq(devtype, "usb_device")) { + if (device_is_devtype(dev, "usb_device")) { dev_if_packed_info(dev, packed_if_str, sizeof(packed_if_str)); dev_usb = dev; goto fallback; @@ -429,55 +429,55 @@ fallback: if (sd_device_get_property_value(dev, "ID_BUS", NULL) >= 0) log_device_debug(dev, "ID_BUS property is already set, setting only properties prefixed with \"ID_USB_\"."); else { - udev_builtin_add_property(dev, test, "ID_BUS", "usb"); + udev_builtin_add_property(dev, event->event_mode, "ID_BUS", "usb"); - udev_builtin_add_property(dev, test, "ID_MODEL", model_str); - udev_builtin_add_property(dev, test, "ID_MODEL_ENC", model_str_enc); - udev_builtin_add_property(dev, test, "ID_MODEL_ID", product_id); + udev_builtin_add_property(dev, event->event_mode, "ID_MODEL", model_str); + udev_builtin_add_property(dev, event->event_mode, "ID_MODEL_ENC", model_str_enc); + udev_builtin_add_property(dev, event->event_mode, "ID_MODEL_ID", product_id); - udev_builtin_add_property(dev, test, "ID_SERIAL", serial); + udev_builtin_add_property(dev, event->event_mode, "ID_SERIAL", serial); if (!isempty(serial_str)) - udev_builtin_add_property(dev, test, "ID_SERIAL_SHORT", serial_str); + udev_builtin_add_property(dev, event->event_mode, "ID_SERIAL_SHORT", serial_str); - udev_builtin_add_property(dev, test, "ID_VENDOR", vendor_str); - udev_builtin_add_property(dev, test, "ID_VENDOR_ENC", vendor_str_enc); - udev_builtin_add_property(dev, test, "ID_VENDOR_ID", vendor_id); + udev_builtin_add_property(dev, event->event_mode, "ID_VENDOR", vendor_str); + udev_builtin_add_property(dev, event->event_mode, "ID_VENDOR_ENC", vendor_str_enc); + udev_builtin_add_property(dev, event->event_mode, "ID_VENDOR_ID", vendor_id); - udev_builtin_add_property(dev, test, "ID_REVISION", revision_str); + udev_builtin_add_property(dev, event->event_mode, "ID_REVISION", revision_str); if (!isempty(type_str)) - udev_builtin_add_property(dev, test, "ID_TYPE", type_str); + udev_builtin_add_property(dev, event->event_mode, "ID_TYPE", type_str); if (!isempty(instance_str)) - udev_builtin_add_property(dev, test, "ID_INSTANCE", instance_str); + udev_builtin_add_property(dev, event->event_mode, "ID_INSTANCE", instance_str); } /* Also export the same values in the above by prefixing ID_USB_. */ - udev_builtin_add_property(dev, test, "ID_USB_MODEL", model_str); - udev_builtin_add_property(dev, test, "ID_USB_MODEL_ENC", model_str_enc); - udev_builtin_add_property(dev, test, "ID_USB_MODEL_ID", product_id); - udev_builtin_add_property(dev, test, "ID_USB_SERIAL", serial); + udev_builtin_add_property(dev, event->event_mode, "ID_USB_MODEL", model_str); + udev_builtin_add_property(dev, event->event_mode, "ID_USB_MODEL_ENC", model_str_enc); + udev_builtin_add_property(dev, event->event_mode, "ID_USB_MODEL_ID", product_id); + udev_builtin_add_property(dev, event->event_mode, "ID_USB_SERIAL", serial); if (!isempty(serial_str)) - udev_builtin_add_property(dev, test, "ID_USB_SERIAL_SHORT", serial_str); + udev_builtin_add_property(dev, event->event_mode, "ID_USB_SERIAL_SHORT", serial_str); - udev_builtin_add_property(dev, test, "ID_USB_VENDOR", vendor_str); - udev_builtin_add_property(dev, test, "ID_USB_VENDOR_ENC", vendor_str_enc); - udev_builtin_add_property(dev, test, "ID_USB_VENDOR_ID", vendor_id); + udev_builtin_add_property(dev, event->event_mode, "ID_USB_VENDOR", vendor_str); + udev_builtin_add_property(dev, event->event_mode, "ID_USB_VENDOR_ENC", vendor_str_enc); + udev_builtin_add_property(dev, event->event_mode, "ID_USB_VENDOR_ID", vendor_id); - udev_builtin_add_property(dev, test, "ID_USB_REVISION", revision_str); + udev_builtin_add_property(dev, event->event_mode, "ID_USB_REVISION", revision_str); if (!isempty(type_str)) - udev_builtin_add_property(dev, test, "ID_USB_TYPE", type_str); + udev_builtin_add_property(dev, event->event_mode, "ID_USB_TYPE", type_str); if (!isempty(instance_str)) - udev_builtin_add_property(dev, test, "ID_USB_INSTANCE", instance_str); + udev_builtin_add_property(dev, event->event_mode, "ID_USB_INSTANCE", instance_str); if (!isempty(packed_if_str)) - udev_builtin_add_property(dev, test, "ID_USB_INTERFACES", packed_if_str); + udev_builtin_add_property(dev, event->event_mode, "ID_USB_INTERFACES", packed_if_str); if (ifnum) - udev_builtin_add_property(dev, test, "ID_USB_INTERFACE_NUM", ifnum); + udev_builtin_add_property(dev, event->event_mode, "ID_USB_INTERFACE_NUM", ifnum); if (driver) - udev_builtin_add_property(dev, test, "ID_USB_DRIVER", driver); + udev_builtin_add_property(dev, event->event_mode, "ID_USB_DRIVER", driver); return 0; } diff --git a/src/udev/udev-builtin.c b/src/udev/udev-builtin.c index bcc2018..1a1cb37 100644 --- a/src/udev/udev-builtin.c +++ b/src/udev/udev-builtin.c @@ -99,7 +99,7 @@ UdevBuiltinCommand udev_builtin_lookup(const char *command) { return _UDEV_BUILTIN_INVALID; } -int udev_builtin_run(UdevEvent *event, UdevBuiltinCommand cmd, const char *command, bool test) { +int udev_builtin_run(UdevEvent *event, UdevBuiltinCommand cmd, const char *command) { _cleanup_strv_free_ char **argv = NULL; int r; @@ -117,10 +117,10 @@ int udev_builtin_run(UdevEvent *event, UdevBuiltinCommand cmd, const char *comma /* we need '0' here to reset the internal state */ optind = 0; - return builtins[cmd]->cmd(event, strv_length(argv), argv, test); + return builtins[cmd]->cmd(event, strv_length(argv), argv); } -int udev_builtin_add_property(sd_device *dev, bool test, const char *key, const char *val) { +int udev_builtin_add_property(sd_device *dev, EventMode mode, const char *key, const char *val) { int r; assert(dev); @@ -131,13 +131,13 @@ int udev_builtin_add_property(sd_device *dev, bool test, const char *key, const return log_device_debug_errno(dev, r, "Failed to add property '%s%s%s'", key, val ? "=" : "", strempty(val)); - if (test) + if (mode == EVENT_UDEVADM_TEST_BUILTIN) printf("%s=%s\n", key, strempty(val)); return 0; } -int udev_builtin_add_propertyf(sd_device *dev, bool test, const char *key, const char *valf, ...) { +int udev_builtin_add_propertyf(sd_device *dev, EventMode mode, const char *key, const char *valf, ...) { _cleanup_free_ char *val = NULL; va_list ap; int r; @@ -152,5 +152,28 @@ int udev_builtin_add_propertyf(sd_device *dev, bool test, const char *key, const if (r < 0) return log_oom_debug(); - return udev_builtin_add_property(dev, test, key, val); + return udev_builtin_add_property(dev, mode, key, val); +} + +int udev_builtin_import_property(sd_device *dev, sd_device *src, EventMode mode, const char *key) { + const char *val; + int r; + + assert(dev); + assert(key); + + if (!src) + return 0; + + r = sd_device_get_property_value(src, key, &val); + if (r == -ENOENT) + return 0; + if (r < 0) + return log_device_debug_errno(src, r, "Failed to get property \"%s\", ignoring: %m", key); + + r = udev_builtin_add_property(dev, mode, key, val); + if (r < 0) + return r; + + return 1; } diff --git a/src/udev/udev-builtin.h b/src/udev/udev-builtin.h index fcd41d6..0d82beb 100644 --- a/src/udev/udev-builtin.h +++ b/src/udev/udev-builtin.h @@ -34,7 +34,7 @@ typedef enum UdevBuiltinCommand { typedef struct UdevBuiltin { const char *name; - int (*cmd)(UdevEvent *event, int argc, char *argv[], bool test); + int (*cmd)(UdevEvent *event, int argc, char *argv[]); const char *help; int (*init)(void); void (*exit)(void); @@ -79,10 +79,11 @@ void udev_builtin_exit(void); UdevBuiltinCommand udev_builtin_lookup(const char *command); const char *udev_builtin_name(UdevBuiltinCommand cmd); bool udev_builtin_run_once(UdevBuiltinCommand cmd); -int udev_builtin_run(UdevEvent *event, UdevBuiltinCommand cmd, const char *command, bool test); +int udev_builtin_run(UdevEvent *event, UdevBuiltinCommand cmd, const char *command); void udev_builtin_list(void); bool udev_builtin_should_reload(void); -int udev_builtin_add_property(sd_device *dev, bool test, const char *key, const char *val); -int udev_builtin_add_propertyf(sd_device *dev, bool test, const char *key, const char *valf, ...) _printf_(4, 5); +int udev_builtin_add_property(sd_device *dev, EventMode mode, const char *key, const char *val); +int udev_builtin_add_propertyf(sd_device *dev, EventMode mode, const char *key, const char *valf, ...) _printf_(4, 5); +int udev_builtin_import_property(sd_device *dev, sd_device *src, EventMode mode, const char *key); int udev_builtin_hwdb_lookup(sd_device *dev, const char *prefix, const char *modalias, - const char *filter, bool test); + const char *filter, EventMode mode); diff --git a/src/udev/udev-event.c b/src/udev/udev-event.c index ed22c8b..607071a 100644 --- a/src/udev/udev-event.c +++ b/src/udev/udev-event.c @@ -14,10 +14,10 @@ #include "udev-node.h" #include "udev-trace.h" #include "udev-util.h" -#include "udev-watch.h" #include "user-util.h" -UdevEvent *udev_event_new(sd_device *dev, usec_t exec_delay_usec, sd_netlink *rtnl, int log_level) { +UdevEvent *udev_event_new(sd_device *dev, UdevWorker *worker, EventMode mode) { + int log_level = worker ? worker->log_level : log_get_max_level(); UdevEvent *event; assert(dev); @@ -27,15 +27,16 @@ UdevEvent *udev_event_new(sd_device *dev, usec_t exec_delay_usec, sd_netlink *rt return NULL; *event = (UdevEvent) { + .worker = worker, + .rtnl = worker ? sd_netlink_ref(worker->rtnl) : NULL, .dev = sd_device_ref(dev), .birth_usec = now(CLOCK_MONOTONIC), - .exec_delay_usec = exec_delay_usec, - .rtnl = sd_netlink_ref(rtnl), .uid = UID_INVALID, .gid = GID_INVALID, .mode = MODE_INVALID, .log_level_was_debug = log_level == LOG_DEBUG, .default_log_level = log_level, + .event_mode = mode, }; return event; @@ -110,6 +111,9 @@ static int rename_netif(UdevEvent *event) { assert(event); + if (!EVENT_MODE_DESTRUCTIVE(event)) + return 0; + if (!event->name) return 0; /* No new name is requested. */ @@ -171,6 +175,12 @@ static int rename_netif(UdevEvent *event) { goto revert; } + r = device_add_property(event->dev_db_clone, "ID_PROCESSING", "1"); + if (r < 0) { + log_device_warning_errno(event->dev_db_clone, r, "Failed to add 'ID_PROCESSING' property: %m"); + goto revert; + } + r = device_update_db(event->dev_db_clone); if (r < 0) { log_device_debug_errno(event->dev_db_clone, r, "Failed to update database under /run/udev/data/: %m"); @@ -197,6 +207,7 @@ static int rename_netif(UdevEvent *event) { revert: /* Restore 'dev_db_clone' */ (void) device_add_property(event->dev_db_clone, "ID_RENAMING", NULL); + (void) device_add_property(event->dev_db_clone, "ID_PROCESSING", NULL); (void) device_update_db(event->dev_db_clone); /* Restore 'dev' */ @@ -215,6 +226,9 @@ static int assign_altnames(UdevEvent *event) { int ifindex, r; const char *s; + if (!EVENT_MODE_DESTRUCTIVE(event)) + return 0; + if (strv_isempty(event->altnames)) return 0; @@ -243,6 +257,9 @@ static int update_devnode(UdevEvent *event) { sd_device *dev = ASSERT_PTR(ASSERT_PTR(event)->dev); int r; + if (!EVENT_MODE_DESTRUCTIVE(event)) + return 0; + r = sd_device_get_devnum(dev, NULL); if (r == -ENOENT) return 0; @@ -276,14 +293,7 @@ static int update_devnode(UdevEvent *event) { return udev_node_update(dev, event->dev_db_clone); } -static int event_execute_rules_on_remove( - UdevEvent *event, - int inotify_fd, - usec_t timeout_usec, - int timeout_signal, - Hashmap *properties_list, - UdevRules *rules) { - +static int event_execute_rules_on_remove(UdevEvent *event, UdevRules *rules) { sd_device *dev = ASSERT_PTR(ASSERT_PTR(event)->dev); int r; @@ -291,22 +301,22 @@ static int event_execute_rules_on_remove( if (r < 0) log_device_debug_errno(dev, r, "Failed to read database under /run/udev/data/: %m"); - r = device_tag_index(dev, NULL, false); - if (r < 0) - log_device_debug_errno(dev, r, "Failed to remove corresponding tag files under /run/udev/tag/, ignoring: %m"); - - r = device_delete_db(dev); - if (r < 0) - log_device_debug_errno(dev, r, "Failed to delete database under /run/udev/data/, ignoring: %m"); + if (EVENT_MODE_DESTRUCTIVE(event)) { + r = device_tag_index(dev, NULL, false); + if (r < 0) + log_device_debug_errno(dev, r, "Failed to remove corresponding tag files under /run/udev/tag/, ignoring: %m"); - r = udev_watch_end(inotify_fd, dev); - if (r < 0) - log_device_warning_errno(dev, r, "Failed to remove inotify watch, ignoring: %m"); + r = device_delete_db(dev); + if (r < 0) + log_device_debug_errno(dev, r, "Failed to delete database under /run/udev/data/, ignoring: %m"); + } - r = udev_rules_apply_to_event(rules, event, timeout_usec, timeout_signal, properties_list); + r = udev_rules_apply_to_event(rules, event); - if (sd_device_get_devnum(dev, NULL) >= 0) - (void) udev_node_remove(dev); + if (EVENT_MODE_DESTRUCTIVE(event)) { + if (sd_device_get_devnum(dev, NULL) >= 0) + (void) udev_node_remove(dev); + } return r; } @@ -328,19 +338,45 @@ static int copy_all_tags(sd_device *d, sd_device *s) { return 0; } -int udev_event_execute_rules( - UdevEvent *event, - int inotify_fd, /* This may be negative */ - usec_t timeout_usec, - int timeout_signal, - Hashmap *properties_list, - UdevRules *rules) { +static int update_clone(UdevEvent *event) { + sd_device *dev = ASSERT_PTR(ASSERT_PTR(event)->dev_db_clone); + int r; + + if (!EVENT_MODE_DESTRUCTIVE(event)) + return 0; + + /* Drop previously added property for safety to make IMPORT{db}="ID_RENAMING" not work. This is + * mostly for 'move' uevent, but let's do unconditionally. Why? If a network interface is renamed in + * initrd, then udevd may lose the 'move' uevent during switching root. Usually, we do not set the + * persistent flag for network interfaces, but user may set it. Just for safety. */ + r = device_add_property(dev, "ID_RENAMING", NULL); + if (r < 0) + return log_device_debug_errno(dev, r, "Failed to remove 'ID_RENAMING' property: %m"); + + /* If the database file already exists, append ID_PROCESSING property to the existing database, + * to indicate that the device is being processed by udevd. */ + if (device_has_db(dev) > 0) { + r = device_add_property(dev, "ID_PROCESSING", "1"); + if (r < 0) + return log_device_warning_errno(dev, r, "Failed to add 'ID_PROCESSING' property: %m"); + + r = device_update_db(dev); + if (r < 0) + return log_device_warning_errno(dev, r, "Failed to update database under /run/udev/data/: %m"); + } + + return 0; +} + +int udev_event_execute_rules(UdevEvent *event, UdevRules *rules) { sd_device_action_t action; sd_device *dev; int r; - dev = ASSERT_PTR(ASSERT_PTR(event)->dev); + assert(event); + assert(IN_SET(event->event_mode, EVENT_UDEV_WORKER, EVENT_UDEVADM_TEST, EVENT_TEST_RULE_RUNNER)); + dev = ASSERT_PTR(event->dev); assert(rules); r = sd_device_get_action(dev, &action); @@ -348,12 +384,7 @@ int udev_event_execute_rules( return log_device_error_errno(dev, r, "Failed to get ACTION: %m"); if (action == SD_DEVICE_REMOVE) - return event_execute_rules_on_remove(event, inotify_fd, timeout_usec, timeout_signal, properties_list, rules); - - /* Disable watch during event processing. */ - r = udev_watch_end(inotify_fd, dev); - if (r < 0) - log_device_warning_errno(dev, r, "Failed to remove inotify watch, ignoring: %m"); + return event_execute_rules_on_remove(event, rules); r = device_clone_with_db(dev, &event->dev_db_clone); if (r < 0) @@ -363,17 +394,13 @@ int udev_event_execute_rules( if (r < 0) log_device_warning_errno(dev, r, "Failed to copy all tags from old database entry, ignoring: %m"); - /* Drop previously added property for safety to make IMPORT{db}="ID_RENAMING" not work. This is - * mostly for 'move' uevent, but let's do unconditionally. Why? If a network interface is renamed in - * initrd, then udevd may lose the 'move' uevent during switching root. Usually, we do not set the - * persistent flag for network interfaces, but user may set it. Just for safety. */ - r = device_add_property(event->dev_db_clone, "ID_RENAMING", NULL); + r = update_clone(event); if (r < 0) - return log_device_debug_errno(dev, r, "Failed to remove 'ID_RENAMING' property: %m"); + return r; DEVICE_TRACE_POINT(rules_start, dev); - r = udev_rules_apply_to_event(rules, event, timeout_usec, timeout_signal, properties_list); + r = udev_rules_apply_to_event(rules, event); if (r < 0) return log_device_debug_errno(dev, r, "Failed to apply udev rules: %m"); @@ -396,14 +423,27 @@ int udev_event_execute_rules( if (r < 0) return log_device_debug_errno(dev, r, "Failed to set initialization timestamp: %m"); - /* (re)write database file */ - r = device_tag_index(dev, event->dev_db_clone, true); - if (r < 0) - return log_device_debug_errno(dev, r, "Failed to update tags under /run/udev/tag/: %m"); + if (EVENT_MODE_DESTRUCTIVE(event)) { + /* (re)write database file */ + r = device_tag_index(dev, event->dev_db_clone, true); + if (r < 0) + return log_device_debug_errno(dev, r, "Failed to update tags under /run/udev/tag/: %m"); + } - r = device_update_db(dev); - if (r < 0) - return log_device_debug_errno(dev, r, "Failed to update database under /run/udev/data/: %m"); + /* If the database file for the device will be created below, add ID_PROCESSING=1 to indicate that + * the device is still being processed by udevd, as commands specified in RUN are invoked after + * the database is created. See issue #30056. */ + if (device_should_have_db(dev) && !ordered_hashmap_isempty(event->run_list)) { + r = device_add_property(dev, "ID_PROCESSING", "1"); + if (r < 0) + return log_device_warning_errno(dev, r, "Failed to add 'ID_PROCESSING' property: %m"); + } + + if (EVENT_MODE_DESTRUCTIVE(event)) { + r = device_update_db(dev); + if (r < 0) + return log_device_debug_errno(dev, r, "Failed to update database under /run/udev/data/: %m"); + } device_set_is_initialized(dev); diff --git a/src/udev/udev-event.h b/src/udev/udev-event.h index 6b94fd0..3dc8936 100644 --- a/src/udev/udev-event.h +++ b/src/udev/udev-event.h @@ -15,9 +15,21 @@ #include "macro.h" #include "time-util.h" #include "udev-rules.h" +#include "udev-worker.h" #include "user-util.h" +typedef enum EventMode { + EVENT_UDEV_WORKER, + EVENT_UDEVADM_TEST, + EVENT_UDEVADM_TEST_BUILTIN, + EVENT_TEST_RULE_RUNNER, + EVENT_TEST_SPAWN, +} EventMode; + typedef struct UdevEvent { + UdevWorker *worker; + sd_netlink *rtnl; + sd_device *dev; sd_device *dev_parent; sd_device *dev_db_clone; @@ -29,9 +41,7 @@ typedef struct UdevEvent { gid_t gid; OrderedHashmap *seclabel_list; OrderedHashmap *run_list; - usec_t exec_delay_usec; usec_t birth_usec; - sd_netlink *rtnl; unsigned builtin_run; unsigned builtin_ret; UdevRuleEscapeType esc:8; @@ -45,16 +55,16 @@ typedef struct UdevEvent { bool run_final; bool log_level_was_debug; int default_log_level; + EventMode event_mode; } UdevEvent; -UdevEvent *udev_event_new(sd_device *dev, usec_t exec_delay_usec, sd_netlink *rtnl, int log_level); +UdevEvent *udev_event_new(sd_device *dev, UdevWorker *worker, EventMode mode); UdevEvent *udev_event_free(UdevEvent *event); DEFINE_TRIVIAL_CLEANUP_FUNC(UdevEvent*, udev_event_free); -int udev_event_execute_rules( - UdevEvent *event, - int inotify_fd, - usec_t timeout_usec, - int timeout_signal, - Hashmap *properties_list, - UdevRules *rules); +int udev_event_execute_rules(UdevEvent *event, UdevRules *rules); + +static inline bool EVENT_MODE_DESTRUCTIVE(UdevEvent *event) { + assert(event); + return IN_SET(event->event_mode, EVENT_UDEV_WORKER, EVENT_TEST_RULE_RUNNER); +} diff --git a/src/udev/udev-format.c b/src/udev/udev-format.c index 05ed9fd..bd74ab0 100644 --- a/src/udev/udev-format.c +++ b/src/udev/udev-format.c @@ -156,7 +156,6 @@ static ssize_t udev_event_subst_format( const char *attr, char *dest, size_t l, - Hashmap *global_props, bool *ret_truncated) { sd_device *parent, *dev = ASSERT_PTR(ASSERT_PTR(event)->dev); @@ -349,7 +348,7 @@ static ssize_t udev_event_subst_format( case FORMAT_SUBST_ENV: if (isempty(attr)) return -EINVAL; - r = device_get_property_value_with_fallback(dev, attr, global_props, &val); + r = device_get_property_value_with_fallback(dev, attr, event->worker ? event->worker->properties : NULL, &val); if (r == -ENOENT) goto null_terminate; if (r < 0) @@ -379,7 +378,6 @@ size_t udev_event_apply_format( char *dest, size_t size, bool replace_whitespace, - Hashmap *global_props, bool *ret_truncated) { bool truncated = false; @@ -412,7 +410,7 @@ size_t udev_event_apply_format( continue; } - subst_len = udev_event_subst_format(event, type, attr, dest, size, global_props, &t); + subst_len = udev_event_subst_format(event, type, attr, dest, size, &t); if (subst_len < 0) { log_device_warning_errno(event->dev, subst_len, "Failed to substitute variable '$%s' or apply format '%%%c', ignoring: %m", diff --git a/src/udev/udev-format.h b/src/udev/udev-format.h index 92fef9b..9914dc0 100644 --- a/src/udev/udev-format.h +++ b/src/udev/udev-format.h @@ -14,7 +14,6 @@ size_t udev_event_apply_format( char *dest, size_t size, bool replace_whitespace, - Hashmap *global_props, bool *ret_truncated); int udev_check_format(const char *value, size_t *offset, const char **hint); diff --git a/src/udev/udev-manager.c b/src/udev/udev-manager.c index 8077e51..bb94478 100644 --- a/src/udev/udev-manager.c +++ b/src/udev/udev-manager.c @@ -274,15 +274,9 @@ static void manager_reload(Manager *manager, bool force) { return; /* If we eat this up, then tell our service manager to just continue */ - (void) sd_notifyf(/* unset= */ false, - "RELOADING=1\n" - "STATUS=Skipping configuration reloading, nothing changed.\n" - "MONOTONIC_USEC=" USEC_FMT, now(CLOCK_MONOTONIC)); + (void) notify_reloading_full("Skipping configuration reloading, nothing changed."); } else { - (void) sd_notifyf(/* unset= */ false, - "RELOADING=1\n" - "STATUS=Flushing configuration...\n" - "MONOTONIC_USEC=" USEC_FMT, now(CLOCK_MONOTONIC)); + (void) notify_reloading(); manager_kill_workers(manager, false); @@ -332,12 +326,38 @@ static int on_event_timeout_warning(sd_event_source *s, uint64_t usec, void *use return 1; } +static usec_t extra_timeout_usec(void) { + static usec_t saved = 10 * USEC_PER_SEC; + static bool parsed = false; + usec_t timeout; + const char *e; + int r; + + if (parsed) + return saved; + + parsed = true; + + e = getenv("SYSTEMD_UDEV_EXTRA_TIMEOUT_SEC"); + if (!e) + return saved; + + r = parse_sec(e, &timeout); + if (r < 0) + log_debug_errno(r, "Failed to parse $SYSTEMD_UDEV_EXTRA_TIMEOUT_SEC=%s, ignoring: %m", e); + + if (timeout > 5 * USEC_PER_HOUR) /* Add an arbitrary upper bound */ + log_debug("Parsed $SYSTEMD_UDEV_EXTRA_TIMEOUT_SEC=%s is too large, ignoring.", e); + else + saved = timeout; + + return saved; +} + static void worker_attach_event(Worker *worker, Event *event) { - Manager *manager; - sd_event *e; + Manager *manager = ASSERT_PTR(ASSERT_PTR(worker)->manager); + sd_event *e = ASSERT_PTR(manager->event); - assert(worker); - assert(worker->manager); assert(event); assert(!event->worker); assert(!worker->event); @@ -347,15 +367,16 @@ static void worker_attach_event(Worker *worker, Event *event) { event->state = EVENT_RUNNING; event->worker = worker; - manager = worker->manager; - e = manager->event; - (void) sd_event_add_time_relative(e, &event->timeout_warning_event, CLOCK_MONOTONIC, udev_warn_timeout(manager->timeout_usec), USEC_PER_SEC, on_event_timeout_warning, event); + /* Manager.timeout_usec is also used as the timeout for running programs specified in + * IMPORT{program}=, PROGRAM=, or RUN=. Here, let's add an extra time before the manager + * kills a worker, to make it possible that the worker detects timed out of spawned programs, + * kills them, and finalizes the event. */ (void) sd_event_add_time_relative(e, &event->timeout_event, CLOCK_MONOTONIC, - manager->timeout_usec, USEC_PER_SEC, + usec_add(manager->timeout_usec, extra_timeout_usec()), USEC_PER_SEC, on_event_timeout, event); } @@ -864,7 +885,7 @@ static int on_ctrl_msg(UdevCtrl *uctrl, UdevCtrlMessageType type, const UdevCtrl switch (type) { case UDEV_CTRL_SET_LOG_LEVEL: - if ((value->intval & LOG_PRIMASK) != value->intval) { + if (LOG_PRI(value->intval) != value->intval) { log_debug("Received invalid udev control message (SET_LOG_LEVEL, %i), ignoring.", value->intval); break; } @@ -1194,13 +1215,33 @@ Manager* manager_new(void) { .worker_watch = EBADF_PAIR, .log_level = LOG_INFO, .resolve_name_timing = RESOLVE_NAME_EARLY, - .timeout_usec = 180 * USEC_PER_SEC, + .timeout_usec = DEFAULT_WORKER_TIMEOUT_USEC, .timeout_signal = SIGKILL, }; return manager; } +void manager_adjust_arguments(Manager *manager) { + assert(manager); + + if (manager->timeout_usec < MIN_WORKER_TIMEOUT_USEC) { + log_debug("Timeout (%s) for processing event is too small, using the default: %s", + FORMAT_TIMESPAN(manager->timeout_usec, 1), + FORMAT_TIMESPAN(DEFAULT_WORKER_TIMEOUT_USEC, 1)); + + manager->timeout_usec = DEFAULT_WORKER_TIMEOUT_USEC; + } + + if (manager->exec_delay_usec >= manager->timeout_usec) { + log_debug("Delay (%s) for executing RUN= commands is too large compared with the timeout (%s) for event execution, ignoring the delay.", + FORMAT_TIMESPAN(manager->exec_delay_usec, 1), + FORMAT_TIMESPAN(manager->timeout_usec, 1)); + + manager->exec_delay_usec = 0; + } +} + int manager_init(Manager *manager, int fd_ctrl, int fd_uevent) { _cleanup_free_ char *cgroup = NULL; int r; @@ -1260,22 +1301,22 @@ int manager_main(Manager *manager) { udev_watch_restore(manager->inotify_fd); - /* block and listen to all signals on signalfd */ - assert_se(sigprocmask_many(SIG_BLOCK, NULL, SIGTERM, SIGINT, SIGHUP, SIGCHLD, SIGRTMIN+18, -1) >= 0); + /* block SIGCHLD for listening child events. */ + assert_se(sigprocmask_many(SIG_BLOCK, NULL, SIGCHLD) >= 0); r = sd_event_default(&manager->event); if (r < 0) return log_error_errno(r, "Failed to allocate event loop: %m"); - r = sd_event_add_signal(manager->event, NULL, SIGINT, on_sigterm, manager); + r = sd_event_add_signal(manager->event, NULL, SIGINT | SD_EVENT_SIGNAL_PROCMASK, on_sigterm, manager); if (r < 0) return log_error_errno(r, "Failed to create SIGINT event source: %m"); - r = sd_event_add_signal(manager->event, NULL, SIGTERM, on_sigterm, manager); + r = sd_event_add_signal(manager->event, NULL, SIGTERM | SD_EVENT_SIGNAL_PROCMASK, on_sigterm, manager); if (r < 0) return log_error_errno(r, "Failed to create SIGTERM event source: %m"); - r = sd_event_add_signal(manager->event, NULL, SIGHUP, on_sighup, manager); + r = sd_event_add_signal(manager->event, NULL, SIGHUP | SD_EVENT_SIGNAL_PROCMASK, on_sighup, manager); if (r < 0) return log_error_errno(r, "Failed to create SIGHUP event source: %m"); @@ -1325,7 +1366,8 @@ int manager_main(Manager *manager) { log_full_errno(ERRNO_IS_NOT_SUPPORTED(r) || ERRNO_IS_PRIVILEGE(r) || (r == -EHOSTDOWN) ? LOG_DEBUG : LOG_WARNING, r, "Failed to allocate memory pressure watch, ignoring: %m"); - r = sd_event_add_signal(manager->event, &manager->memory_pressure_event_source, SIGRTMIN+18, sigrtmin18_handler, NULL); + r = sd_event_add_signal(manager->event, &manager->memory_pressure_event_source, + (SIGRTMIN+18) | SD_EVENT_SIGNAL_PROCMASK, sigrtmin18_handler, NULL); if (r < 0) return log_error_errno(r, "Failed to allocate SIGRTMIN+18 event source, ignoring: %m"); diff --git a/src/udev/udev-manager.h b/src/udev/udev-manager.h index afbc67f..864fc02 100644 --- a/src/udev/udev-manager.h +++ b/src/udev/udev-manager.h @@ -56,6 +56,7 @@ Manager* manager_new(void); Manager* manager_free(Manager *manager); DEFINE_TRIVIAL_CLEANUP_FUNC(Manager*, manager_free); +void manager_adjust_arguments(Manager *manager); int manager_init(Manager *manager, int fd_ctrl, int fd_uevent); int manager_main(Manager *manager); diff --git a/src/udev/udev-node.c b/src/udev/udev-node.c index e12c26c..633fb2a 100644 --- a/src/udev/udev-node.c +++ b/src/udev/udev-node.c @@ -510,22 +510,17 @@ static int link_update(sd_device *dev, const char *slink, bool add) { } static int device_get_devpath_by_devnum(sd_device *dev, char **ret) { - const char *subsystem; dev_t devnum; int r; assert(dev); assert(ret); - r = sd_device_get_subsystem(dev, &subsystem); - if (r < 0) - return r; - r = sd_device_get_devnum(dev, &devnum); if (r < 0) return r; - return device_path_make_major_minor(streq(subsystem, "block") ? S_IFBLK : S_IFCHR, devnum, ret); + return device_path_make_major_minor(device_in_subsystem(dev, "block") ? S_IFBLK : S_IFCHR, devnum, ret); } int udev_node_update(sd_device *dev, sd_device *dev_old) { diff --git a/src/udev/udev-rules.c b/src/udev/udev-rules.c index 5f12002..581bbaf 100644 --- a/src/udev/udev-rules.c +++ b/src/udev/udev-rules.c @@ -691,9 +691,7 @@ static int parse_token(UdevRuleLine *rule_line, const char *key, char *attr, Ude } if (!is_match) { - if (STR_IN_SET(attr, - "ACTION", "DEVLINKS", "DEVNAME", "DEVPATH", "DEVTYPE", "DRIVER", - "IFINDEX", "MAJOR", "MINOR", "SEQNUM", "SUBSYSTEM", "TAGS")) + if (!device_property_can_set(attr)) return log_line_error_errno(rule_line, SYNTHETIC_ERRNO(EINVAL), "Invalid ENV attribute. '%s' cannot be set.", attr); @@ -1538,7 +1536,7 @@ int udev_rules_parse_file(UdevRules *rules, const char *filename, bool extra_che r = hashmap_put_stats_by_path(&rules->stats_by_path, filename, &st); if (r < 0) - return log_warning_errno(errno, "Failed to save stat for %s, ignoring: %m", filename); + return log_warning_errno(r, "Failed to save stat for %s, ignoring: %m", filename); (void) fd_warn_permissions(filename, fileno(f)); @@ -1761,7 +1759,7 @@ static bool token_match_attr(UdevRuleToken *token, sd_device *dev, UdevEvent *ev switch (token->attr_subst_type) { case SUBST_TYPE_FORMAT: - (void) udev_event_apply_format(event, name, nbuf, sizeof(nbuf), false, NULL, &truncated); + (void) udev_event_apply_format(event, name, nbuf, sizeof(nbuf), false, &truncated); if (truncated) { log_event_truncated(dev, token, "sysfs attribute name", name, token->type == TK_M_ATTR ? "ATTR" : "ATTRS", /* is_match = */ true); @@ -1928,10 +1926,7 @@ static size_t udev_replace_ifname(char *str) { static int udev_rule_apply_token_to_event( UdevRuleToken *token, sd_device *dev, - UdevEvent *event, - usec_t timeout_usec, - int timeout_signal, - Hashmap *properties_list) { + UdevEvent *event) { int r; @@ -1983,7 +1978,7 @@ static int udev_rule_apply_token_to_event( case TK_M_ENV: { const char *val = NULL; - (void) device_get_property_value_with_fallback(dev, token->data, properties_list, &val); + (void) device_get_property_value_with_fallback(dev, token->data, event->worker ? event->worker->properties : NULL, &val); return token_match_string(token, val); } @@ -2038,7 +2033,7 @@ static int udev_rule_apply_token_to_event( char buf[UDEV_PATH_SIZE]; bool truncated; - (void) udev_event_apply_format(event, token->data, buf, sizeof(buf), false, properties_list, &truncated); + (void) udev_event_apply_format(event, token->data, buf, sizeof(buf), false, &truncated); if (truncated) { log_event_truncated(dev, token, "sysctl entry name", token->data, "SYSCTL", /* is_match = */ true); return false; @@ -2056,7 +2051,7 @@ static int udev_rule_apply_token_to_event( struct stat statbuf; bool match, truncated; - (void) udev_event_apply_format(event, token->value, buf, sizeof(buf), false, properties_list, &truncated); + (void) udev_event_apply_format(event, token->value, buf, sizeof(buf), false, &truncated); if (truncated) { log_event_truncated(dev, token, "file name", token->value, "TEST", /* is_match = */ true); return false; @@ -2099,15 +2094,15 @@ static int udev_rule_apply_token_to_event( size_t count; event->program_result = mfree(event->program_result); - (void) udev_event_apply_format(event, token->value, buf, sizeof(buf), false, properties_list, &truncated); + (void) udev_event_apply_format(event, token->value, buf, sizeof(buf), false, &truncated); if (truncated) { log_event_truncated(dev, token, "command", token->value, "PROGRAM", /* is_match = */ true); return false; } - log_event_debug(dev, token, "Running PROGRAM '%s'", buf); + log_event_debug(dev, token, "Running PROGRAM=\"%s\"", buf); - r = udev_event_spawn(event, timeout_usec, timeout_signal, true, buf, result, sizeof(result), NULL); + r = udev_event_spawn(event, /* accept_failure = */ true, buf, result, sizeof(result), NULL); if (r != 0) { if (r < 0) log_event_warning_errno(dev, token, r, "Failed to execute \"%s\": %m", buf); @@ -2131,7 +2126,7 @@ static int udev_rule_apply_token_to_event( char buf[UDEV_PATH_SIZE]; bool truncated; - (void) udev_event_apply_format(event, token->value, buf, sizeof(buf), false, properties_list, &truncated); + (void) udev_event_apply_format(event, token->value, buf, sizeof(buf), false, &truncated); if (truncated) { log_event_truncated(dev, token, "file name to be imported", token->value, "IMPORT", /* is_match = */ true); return false; @@ -2182,7 +2177,7 @@ static int udev_rule_apply_token_to_event( char buf[UDEV_LINE_SIZE], result[UDEV_LINE_SIZE]; bool truncated; - (void) udev_event_apply_format(event, token->value, buf, sizeof(buf), false, properties_list, &truncated); + (void) udev_event_apply_format(event, token->value, buf, sizeof(buf), false, &truncated); if (truncated) { log_event_truncated(dev, token, "command", token->value, "IMPORT", /* is_match = */ true); return false; @@ -2190,7 +2185,7 @@ static int udev_rule_apply_token_to_event( log_event_debug(dev, token, "Importing properties from results of '%s'", buf); - r = udev_event_spawn(event, timeout_usec, timeout_signal, true, buf, result, sizeof result, &truncated); + r = udev_event_spawn(event, /* accept_failure = */ true, buf, result, sizeof result, &truncated); if (r != 0) { if (r < 0) log_event_warning_errno(dev, token, r, "Failed to execute '%s', ignoring: %m", buf); @@ -2261,7 +2256,7 @@ static int udev_rule_apply_token_to_event( event->builtin_run |= mask; } - (void) udev_event_apply_format(event, token->value, buf, sizeof(buf), false, properties_list, &truncated); + (void) udev_event_apply_format(event, token->value, buf, sizeof(buf), false, &truncated); if (truncated) { log_event_truncated(dev, token, "builtin command", token->value, "IMPORT", /* is_match = */ true); return false; @@ -2269,7 +2264,7 @@ static int udev_rule_apply_token_to_event( log_event_debug(dev, token, "Importing properties from results of builtin command '%s'", buf); - r = udev_builtin_run(event, cmd, buf, false); + r = udev_builtin_run(event, cmd, buf); if (r < 0) { /* remember failure */ log_event_debug_errno(dev, token, r, "Failed to run builtin '%s': %m", buf); @@ -2317,7 +2312,7 @@ static int udev_rule_apply_token_to_event( char buf[UDEV_PATH_SIZE]; bool truncated; - (void) udev_event_apply_format(event, token->value, buf, sizeof(buf), false, properties_list, &truncated); + (void) udev_event_apply_format(event, token->value, buf, sizeof(buf), false, &truncated); if (truncated) { log_event_truncated(dev, token, "property name", token->value, "IMPORT", /* is_match = */ true); return false; @@ -2378,7 +2373,7 @@ static int udev_rule_apply_token_to_event( if (token->op == OP_ASSIGN_FINAL) event->owner_final = true; - (void) udev_event_apply_format(event, token->value, owner, sizeof(owner), false, properties_list, &truncated); + (void) udev_event_apply_format(event, token->value, owner, sizeof(owner), false, &truncated); if (truncated) { log_event_truncated(dev, token, "user name", token->value, "OWNER", /* is_match = */ false); break; @@ -2401,7 +2396,7 @@ static int udev_rule_apply_token_to_event( if (token->op == OP_ASSIGN_FINAL) event->group_final = true; - (void) udev_event_apply_format(event, token->value, group, sizeof(group), false, properties_list, &truncated); + (void) udev_event_apply_format(event, token->value, group, sizeof(group), false, &truncated); if (truncated) { log_event_truncated(dev, token, "group name", token->value, "GROUP", /* is_match = */ false); break; @@ -2423,7 +2418,7 @@ static int udev_rule_apply_token_to_event( if (token->op == OP_ASSIGN_FINAL) event->mode_final = true; - (void) udev_event_apply_format(event, token->value, mode_str, sizeof(mode_str), false, properties_list, &truncated); + (void) udev_event_apply_format(event, token->value, mode_str, sizeof(mode_str), false, &truncated); if (truncated) { log_event_truncated(dev, token, "mode", token->value, "MODE", /* is_match = */ false); break; @@ -2475,7 +2470,7 @@ static int udev_rule_apply_token_to_event( if (!name) return log_oom(); - (void) udev_event_apply_format(event, token->value, label_str, sizeof(label_str), false, properties_list, &truncated); + (void) udev_event_apply_format(event, token->value, label_str, sizeof(label_str), false, &truncated); if (truncated) { log_event_truncated(dev, token, "security label", token->value, "SECLABEL", /* is_match = */ false); break; @@ -2519,7 +2514,7 @@ static int udev_rule_apply_token_to_event( } if (token->op == OP_ADD && - device_get_property_value_with_fallback(dev, name, properties_list, &val) >= 0) { + device_get_property_value_with_fallback(dev, name, event->worker ? event->worker->properties : NULL, &val) >= 0) { l = strpcpyl_full(&p, l, &truncated, val, " ", NULL); if (truncated) { log_event_warning(dev, token, @@ -2529,7 +2524,7 @@ static int udev_rule_apply_token_to_event( } } - (void) udev_event_apply_format(event, token->value, p, l, false, properties_list, &truncated); + (void) udev_event_apply_format(event, token->value, p, l, false, &truncated); if (truncated) { _cleanup_free_ char *key_with_name = strjoin("ENV{", name, "}"); log_event_truncated(dev, token, "property value", token->value, @@ -2554,7 +2549,7 @@ static int udev_rule_apply_token_to_event( char buf[UDEV_PATH_SIZE]; bool truncated; - (void) udev_event_apply_format(event, token->value, buf, sizeof(buf), false, properties_list, &truncated); + (void) udev_event_apply_format(event, token->value, buf, sizeof(buf), false, &truncated); if (truncated) { log_event_truncated(dev, token, "tag name", token->value, "TAG", /* is_match = */ false); break; @@ -2591,7 +2586,7 @@ static int udev_rule_apply_token_to_event( break; } - (void) udev_event_apply_format(event, token->value, buf, sizeof(buf), false, properties_list, &truncated); + (void) udev_event_apply_format(event, token->value, buf, sizeof(buf), false, &truncated); if (truncated) { log_event_truncated(dev, token, "network interface name", token->value, "NAME", /* is_match = */ false); break; @@ -2629,7 +2624,7 @@ static int udev_rule_apply_token_to_event( device_cleanup_devlinks(dev); (void) udev_event_apply_format(event, token->value, buf, sizeof(buf), - /* replace_whitespace = */ event->esc != ESCAPE_NONE, properties_list, &truncated); + /* replace_whitespace = */ event->esc != ESCAPE_NONE, &truncated); if (truncated) { log_event_truncated(dev, token, "symbolic link path", token->value, "SYMLINK", /* is_match = */ false); break; @@ -2701,33 +2696,37 @@ static int udev_rule_apply_token_to_event( log_event_error_errno(dev, token, r, "Could not find file matches '%s', ignoring: %m", buf); break; } - (void) udev_event_apply_format(event, token->value, value, sizeof(value), false, properties_list, &truncated); + (void) udev_event_apply_format(event, token->value, value, sizeof(value), false, &truncated); if (truncated) { log_event_truncated(dev, token, "attribute value", token->value, "ATTR", /* is_match = */ false); break; } - log_event_debug(dev, token, "ATTR '%s' writing '%s'", buf, value); - r = write_string_file(buf, value, - WRITE_STRING_FILE_VERIFY_ON_FAILURE | - WRITE_STRING_FILE_DISABLE_BUFFER | - WRITE_STRING_FILE_AVOID_NEWLINE | - WRITE_STRING_FILE_VERIFY_IGNORE_NEWLINE); - if (r < 0) - log_event_error_errno(dev, token, r, "Failed to write ATTR{%s}, ignoring: %m", buf); + if (EVENT_MODE_DESTRUCTIVE(event)) { + log_event_debug(dev, token, "Writing ATTR{'%s'}=\"%s\".", buf, value); + r = write_string_file(buf, value, + WRITE_STRING_FILE_VERIFY_ON_FAILURE | + WRITE_STRING_FILE_DISABLE_BUFFER | + WRITE_STRING_FILE_AVOID_NEWLINE | + WRITE_STRING_FILE_VERIFY_IGNORE_NEWLINE); + if (r < 0) + log_event_error_errno(dev, token, r, "Failed to write ATTR{%s}=\"%s\", ignoring: %m", buf, value); + } else + log_event_debug(dev, token, "Running in test mode, skipping writing ATTR{%s}=\"%s\".", buf, value); + break; } case TK_A_SYSCTL: { char buf[UDEV_PATH_SIZE], value[UDEV_NAME_SIZE]; bool truncated; - (void) udev_event_apply_format(event, token->data, buf, sizeof(buf), false, properties_list, &truncated); + (void) udev_event_apply_format(event, token->data, buf, sizeof(buf), false, &truncated); if (truncated) { log_event_truncated(dev, token, "sysctl entry name", token->data, "SYSCTL", /* is_match = */ false); break; } - (void) udev_event_apply_format(event, token->value, value, sizeof(value), false, properties_list, &truncated); + (void) udev_event_apply_format(event, token->value, value, sizeof(value), false, &truncated); if (truncated) { _cleanup_free_ char *key_with_name = strjoin("SYSCTL{", buf, "}"); log_event_truncated(dev, token, "sysctl value", token->value, @@ -2736,10 +2735,15 @@ static int udev_rule_apply_token_to_event( } sysctl_normalize(buf); - log_event_debug(dev, token, "SYSCTL '%s' writing '%s'", buf, value); - r = sysctl_write(buf, value); - if (r < 0) - log_event_error_errno(dev, token, r, "Failed to write SYSCTL{%s}='%s', ignoring: %m", buf, value); + + if (EVENT_MODE_DESTRUCTIVE(event)) { + log_event_debug(dev, token, "Writing SYSCTL{%s}=\"%s\".", buf, value); + r = sysctl_write(buf, value); + if (r < 0) + log_event_error_errno(dev, token, r, "Failed to write SYSCTL{%s}=\"%s\", ignoring: %m", buf, value); + } else + log_event_debug(dev, token, "Running in test mode, skipping writing SYSCTL{%s}=\"%s\".", buf, value); + break; } case TK_A_RUN_BUILTIN: @@ -2756,7 +2760,7 @@ static int udev_rule_apply_token_to_event( if (IN_SET(token->op, OP_ASSIGN, OP_ASSIGN_FINAL)) ordered_hashmap_clear_free_key(event->run_list); - (void) udev_event_apply_format(event, token->value, buf, sizeof(buf), false, properties_list, &truncated); + (void) udev_event_apply_format(event, token->value, buf, sizeof(buf), false, &truncated); if (truncated) { log_event_truncated(dev, token, "command", token->value, token->type == TK_A_RUN_BUILTIN ? "RUN{builtin}" : "RUN{program}", @@ -2793,11 +2797,7 @@ static bool token_is_for_parents(UdevRuleToken *token) { return token->type >= TK_M_PARENTS_KERNEL && token->type <= TK_M_PARENTS_TAG; } -static int udev_rule_apply_parent_token_to_event( - UdevRuleToken *head_token, - UdevEvent *event, - int timeout_signal) { - +static int udev_rule_apply_parent_token_to_event(UdevRuleToken *head_token, UdevEvent *event) { int r; assert(head_token); @@ -2810,7 +2810,7 @@ static int udev_rule_apply_parent_token_to_event( if (!token_is_for_parents(token)) return true; /* All parent tokens match. */ - r = udev_rule_apply_token_to_event(token, event->dev_parent, event, 0, timeout_signal, NULL); + r = udev_rule_apply_token_to_event(token, event->dev_parent, event); if (r < 0) return r; if (r == 0) @@ -2830,9 +2830,6 @@ static int udev_rule_apply_parent_token_to_event( static int udev_rule_apply_line_to_event( UdevRuleLine *line, UdevEvent *event, - usec_t timeout_usec, - int timeout_signal, - Hashmap *properties_list, UdevRuleLine **next_line) { UdevRuleLineType mask = LINE_HAS_GOTO | LINE_UPDATE_SOMETHING; @@ -2868,7 +2865,7 @@ static int udev_rule_apply_line_to_event( if (parents_done) continue; - r = udev_rule_apply_parent_token_to_event(token, event, timeout_signal); + r = udev_rule_apply_parent_token_to_event(token, event); if (r <= 0) return r; @@ -2876,7 +2873,7 @@ static int udev_rule_apply_line_to_event( continue; } - r = udev_rule_apply_token_to_event(token, event->dev, event, timeout_usec, timeout_signal, properties_list); + r = udev_rule_apply_token_to_event(token, event->dev, event); if (r <= 0) return r; } @@ -2887,13 +2884,7 @@ static int udev_rule_apply_line_to_event( return 0; } -int udev_rules_apply_to_event( - UdevRules *rules, - UdevEvent *event, - usec_t timeout_usec, - int timeout_signal, - Hashmap *properties_list) { - +int udev_rules_apply_to_event(UdevRules *rules, UdevEvent *event) { int r; assert(rules); @@ -2901,7 +2892,7 @@ int udev_rules_apply_to_event( LIST_FOREACH(rule_files, file, rules->rule_files) LIST_FOREACH_WITH_NEXT(rule_lines, line, next_line, file->rule_lines) { - r = udev_rule_apply_line_to_event(line, event, timeout_usec, timeout_signal, properties_list, &next_line); + r = udev_rule_apply_line_to_event(line, event, &next_line); if (r < 0) return r; } diff --git a/src/udev/udev-rules.h b/src/udev/udev-rules.h index 4352312..9d19c80 100644 --- a/src/udev/udev-rules.h +++ b/src/udev/udev-rules.h @@ -39,10 +39,7 @@ DEFINE_TRIVIAL_CLEANUP_FUNC(UdevRules*, udev_rules_free); #define udev_rules_free_and_replace(a, b) free_and_replace_full(a, b, udev_rules_free) bool udev_rules_should_reload(UdevRules *rules); -int udev_rules_apply_to_event(UdevRules *rules, UdevEvent *event, - usec_t timeout_usec, - int timeout_signal, - Hashmap *properties_list); +int udev_rules_apply_to_event(UdevRules *rules, UdevEvent *event); int udev_rules_apply_static_dev_perms(UdevRules *rules); ResolveNameTiming resolve_name_timing_from_string(const char *s) _pure_; diff --git a/src/udev/udev-spawn.c b/src/udev/udev-spawn.c index 67a3005..3f867a8 100644 --- a/src/udev/udev-spawn.c +++ b/src/udev/udev-spawn.c @@ -23,6 +23,7 @@ typedef struct Spawn { usec_t timeout_usec; int timeout_signal; usec_t event_birth_usec; + usec_t cmd_birth_usec; bool accept_failure; int fd_stdout; int fd_stderr; @@ -105,19 +106,18 @@ static int on_spawn_timeout(sd_event_source *s, uint64_t usec, void *userdata) { DEVICE_TRACE_POINT(spawn_timeout, spawn->device, spawn->cmd); - kill_and_sigcont(spawn->pid, spawn->timeout_signal); - - log_device_error(spawn->device, "Spawned process '%s' ["PID_FMT"] timed out after %s, killing", + log_device_error(spawn->device, "Spawned process '%s' ["PID_FMT"] timed out after %s, killing.", spawn->cmd, spawn->pid, FORMAT_TIMESPAN(spawn->timeout_usec, USEC_PER_SEC)); + kill_and_sigcont(spawn->pid, spawn->timeout_signal); return 1; } static int on_spawn_timeout_warning(sd_event_source *s, uint64_t usec, void *userdata) { Spawn *spawn = ASSERT_PTR(userdata); - log_device_warning(spawn->device, "Spawned process '%s' ["PID_FMT"] is taking longer than %s to complete", + log_device_warning(spawn->device, "Spawned process '%s' ["PID_FMT"] is taking longer than %s to complete.", spawn->cmd, spawn->pid, FORMAT_TIMESPAN(spawn->timeout_warn_usec, USEC_PER_SEC)); @@ -164,31 +164,20 @@ static int spawn_wait(Spawn *spawn) { if (r < 0) return log_device_debug_errno(spawn->device, r, "Failed to allocate sd-event object: %m"); - if (spawn->timeout_usec > 0) { - usec_t usec, age_usec; - - usec = now(CLOCK_MONOTONIC); - age_usec = usec - spawn->event_birth_usec; - if (age_usec < spawn->timeout_usec) { - if (spawn->timeout_warn_usec > 0 && - spawn->timeout_warn_usec < spawn->timeout_usec && - spawn->timeout_warn_usec > age_usec) { - spawn->timeout_warn_usec -= age_usec; - - r = sd_event_add_time(e, NULL, CLOCK_MONOTONIC, - usec + spawn->timeout_warn_usec, USEC_PER_SEC, - on_spawn_timeout_warning, spawn); - if (r < 0) - return log_device_debug_errno(spawn->device, r, "Failed to create timeout warning event source: %m"); - } - - spawn->timeout_usec -= age_usec; - + if (spawn->timeout_usec != USEC_INFINITY) { + if (spawn->timeout_warn_usec < spawn->timeout_usec) { r = sd_event_add_time(e, NULL, CLOCK_MONOTONIC, - usec + spawn->timeout_usec, USEC_PER_SEC, on_spawn_timeout, spawn); + usec_add(spawn->cmd_birth_usec, spawn->timeout_warn_usec), USEC_PER_SEC, + on_spawn_timeout_warning, spawn); if (r < 0) - return log_device_debug_errno(spawn->device, r, "Failed to create timeout event source: %m"); + return log_device_debug_errno(spawn->device, r, "Failed to create timeout warning event source: %m"); } + + r = sd_event_add_time(e, NULL, CLOCK_MONOTONIC, + usec_add(spawn->cmd_birth_usec, spawn->timeout_usec), USEC_PER_SEC, + on_spawn_timeout, spawn); + if (r < 0) + return log_device_debug_errno(spawn->device, r, "Failed to create timeout event source: %m"); } if (spawn->fd_stdout >= 0) { @@ -222,8 +211,6 @@ static int spawn_wait(Spawn *spawn) { int udev_event_spawn( UdevEvent *event, - usec_t timeout_usec, - int timeout_signal, bool accept_failure, const char *cmd, char *result, @@ -238,9 +225,30 @@ int udev_event_spawn( int r; assert(event); + assert(IN_SET(event->event_mode, EVENT_UDEV_WORKER, EVENT_UDEVADM_TEST, EVENT_TEST_RULE_RUNNER, EVENT_TEST_SPAWN)); assert(event->dev); + assert(cmd); assert(result || result_size == 0); + if (event->event_mode == EVENT_UDEVADM_TEST && + !STARTSWITH_SET(cmd, "ata_id", "cdrom_id", "dmi_memory_id", "fido_id", "mtd_probe", "scsi_id")) { + log_device_debug(event->dev, "Running in test mode, skipping execution of '%s'.", cmd); + result[0] = '\0'; + if (ret_truncated) + *ret_truncated = false; + return 0; + } + + int timeout_signal = event->worker ? event->worker->timeout_signal : SIGKILL; + usec_t timeout_usec = event->worker ? event->worker->timeout_usec : DEFAULT_WORKER_TIMEOUT_USEC; + usec_t now_usec = now(CLOCK_MONOTONIC); + usec_t age_usec = usec_sub_unsigned(now_usec, event->birth_usec); + usec_t cmd_timeout_usec = usec_sub_unsigned(timeout_usec, age_usec); + if (cmd_timeout_usec <= 0) + return log_device_warning_errno(event->dev, SYNTHETIC_ERRNO(ETIME), + "The event already takes longer (%s) than the timeout (%s), skipping execution of '%s'.", + FORMAT_TIMESPAN(age_usec, 1), FORMAT_TIMESPAN(timeout_usec, 1), cmd); + /* pipes from child to parent */ if (result || log_get_max_level() >= LOG_INFO) if (pipe2(outpipe, O_NONBLOCK|O_CLOEXEC) != 0) @@ -300,10 +308,11 @@ int udev_event_spawn( .cmd = cmd, .pid = pid, .accept_failure = accept_failure, - .timeout_warn_usec = udev_warn_timeout(timeout_usec), - .timeout_usec = timeout_usec, + .timeout_warn_usec = udev_warn_timeout(cmd_timeout_usec), + .timeout_usec = cmd_timeout_usec, .timeout_signal = timeout_signal, .event_birth_usec = event->birth_usec, + .cmd_birth_usec = now_usec, .fd_stdout = outpipe[READ_END], .fd_stderr = errpipe[READ_END], .result = result, @@ -323,29 +332,42 @@ int udev_event_spawn( return r; /* 0 for success, and positive if the program failed */ } -void udev_event_execute_run(UdevEvent *event, usec_t timeout_usec, int timeout_signal) { +void udev_event_execute_run(UdevEvent *event) { const char *command; void *val; int r; + assert(event); + ORDERED_HASHMAP_FOREACH_KEY(val, command, event->run_list) { UdevBuiltinCommand builtin_cmd = PTR_TO_UDEV_BUILTIN_CMD(val); if (builtin_cmd != _UDEV_BUILTIN_INVALID) { log_device_debug(event->dev, "Running built-in command \"%s\"", command); - r = udev_builtin_run(event, builtin_cmd, command, false); + r = udev_builtin_run(event, builtin_cmd, command); if (r < 0) log_device_debug_errno(event->dev, r, "Failed to run built-in command \"%s\", ignoring: %m", command); } else { - if (event->exec_delay_usec > 0) { + if (event->worker && event->worker->exec_delay_usec > 0) { + usec_t timeout_usec = event->worker ? event->worker->timeout_usec : DEFAULT_WORKER_TIMEOUT_USEC; + usec_t now_usec = now(CLOCK_MONOTONIC); + usec_t age_usec = usec_sub_unsigned(now_usec, event->birth_usec); + + if (event->worker->exec_delay_usec >= usec_sub_unsigned(timeout_usec, age_usec)) { + log_device_warning(event->dev, + "Cannot delaying execution of \"%s\" for %s, skipping.", + command, FORMAT_TIMESPAN(event->worker->exec_delay_usec, USEC_PER_SEC)); + continue; + } + log_device_debug(event->dev, "Delaying execution of \"%s\" for %s.", - command, FORMAT_TIMESPAN(event->exec_delay_usec, USEC_PER_SEC)); - (void) usleep_safe(event->exec_delay_usec); + command, FORMAT_TIMESPAN(event->worker->exec_delay_usec, USEC_PER_SEC)); + (void) usleep_safe(event->worker->exec_delay_usec); } log_device_debug(event->dev, "Running command \"%s\"", command); - r = udev_event_spawn(event, timeout_usec, timeout_signal, false, command, NULL, 0, NULL); + r = udev_event_spawn(event, /* accept_failure = */ false, command, NULL, 0, NULL); if (r < 0) log_device_warning_errno(event->dev, r, "Failed to execute '%s', ignoring: %m", command); else if (r > 0) /* returned value is positive when program fails */ diff --git a/src/udev/udev-spawn.h b/src/udev/udev-spawn.h index 5efea2e..6b22b68 100644 --- a/src/udev/udev-spawn.h +++ b/src/udev/udev-spawn.h @@ -14,15 +14,16 @@ typedef struct UdevEvent UdevEvent; int udev_event_spawn( UdevEvent *event, - usec_t timeout_usec, - int timeout_signal, bool accept_failure, const char *cmd, char *result, size_t ressize, bool *ret_truncated); -void udev_event_execute_run(UdevEvent *event, usec_t timeout_usec, int timeout_signal); +void udev_event_execute_run(UdevEvent *event); static inline usec_t udev_warn_timeout(usec_t timeout_usec) { + if (timeout_usec == USEC_INFINITY) + return USEC_INFINITY; + return DIV_ROUND_UP(timeout_usec, 3); } diff --git a/src/udev/udev-watch.c b/src/udev/udev-watch.c index 58c8279..258eb26 100644 --- a/src/udev/udev-watch.c +++ b/src/udev/udev-watch.c @@ -232,12 +232,9 @@ int udev_watch_end(int inotify_fd, sd_device *dev) { _cleanup_close_ int dirfd = -EBADF; int wd, r; + assert(inotify_fd >= 0); assert(dev); - /* This may be called by 'udevadm test'. In that case, inotify_fd is not initialized. */ - if (inotify_fd < 0) - return 0; - if (sd_device_get_devname(dev, NULL) < 0) return 0; diff --git a/src/udev/udev-worker.c b/src/udev/udev-worker.c index 53722b2..97c5679 100644 --- a/src/udev/udev-worker.c +++ b/src/udev/udev-worker.c @@ -138,11 +138,7 @@ static int worker_mark_block_device_read_only(sd_device *dev) { if (!device_for_action(dev, SD_DEVICE_ADD)) return 0; - r = sd_device_get_subsystem(dev, &val); - if (r < 0) - return log_device_debug_errno(dev, r, "Failed to get subsystem: %m"); - - if (!streq(val, "block")) + if (!device_in_subsystem(dev, "block")) return 0; r = sd_device_get_sysname(dev, &val); @@ -176,7 +172,7 @@ static int worker_process_device(UdevWorker *worker, sd_device *dev) { log_device_uevent(dev, "Processing device"); - udev_event = udev_event_new(dev, worker->exec_delay_usec, worker->rtnl, worker->log_level); + udev_event = udev_event_new(dev, worker, EVENT_UDEV_WORKER); if (!udev_event) return -ENOMEM; @@ -194,18 +190,17 @@ static int worker_process_device(UdevWorker *worker, sd_device *dev) { if (worker->blockdev_read_only) (void) worker_mark_block_device_read_only(dev); + /* Disable watch during event processing. */ + r = udev_watch_end(worker->inotify_fd, dev); + if (r < 0) + log_device_warning_errno(dev, r, "Failed to remove inotify watch, ignoring: %m"); + /* apply rules, create node, symlinks */ - r = udev_event_execute_rules( - udev_event, - worker->inotify_fd, - worker->timeout_usec, - worker->timeout_signal, - worker->properties, - worker->rules); + r = udev_event_execute_rules(udev_event, worker->rules); if (r < 0) return r; - udev_event_execute_run(udev_event, worker->timeout_usec, worker->timeout_signal); + udev_event_execute_run(udev_event); if (!worker->rtnl) /* in case rtnl was initialized */ @@ -217,6 +212,15 @@ static int worker_process_device(UdevWorker *worker, sd_device *dev) { log_device_warning_errno(dev, r, "Failed to add inotify watch, ignoring: %m"); } + /* Finalize database. */ + r = device_add_property(dev, "ID_PROCESSING", NULL); + if (r < 0) + return log_device_warning_errno(dev, r, "Failed to remove 'ID_PROCESSING' property: %m"); + + r = device_update_db(dev); + if (r < 0) + return log_device_warning_errno(dev, r, "Failed to update database under /run/udev/data/: %m"); + log_device_uevent(dev, "Device processed"); return 0; } @@ -245,6 +249,7 @@ void udev_broadcast_result(sd_device_monitor *monitor, sd_device *dev, EventResu break; } case EVENT_RESULT_EXIT_STATUS_BASE ... EVENT_RESULT_EXIT_STATUS_MAX: + assert(result != EVENT_RESULT_EXIT_STATUS_BASE); (void) device_add_propertyf(dev, "UDEV_WORKER_EXIT_STATUS", "%i", result - EVENT_RESULT_EXIT_STATUS_BASE); break; @@ -318,8 +323,6 @@ int udev_worker_main(UdevWorker *worker, sd_device *dev) { DEVICE_TRACE_POINT(worker_spawned, dev, getpid_cached()); - assert_se(sigprocmask_many(SIG_BLOCK, NULL, SIGTERM, -1) >= 0); - /* Reset OOM score, we only protect the main daemon. */ r = set_oom_score_adjust(0); if (r < 0) @@ -329,7 +332,7 @@ int udev_worker_main(UdevWorker *worker, sd_device *dev) { if (r < 0) return log_error_errno(r, "Failed to allocate event loop: %m"); - r = sd_event_add_signal(worker->event, NULL, SIGTERM, NULL, NULL); + r = sd_event_add_signal(worker->event, NULL, SIGTERM | SD_EVENT_SIGNAL_PROCMASK, NULL, NULL); if (r < 0) return log_error_errno(r, "Failed to set SIGTERM event: %m"); diff --git a/src/udev/udev-worker.h b/src/udev/udev-worker.h index 05c319e..e9aefc5 100644 --- a/src/udev/udev-worker.h +++ b/src/udev/udev-worker.h @@ -11,6 +11,9 @@ #include "hashmap.h" #include "time-util.h" +#define DEFAULT_WORKER_TIMEOUT_USEC (3 * USEC_PER_MINUTE) +#define MIN_WORKER_TIMEOUT_USEC (1 * USEC_PER_MSEC) + typedef struct UdevRules UdevRules; typedef struct UdevWorker { diff --git a/src/udev/udevadm-control.c b/src/udev/udevadm-control.c index 64615f5..29dc883 100644 --- a/src/udev/udevadm-control.c +++ b/src/udev/udevadm-control.c @@ -1,15 +1,4 @@ /* SPDX-License-Identifier: GPL-2.0-or-later */ -/* - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ #include #include @@ -19,6 +8,7 @@ #include #include +#include "creds-util.h" #include "parse-util.h" #include "process-util.h" #include "static-destruct.h" @@ -37,9 +27,21 @@ static bool arg_exit = false; static int arg_max_children = -1; static int arg_log_level = -1; static int arg_start_exec_queue = -1; +static bool arg_load_credentials = false; STATIC_DESTRUCTOR_REGISTER(arg_env, strv_freep); +static bool arg_has_control_commands(void) { + return + arg_exit || + arg_log_level >= 0 || + arg_start_exec_queue >= 0 || + arg_reload || + !strv_isempty(arg_env) || + arg_max_children >= 0 || + arg_ping; +} + static int help(void) { printf("%s control OPTION\n\n" "Control the udev daemon.\n\n" @@ -53,7 +55,8 @@ static int help(void) { " -p --property=KEY=VALUE Set a global property for all events\n" " -m --children-max=N Maximum number of children\n" " --ping Wait for udev to respond to a ping message\n" - " -t --timeout=SECONDS Maximum time to block for a reply\n", + " -t --timeout=SECONDS Maximum time to block for a reply\n" + " --load-credentials Load udev rules from credentials\n", program_invocation_short_name); return 0; @@ -62,23 +65,25 @@ static int help(void) { static int parse_argv(int argc, char *argv[]) { enum { ARG_PING = 0x100, + ARG_LOAD_CREDENTIALS, }; static const struct option options[] = { - { "exit", no_argument, NULL, 'e' }, - { "log-level", required_argument, NULL, 'l' }, - { "log-priority", required_argument, NULL, 'l' }, /* for backward compatibility */ - { "stop-exec-queue", no_argument, NULL, 's' }, - { "start-exec-queue", no_argument, NULL, 'S' }, - { "reload", no_argument, NULL, 'R' }, - { "reload-rules", no_argument, NULL, 'R' }, /* alias for -R */ - { "property", required_argument, NULL, 'p' }, - { "env", required_argument, NULL, 'p' }, /* alias for -p */ - { "children-max", required_argument, NULL, 'm' }, - { "ping", no_argument, NULL, ARG_PING }, - { "timeout", required_argument, NULL, 't' }, - { "version", no_argument, NULL, 'V' }, - { "help", no_argument, NULL, 'h' }, + { "exit", no_argument, NULL, 'e' }, + { "log-level", required_argument, NULL, 'l' }, + { "log-priority", required_argument, NULL, 'l' }, /* for backward compatibility */ + { "stop-exec-queue", no_argument, NULL, 's' }, + { "start-exec-queue", no_argument, NULL, 'S' }, + { "reload", no_argument, NULL, 'R' }, + { "reload-rules", no_argument, NULL, 'R' }, /* alias for -R */ + { "property", required_argument, NULL, 'p' }, + { "env", required_argument, NULL, 'p' }, /* alias for -p */ + { "children-max", required_argument, NULL, 'm' }, + { "ping", no_argument, NULL, ARG_PING }, + { "timeout", required_argument, NULL, 't' }, + { "load-credentials", no_argument, NULL, ARG_LOAD_CREDENTIALS }, + { "version", no_argument, NULL, 'V' }, + { "help", no_argument, NULL, 'h' }, {} }; @@ -87,10 +92,6 @@ static int parse_argv(int argc, char *argv[]) { assert(argc >= 0); assert(argv); - if (argc <= 1) - return log_error_errno(SYNTHETIC_ERRNO(EINVAL), - "This command expects one or more options."); - while ((c = getopt_long(argc, argv, "el:sSRp:m:t:Vh", options, NULL)) >= 0) switch (c) { @@ -145,6 +146,10 @@ static int parse_argv(int argc, char *argv[]) { return log_error_errno(r, "Failed to parse timeout value '%s': %m", optarg); break; + case ARG_LOAD_CREDENTIALS: + arg_load_credentials = true; + break; + case 'V': return print_version(); @@ -158,6 +163,10 @@ static int parse_argv(int argc, char *argv[]) { assert_not_reached(); } + if (!arg_has_control_commands() && !arg_load_credentials) + return log_error_errno(SYNTHETIC_ERRNO(EINVAL), + "No control command option is specified."); + if (optind < argc) return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Extraneous argument: %s", argv[optind]); @@ -165,19 +174,10 @@ static int parse_argv(int argc, char *argv[]) { return 1; } -int control_main(int argc, char *argv[], void *userdata) { +static int send_control_commands(void) { _cleanup_(udev_ctrl_unrefp) UdevCtrl *uctrl = NULL; int r; - if (running_in_chroot() > 0) { - log_info("Running in chroot, ignoring request."); - return 0; - } - - r = parse_argv(argc, argv); - if (r <= 0) - return r; - r = udev_ctrl_new(&uctrl); if (r < 0) return log_error_errno(r, "Failed to initialize udev control: %m"); @@ -237,3 +237,34 @@ int control_main(int argc, char *argv[], void *userdata) { return 0; } + +int control_main(int argc, char *argv[], void *userdata) { + int r; + + if (running_in_chroot() > 0) { + log_info("Running in chroot, ignoring request."); + return 0; + } + + r = parse_argv(argc, argv); + if (r <= 0) + return r; + + if (arg_load_credentials) { + static const PickUpCredential table[] = { + { "udev.conf.", "/run/udev/udev.conf.d/", ".conf" }, + { "udev.rules.", "/run/udev/rules.d/", ".rules" }, + }; + r = pick_up_credentials(table, ELEMENTSOF(table)); + if (r < 0) + return r; + } + + if (arg_has_control_commands()) { + r = send_control_commands(); + if (r < 0) + return r; + } + + return 0; +} diff --git a/src/udev/udevadm-hwdb.c b/src/udev/udevadm-hwdb.c index 2f5429f..f306a4f 100644 --- a/src/udev/udevadm-hwdb.c +++ b/src/udev/udevadm-hwdb.c @@ -89,7 +89,7 @@ int hwdb_main(int argc, char *argv[], void *userdata) { log_notice("udevadm hwdb is deprecated. Use systemd-hwdb instead."); - if (arg_update) { + if (arg_update && !hwdb_bypass()) { r = hwdb_update(arg_root, arg_hwdb_bin_dir, arg_strict, true); if (r < 0) return r; diff --git a/src/udev/udevadm-info.c b/src/udev/udevadm-info.c index 4cd9ad4..7c3c0cd 100644 --- a/src/udev/udevadm-info.c +++ b/src/udev/udevadm-info.c @@ -759,7 +759,7 @@ static int parse_key_value_argument(const char *s, char **key, char **value) { assert(key); assert(value); - r = extract_many_words(&s, "=", EXTRACT_DONT_COALESCE_SEPARATORS, &k, &v, NULL); + r = extract_many_words(&s, "=", EXTRACT_DONT_COALESCE_SEPARATORS, &k, &v); if (r < 0) return log_error_errno(r, "Failed to parse key/value pair %s: %m", s); if (r < 2) diff --git a/src/udev/udevadm-lock.c b/src/udev/udevadm-lock.c index bc2d5e7..e6384e3 100644 --- a/src/udev/udevadm-lock.c +++ b/src/udev/udevadm-lock.c @@ -126,7 +126,7 @@ static int parse_argv(int argc, char *argv[]) { if (arg_print) { if (optind != argc) - return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "No arguments expected"); + return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "No arguments expected."); } else { if (optind + 1 > argc) return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Too few arguments, command to execute."); @@ -193,7 +193,7 @@ static int lock_device( /* Extra safety: check that the device still refers to what we think it refers to */ if (!S_ISBLK(st.st_mode) || st.st_rdev != devno) - return log_error_errno(SYNTHETIC_ERRNO(ENXIO), "Path '%s' no longer refers to specified block device %u:%u: %m", path, major(devno), minor(devno)); + return log_error_errno(SYNTHETIC_ERRNO(ENXIO), "Path '%s' no longer refers to specified block device %u:%u.", path, major(devno), minor(devno)); r = lock_generic(fd, LOCK_BSD, LOCK_EX|LOCK_NB); if (r < 0) { diff --git a/src/udev/udevadm-monitor.c b/src/udev/udevadm-monitor.c index 27c4853..b1124df 100644 --- a/src/udev/udevadm-monitor.c +++ b/src/udev/udevadm-monitor.c @@ -208,7 +208,7 @@ int monitor_main(int argc, char *argv[], void *userdata) { goto finalize; } - assert_se(sigprocmask_many(SIG_BLOCK, NULL, SIGTERM, SIGINT, -1) >= 0); + assert_se(sigprocmask_many(SIG_BLOCK, NULL, SIGTERM, SIGINT) >= 0); (void) sd_event_add_signal(event, NULL, SIGTERM, NULL, NULL); (void) sd_event_add_signal(event, NULL, SIGINT, NULL, NULL); diff --git a/src/udev/udevadm-test-builtin.c b/src/udev/udevadm-test-builtin.c index 088b4da..322f627 100644 --- a/src/udev/udevadm-test-builtin.c +++ b/src/udev/udevadm-test-builtin.c @@ -6,6 +6,8 @@ #include #include +#include "device-private.h" +#include "device-util.h" #include "log.h" #include "udev-builtin.h" #include "udevadm.h" @@ -77,8 +79,7 @@ int builtin_main(int argc, char *argv[], void *userdata) { UdevBuiltinCommand cmd; int r; - log_set_max_level(LOG_DEBUG); - log_parse_environment(); + log_setup(); r = parse_argv(argc, argv); if (r <= 0) @@ -98,13 +99,22 @@ int builtin_main(int argc, char *argv[], void *userdata) { goto finish; } - event = udev_event_new(dev, 0, NULL, LOG_DEBUG); + event = udev_event_new(dev, NULL, EVENT_UDEVADM_TEST_BUILTIN); if (!event) { r = log_oom(); goto finish; } - r = udev_builtin_run(event, cmd, arg_command, true); + 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); if (r < 0) { log_debug_errno(r, "Builtin command '%s' fails: %m", arg_command); goto finish; diff --git a/src/udev/udevadm-test.c b/src/udev/udevadm-test.c index e1afd7d..c8c23e8 100644 --- a/src/udev/udevadm-test.c +++ b/src/udev/udevadm-test.c @@ -16,14 +16,18 @@ #include "device-private.h" #include "device-util.h" +#include "format-util.h" #include "path-util.h" #include "string-util.h" +#include "strv.h" #include "strxcpyx.h" +#include "terminal-util.h" #include "udev-builtin.h" #include "udev-event.h" #include "udev-format.h" #include "udevadm-util.h" #include "udevadm.h" +#include "user-util.h" static sd_device_action_t arg_action = SD_DEVICE_ADD; static ResolveNameTiming arg_resolve_name_timing = RESOLVE_NAME_EARLY; @@ -89,13 +93,10 @@ int test_main(int argc, char *argv[], void *userdata) { _cleanup_(udev_rules_freep) UdevRules *rules = NULL; _cleanup_(udev_event_freep) UdevEvent *event = NULL; _cleanup_(sd_device_unrefp) sd_device *dev = NULL; - const char *cmd; sigset_t mask, sigmask_orig; - void *val; int r; - log_set_max_level(LOG_DEBUG); - log_parse_environment(); + log_setup(); r = parse_argv(argc, argv); if (r <= 0) @@ -125,24 +126,89 @@ int test_main(int argc, char *argv[], void *userdata) { /* don't read info from the db */ device_seal(dev); - event = udev_event_new(dev, 0, NULL, LOG_DEBUG); + event = udev_event_new(dev, NULL, EVENT_UDEVADM_TEST); assert_se(sigfillset(&mask) >= 0); assert_se(sigprocmask(SIG_SETMASK, &mask, &sigmask_orig) >= 0); - udev_event_execute_rules(event, -1, 60 * USEC_PER_SEC, SIGKILL, NULL, rules); + udev_event_execute_rules(event, rules); + printf("%sProperties:%s\n", ansi_highlight(), ansi_normal()); FOREACH_DEVICE_PROPERTY(dev, key, value) - printf("%s=%s\n", key, value); + printf(" %s=%s\n", key, value); - ORDERED_HASHMAP_FOREACH_KEY(val, cmd, event->run_list) { - char program[UDEV_PATH_SIZE]; - bool truncated; + if (sd_device_get_tag_first(dev)) { + printf("%sTags:%s\n", ansi_highlight(), ansi_normal()); + FOREACH_DEVICE_TAG(dev, tag) + printf(" %s\n", tag); + } + + if (sd_device_get_devnum(dev, NULL) >= 0) { + + if (sd_device_get_devlink_first(dev)) { + int prio; + device_get_devlink_priority(dev, &prio); + printf("%sDevice node symlinks:%s (priority=%i)\n", ansi_highlight(), ansi_normal(), prio); + FOREACH_DEVICE_DEVLINK(dev, devlink) + printf(" %s\n", devlink); + } + + printf("%sInotify watch:%s\n %s\n", ansi_highlight(), ansi_normal(), enabled_disabled(event->inotify_watch)); + + uid_t uid = event->uid; + if (!uid_is_valid(uid)) + (void) device_get_devnode_uid(dev, &uid); + if (uid_is_valid(uid)) { + _cleanup_free_ char *user = uid_to_name(uid); + printf("%sDevice node owner:%s\n %s (uid="UID_FMT")\n", ansi_highlight(), ansi_normal(), strna(user), uid); + } + + gid_t gid = event->gid; + if (!gid_is_valid(uid)) + (void) device_get_devnode_gid(dev, &gid); + if (gid_is_valid(gid)) { + _cleanup_free_ char *group = gid_to_name(gid); + printf("%sDevice node group:%s\n %s (gid="GID_FMT")\n", ansi_highlight(), ansi_normal(), strna(group), gid); + } - (void) udev_event_apply_format(event, cmd, program, sizeof(program), false, NULL, &truncated); - if (truncated) - log_warning("The command '%s' is truncated while substituting into '%s'.", program, cmd); - printf("run: '%s'\n", program); + mode_t mode = event->mode; + if (mode == MODE_INVALID) + (void) device_get_devnode_mode(dev, &mode); + if (mode != MODE_INVALID) + printf("%sDevice node permission:%s\n %04o\n", ansi_highlight(), ansi_normal(), mode); + + if (!ordered_hashmap_isempty(event->seclabel_list)) { + const char *name, *label; + printf("%sDevice node security label:%s\n", ansi_highlight(), ansi_normal()); + ORDERED_HASHMAP_FOREACH_KEY(label, name, event->seclabel_list) + printf(" %s : %s\n", name, label); + } + } + + if (sd_device_get_ifindex(dev, NULL) >= 0) { + if (!isempty(event->name)) + printf("%sNetwork interface name:%s\n %s\n", ansi_highlight(), ansi_normal(), event->name); + + if (!strv_isempty(event->altnames)) { + bool space = true; + printf("%sAlternative interface names:%s", ansi_highlight(), ansi_normal()); + fputstrv(stdout, event->altnames, "\n ", &space); + puts(""); + } + } + + if (!ordered_hashmap_isempty(event->run_list)) { + void *val; + const char *command; + printf("%sQueued commands:%s\n", ansi_highlight(), ansi_normal()); + ORDERED_HASHMAP_FOREACH_KEY(val, command, event->run_list) { + UdevBuiltinCommand builtin_cmd = PTR_TO_UDEV_BUILTIN_CMD(val); + + if (builtin_cmd != _UDEV_BUILTIN_INVALID) + printf(" RUN{builtin} : %s\n", command); + else + printf(" RUN{program} : %s\n", command); + } } r = 0; diff --git a/src/udev/udevadm-wait.c b/src/udev/udevadm-wait.c index e6620c2..6ffc86b 100644 --- a/src/udev/udevadm-wait.c +++ b/src/udev/udevadm-wait.c @@ -67,7 +67,7 @@ static int check_device(const char *path) { return r; if (arg_wait_until == WAIT_UNTIL_INITIALIZED) - return sd_device_get_is_initialized(dev); + return device_is_processed(dev); return true; } diff --git a/src/udev/udevadm.c b/src/udev/udevadm.c index 687b927..899d4e6 100644 --- a/src/udev/udevadm.c +++ b/src/udev/udevadm.c @@ -123,7 +123,7 @@ static int run(int argc, char *argv[]) { if (invoked_as(argv, "udevd")) return run_udevd(argc, argv); - udev_parse_config(); + (void) udev_parse_config(); log_setup(); r = parse_argv(argc, argv); diff --git a/src/udev/udevd.c b/src/udev/udevd.c index 2ed4282..5018541 100644 --- a/src/udev/udevd.c +++ b/src/udev/udevd.c @@ -10,6 +10,7 @@ #include "sd-daemon.h" +#include "conf-parser.h" #include "env-file.h" #include "errno-util.h" #include "fd-util.h" @@ -32,16 +33,15 @@ static int arg_daemonize = false; static int listen_fds(int *ret_ctrl, int *ret_netlink) { int ctrl_fd = -EBADF, netlink_fd = -EBADF; - int fd, n; assert(ret_ctrl); assert(ret_netlink); - n = sd_listen_fds(true); + int n = sd_listen_fds(true); if (n < 0) return n; - for (fd = SD_LISTEN_FDS_START; fd < n + SD_LISTEN_FDS_START; fd++) { + for (int fd = SD_LISTEN_FDS_START; fd < n + SD_LISTEN_FDS_START; fd++) { if (sd_is_socket(fd, AF_UNIX, SOCK_SEQPACKET, -1) > 0) { if (ctrl_fd >= 0) return -EINVAL; @@ -65,70 +65,29 @@ static int listen_fds(int *ret_ctrl, int *ret_netlink) { return 0; } +static DEFINE_CONFIG_PARSE_ENUM(config_parse_resolve_name_timing, resolve_name_timing, ResolveNameTiming, "Failed to parse resolve name timing"); + static int manager_parse_udev_config(Manager *manager) { - _cleanup_free_ char *log_val = NULL, *children_max = NULL, *exec_delay = NULL, - *event_timeout = NULL, *resolve_names = NULL, *timeout_signal = NULL; - int r; + int r, log_val = -1; assert(manager); - r = parse_env_file(NULL, "/etc/udev/udev.conf", - "udev_log", &log_val, - "children_max", &children_max, - "exec_delay", &exec_delay, - "event_timeout", &event_timeout, - "resolve_names", &resolve_names, - "timeout_signal", &timeout_signal); - if (r == -ENOENT) - return 0; - if (r < 0) - return r; + const ConfigTableItem config_table[] = { + { NULL, "udev_log", config_parse_log_level, 0, &log_val }, + { NULL, "children_max", config_parse_unsigned, 0, &manager->children_max }, + { NULL, "exec_delay", config_parse_sec, 0, &manager->exec_delay_usec }, + { NULL, "event_timeout", config_parse_sec, 0, &manager->timeout_usec }, + { NULL, "resolve_names", config_parse_resolve_name_timing, 0, &manager->resolve_name_timing }, + { NULL, "timeout_signal", config_parse_signal, 0, &manager->timeout_signal }, + {} + }; - r = udev_set_max_log_level(log_val); + r = udev_parse_config_full(config_table); if (r < 0) - log_syntax(NULL, LOG_WARNING, "/etc/udev/udev.conf", 0, r, - "Failed to set udev log level '%s', ignoring: %m", log_val); - - if (children_max) { - r = safe_atou(children_max, &manager->children_max); - if (r < 0) - log_syntax(NULL, LOG_WARNING, "/etc/udev/udev.conf", 0, r, - "Failed to parse children_max=%s, ignoring: %m", children_max); - } - - if (exec_delay) { - r = parse_sec(exec_delay, &manager->exec_delay_usec); - if (r < 0) - log_syntax(NULL, LOG_WARNING, "/etc/udev/udev.conf", 0, r, - "Failed to parse exec_delay=%s, ignoring: %m", exec_delay); - } - - if (event_timeout) { - r = parse_sec(event_timeout, &manager->timeout_usec); - if (r < 0) - log_syntax(NULL, LOG_WARNING, "/etc/udev/udev.conf", 0, r, - "Failed to parse event_timeout=%s, ignoring: %m", event_timeout); - } - - if (resolve_names) { - ResolveNameTiming t; - - t = resolve_name_timing_from_string(resolve_names); - if (t < 0) - log_syntax(NULL, LOG_WARNING, "/etc/udev/udev.conf", 0, r, - "Failed to parse resolve_names=%s, ignoring.", resolve_names); - else - manager->resolve_name_timing = t; - } + return r; - if (timeout_signal) { - r = signal_from_string(timeout_signal); - if (r < 0) - log_syntax(NULL, LOG_WARNING, "/etc/udev/udev.conf", 0, r, - "Failed to parse timeout_signal=%s, ignoring: %m", timeout_signal); - else - manager->timeout_signal = r; - } + if (log_val >= 0) + log_set_max_level(log_val); return 0; } @@ -330,8 +289,7 @@ int run_udevd(int argc, char *argv[]) { int fd_ctrl = -EBADF, fd_uevent = -EBADF; int r; - log_set_target(LOG_TARGET_AUTO); - log_open(); + log_setup(); manager = manager_new(); if (!manager) @@ -339,9 +297,6 @@ int run_udevd(int argc, char *argv[]) { manager_parse_udev_config(manager); - log_parse_environment(); - log_open(); /* Done again to update after reading configuration. */ - r = parse_argv(argc, argv, manager); if (r <= 0) return r; @@ -355,6 +310,8 @@ int run_udevd(int argc, char *argv[]) { log_set_max_level(LOG_DEBUG); } + manager_adjust_arguments(manager); + r = must_be_root(); if (r < 0) return r; diff --git a/src/udev/v4l_id/v4l_id.c b/src/udev/v4l_id/v4l_id.c index 30527e9..5c54065 100644 --- a/src/udev/v4l_id/v4l_id.c +++ b/src/udev/v4l_id/v4l_id.c @@ -1,16 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-or-later */ /* * Copyright (c) 2009 Filippo Argiolas - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details: */ #include -- cgit v1.2.3