diff options
Diffstat (limited to 'src/udev')
31 files changed, 635 insertions, 495 deletions
diff --git a/src/udev/meson.build b/src/udev/meson.build index e378d9190c..9d3f6d1c56 100644 --- a/src/udev/meson.build +++ b/src/udev/meson.build @@ -41,6 +41,8 @@ libudev_core_sources = ''' net/link-config.h net/ethtool-util.c net/ethtool-util.h + net/naming-scheme.c + net/naming-scheme.h '''.split() if conf.get('HAVE_KMOD') == 1 @@ -187,12 +189,11 @@ endforeach install_data('udev.conf', install_dir : join_paths(sysconfdir, 'udev')) -udev_pc = configure_file( +configure_file( input : 'udev.pc.in', output : 'udev.pc', - configuration : substs) -install_data(udev_pc, - install_dir : pkgconfigdatadir) + configuration : substs, + install_dir : pkgconfigdatadir == 'no' ? '' : pkgconfigdatadir) meson.add_install_script('sh', '-c', mkdir_p.format(join_paths(sysconfdir, 'udev/rules.d'))) diff --git a/src/udev/net/ethtool-util.c b/src/udev/net/ethtool-util.c index bc0deaf347..0dcec03f67 100644 --- a/src/udev/net/ethtool-util.c +++ b/src/udev/net/ethtool-util.c @@ -31,18 +31,18 @@ static const char* const wol_table[_WOL_MAX] = { [WOL_ARP] = "arp", [WOL_MAGIC] = "magic", [WOL_MAGICSECURE] = "secureon", - [WOL_OFF] = "off" + [WOL_OFF] = "off", }; DEFINE_STRING_TABLE_LOOKUP(wol, WakeOnLan); DEFINE_CONFIG_PARSE_ENUM(config_parse_wol, wol, WakeOnLan, "Failed to parse WakeOnLan setting"); -static const char* const port_table[_NET_DEV_PORT_MAX] = { +static const char* const port_table[] = { [NET_DEV_PORT_TP] = "tp", [NET_DEV_PORT_AUI] = "aui", [NET_DEV_PORT_MII] = "mii", [NET_DEV_PORT_FIBRE] = "fibre", - [NET_DEV_PORT_BNC] = "bnc" + [NET_DEV_PORT_BNC] = "bnc", }; DEFINE_STRING_TABLE_LOOKUP(port, NetDevPort); @@ -583,7 +583,7 @@ int ethtool_set_glinksettings(int *fd, const char *ifname, struct link_config *l struct ifreq ifr = {}; int r; - if (link->autonegotiation != 0) { + if (link->autonegotiation != AUTONEG_DISABLE && eqzero(link->advertise)) { log_info("link_config: autonegotiation is unset or enabled, the speed and duplex are not writable."); return 0; } @@ -612,9 +612,11 @@ int ethtool_set_glinksettings(int *fd, const char *ifname, struct link_config *l if (link->port != _NET_DEV_PORT_INVALID) u->base.port = link->port; - u->base.autoneg = link->autonegotiation; + if (link->autonegotiation >= 0) + u->base.autoneg = link->autonegotiation; if (!eqzero(link->advertise)) { + u->base.autoneg = AUTONEG_ENABLE; memcpy(&u->link_modes.advertising, link->advertise, sizeof(link->advertise)); memzero((uint8_t*) &u->link_modes.advertising + sizeof(link->advertise), ETHTOOL_LINK_MODE_MASK_MAX_KERNEL_NBYTES - sizeof(link->advertise)); diff --git a/src/udev/net/ethtool-util.h b/src/udev/net/ethtool-util.h index e4bc5161d5..618b26bf59 100644 --- a/src/udev/net/ethtool-util.h +++ b/src/udev/net/ethtool-util.h @@ -42,14 +42,14 @@ typedef enum NetDevFeature { } NetDevFeature; typedef enum NetDevPort { - NET_DEV_PORT_TP = 0x00, - NET_DEV_PORT_AUI = 0x01, - NET_DEV_PORT_MII = 0x02, - NET_DEV_PORT_FIBRE = 0x03, - NET_DEV_PORT_BNC = 0x04, - NET_DEV_PORT_DA = 0x05, - NET_DEV_PORT_NONE = 0xef, - NET_DEV_PORT_OTHER = 0xff, + NET_DEV_PORT_TP = PORT_TP, + NET_DEV_PORT_AUI = PORT_AUI, + NET_DEV_PORT_MII = PORT_MII, + NET_DEV_PORT_FIBRE = PORT_FIBRE, + NET_DEV_PORT_BNC = PORT_BNC, + NET_DEV_PORT_DA = PORT_DA, + NET_DEV_PORT_NONE = PORT_NONE, + NET_DEV_PORT_OTHER = PORT_OTHER, _NET_DEV_PORT_MAX, _NET_DEV_PORT_INVALID = -1 } NetDevPort; diff --git a/src/udev/net/link-config.c b/src/udev/net/link-config.c index ac66ffd047..eb2477cea4 100644 --- a/src/udev/net/link-config.c +++ b/src/udev/net/link-config.c @@ -14,6 +14,7 @@ #include "link-config.h" #include "log.h" #include "missing_network.h" +#include "naming-scheme.h" #include "netlink-util.h" #include "network-internal.h" #include "parse-util.h" @@ -186,6 +187,22 @@ static bool enable_name_policy(void) { return proc_cmdline_get_bool("net.ifnames", &b) <= 0 || b; } +static int link_name_type(sd_device *device, unsigned *type) { + const char *s; + int r; + + r = sd_device_get_sysattr_value(device, "name_assign_type", &s); + if (r < 0) + return log_device_debug_errno(device, r, "Failed to query name_assign_type: %m"); + + r = safe_atou(s, type); + if (r < 0) + return log_device_warning_errno(device, r, "Failed to parse name_assign_type \"%s\": %m", s); + + log_device_debug(device, "Device has name_assign_type=%d", *type); + return 0; +} + int link_config_load(link_config_ctx *ctx) { _cleanup_strv_free_ char **files; char **f; @@ -256,13 +273,13 @@ int link_config_get(link_config_ctx *ctx, sd_device *device, link_config **ret) if (name_assign_type == NET_NAME_ENUM) { log_warning("Config file %s applies to device based on potentially unpredictable interface name '%s'", - link->filename, sysname); + link->filename, sysname); *ret = link; return 0; } else if (name_assign_type == NET_NAME_RENAMED) { log_warning("Config file %s matches device based on renamed interface name '%s', ignoring", - link->filename, sysname); + link->filename, sysname); continue; } @@ -272,13 +289,11 @@ int link_config_get(link_config_ctx *ctx, sd_device *device, link_config **ret) link->filename, sysname); *ret = link; - return 0; } } *ret = NULL; - return -ENOENT; } @@ -298,31 +313,6 @@ static bool mac_is_random(sd_device *device) { return type == NET_ADDR_RANDOM; } -static bool should_rename(sd_device *device, bool respect_predictable) { - const char *s; - unsigned type; - int r; - - /* if we can't get the assgin type, assume we should rename */ - if (sd_device_get_sysattr_value(device, "name_assign_type", &s) < 0) - return true; - - r = safe_atou(s, &type); - if (r < 0) - return true; - - switch (type) { - case NET_NAME_PREDICTABLE: - /* the kernel claims to have given a predictable name */ - if (respect_predictable) - return false; - _fallthrough_; - default: - /* the name is known to be bad, or of an unknown type */ - return true; - } -} - static int get_mac(sd_device *device, bool want_random, struct ether_addr *mac) { int r; @@ -349,12 +339,12 @@ static int get_mac(sd_device *device, bool want_random, int link_config_apply(link_config_ctx *ctx, link_config *config, sd_device *device, const char **name) { - bool respect_predictable = false; struct ether_addr generated_mac; struct ether_addr *mac = NULL; const char *new_name = NULL; const char *old_name; - unsigned speed; + unsigned speed, name_type = NET_NAME_UNKNOWN; + NamePolicy policy; int r, ifindex; assert(ctx); @@ -407,38 +397,63 @@ int link_config_apply(link_config_ctx *ctx, link_config *config, if (r < 0) return log_device_warning_errno(device, r, "Could not find ifindex: %m"); - if (ctx->enable_name_policy && config->name_policy) { - NamePolicy *policy; - for (policy = config->name_policy; - !new_name && *policy != _NAMEPOLICY_INVALID; policy++) { - switch (*policy) { - case NAMEPOLICY_KERNEL: - respect_predictable = true; - break; - case NAMEPOLICY_DATABASE: - (void) sd_device_get_property_value(device, "ID_NET_NAME_FROM_DATABASE", &new_name); - break; - case NAMEPOLICY_ONBOARD: - (void) sd_device_get_property_value(device, "ID_NET_NAME_ONBOARD", &new_name); - break; - case NAMEPOLICY_SLOT: - (void) sd_device_get_property_value(device, "ID_NET_NAME_SLOT", &new_name); - break; - case NAMEPOLICY_PATH: - (void) sd_device_get_property_value(device, "ID_NET_NAME_PATH", &new_name); - break; - case NAMEPOLICY_MAC: - (void) sd_device_get_property_value(device, "ID_NET_NAME_MAC", &new_name); - break; - default: - break; + (void) link_name_type(device, &name_type); + + if (IN_SET(name_type, NET_NAME_USER, NET_NAME_RENAMED) + && !naming_scheme_has(NAMING_ALLOW_RERENAMES)) { + log_device_debug(device, "Device already has a name given by userspace, not renaming."); + goto no_rename; + } + + if (ctx->enable_name_policy && config->name_policy) + for (NamePolicy *p = config->name_policy; !new_name && *p != _NAMEPOLICY_INVALID; p++) { + policy = *p; + + switch (policy) { + case NAMEPOLICY_KERNEL: + if (name_type != NET_NAME_PREDICTABLE) + continue; + + /* The kernel claims to have given a predictable name, keep it. */ + log_device_debug(device, "Policy *%s*: keeping predictable kernel name", + name_policy_to_string(policy)); + goto no_rename; + case NAMEPOLICY_KEEP: + if (!IN_SET(name_type, NET_NAME_USER, NET_NAME_RENAMED)) + continue; + + log_device_debug(device, "Policy *%s*: keeping existing userspace name", + name_policy_to_string(policy)); + goto no_rename; + case NAMEPOLICY_DATABASE: + (void) sd_device_get_property_value(device, "ID_NET_NAME_FROM_DATABASE", &new_name); + break; + case NAMEPOLICY_ONBOARD: + (void) sd_device_get_property_value(device, "ID_NET_NAME_ONBOARD", &new_name); + break; + case NAMEPOLICY_SLOT: + (void) sd_device_get_property_value(device, "ID_NET_NAME_SLOT", &new_name); + break; + case NAMEPOLICY_PATH: + (void) sd_device_get_property_value(device, "ID_NET_NAME_PATH", &new_name); + break; + case NAMEPOLICY_MAC: + (void) sd_device_get_property_value(device, "ID_NET_NAME_MAC", &new_name); + break; + default: + assert_not_reached("invalid policy"); } } - } - if (!new_name && should_rename(device, respect_predictable)) + if (new_name) + log_device_debug(device, "Policy *%s* yields \"%s\".", name_policy_to_string(policy), new_name); + else if (config->name) { new_name = config->name; + log_device_debug(device, "Policies didn't yield a name, using specified Name=%s.", new_name); + } else + log_device_debug(device, "Policies didn't yield a name and Name= is not given, not renaming."); + no_rename: switch (config->mac_policy) { case MACPOLICY_PERSISTENT: @@ -497,7 +512,7 @@ int link_get_driver(link_config_ctx *ctx, sd_device *device, char **ret) { static const char* const mac_policy_table[_MACPOLICY_MAX] = { [MACPOLICY_PERSISTENT] = "persistent", [MACPOLICY_RANDOM] = "random", - [MACPOLICY_NONE] = "none" + [MACPOLICY_NONE] = "none", }; DEFINE_STRING_TABLE_LOOKUP(mac_policy, MACPolicy); @@ -506,11 +521,12 @@ DEFINE_CONFIG_PARSE_ENUM(config_parse_mac_policy, mac_policy, MACPolicy, static const char* const name_policy_table[_NAMEPOLICY_MAX] = { [NAMEPOLICY_KERNEL] = "kernel", + [NAMEPOLICY_KEEP] = "keep", [NAMEPOLICY_DATABASE] = "database", [NAMEPOLICY_ONBOARD] = "onboard", [NAMEPOLICY_SLOT] = "slot", [NAMEPOLICY_PATH] = "path", - [NAMEPOLICY_MAC] = "mac" + [NAMEPOLICY_MAC] = "mac", }; DEFINE_STRING_TABLE_LOOKUP(name_policy, NamePolicy); diff --git a/src/udev/net/link-config.h b/src/udev/net/link-config.h index 8204959034..1113b1052e 100644 --- a/src/udev/net/link-config.h +++ b/src/udev/net/link-config.h @@ -22,6 +22,7 @@ typedef enum MACPolicy { typedef enum NamePolicy { NAMEPOLICY_KERNEL, + NAMEPOLICY_KEEP, NAMEPOLICY_DATABASE, NAMEPOLICY_ONBOARD, NAMEPOLICY_SLOT, diff --git a/src/udev/net/naming-scheme.c b/src/udev/net/naming-scheme.c new file mode 100644 index 0000000000..27cede5e2e --- /dev/null +++ b/src/udev/net/naming-scheme.c @@ -0,0 +1,64 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ +#include "alloc-util.h" +#include "naming-scheme.h" +#include "proc-cmdline.h" +#include "string-util.h" + +static const NamingScheme naming_schemes[] = { + { "v238", NAMING_V238 }, + { "v239", NAMING_V239 }, + { "v240", NAMING_V240 }, + /* … add more schemes here, as the logic to name devices is updated … */ +}; + +static const NamingScheme* naming_scheme_from_name(const char *name) { + size_t i; + + if (streq(name, "latest")) + return naming_schemes + ELEMENTSOF(naming_schemes) - 1; + + for (i = 0; i < ELEMENTSOF(naming_schemes); i++) + if (streq(naming_schemes[i].name, name)) + return naming_schemes + i; + + return NULL; +} + +const NamingScheme* naming_scheme(void) { + static const NamingScheme *cache = NULL; + _cleanup_free_ char *buffer = NULL; + const char *e, *k; + + if (cache) + return cache; + + /* Acquire setting from the kernel command line */ + (void) proc_cmdline_get_key("net.naming-scheme", 0, &buffer); + + /* Also acquire it from an env var */ + e = getenv("NET_NAMING_SCHEME"); + if (e) { + if (*e == ':') { + /* If prefixed with ':' the kernel cmdline takes precedence */ + k = buffer ?: e + 1; + } else + k = e; /* Otherwise the env var takes precedence */ + } else + k = buffer; + + if (k) { + cache = naming_scheme_from_name(k); + if (cache) { + log_info("Using interface naming scheme '%s'.", cache->name); + return cache; + } + + log_warning("Unknown interface naming scheme '%s' requested, ignoring.", k); + } + + cache = naming_scheme_from_name(DEFAULT_NET_NAMING_SCHEME); + assert(cache); + log_info("Using default interface naming scheme '%s'.", cache->name); + + return cache; +} diff --git a/src/udev/net/naming-scheme.h b/src/udev/net/naming-scheme.h new file mode 100644 index 0000000000..0b3d9bff1d --- /dev/null +++ b/src/udev/net/naming-scheme.h @@ -0,0 +1,48 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ +#pragma once + +#include <stdbool.h> + +#include "macro.h" + +/* So here's the deal: net_id is supposed to be an excercise in providing stable names for network devices. However, we + * also want to keep updating the naming scheme used in future versions of net_id. These two goals of course are + * contradictory: on one hand we want things to not change and on the other hand we want them to improve. Our way out + * of this dilemma is to introduce the "naming scheme" concept: each time we improve the naming logic we define a new + * flag for it. Then, we keep a list of schemes, each identified by a name associated with the flags it implements. Via + * a kernel command line and environment variable we then allow the user to pick the scheme they want us to follow: + * installers could "freeze" the used scheme at the moment of installation this way. + * + * Developers: each time you tweak the naming logic here, define a new flag below, and condition the tweak with + * it. Each time we do a release we'll then add a new scheme entry and include all newly defined flags. + * + * Note that this is only half a solution to the problem though: not only udev/net_id gets updated all the time, the + * kernel gets too. And thus a kernel that previously didn't expose some sysfs attribute we look for might eventually + * do, and thus affect our naming scheme too. Thus, enforcing a naming scheme will make interfacing more stable across + * OS versions, but not fully stabilize them. */ +typedef enum NamingSchemeFlags { + /* First, the individual features */ + NAMING_SR_IOV_V = 1 << 0, /* Use "v" suffix for SR-IOV, see 609948c7043a40008b8299529c978ed8e11de8f6*/ + NAMING_NPAR_ARI = 1 << 1, /* Use NPAR "ARI", see 6bc04997b6eab35d1cb9fa73889892702c27be09 */ + NAMING_INFINIBAND = 1 << 2, /* Use "ib" prefix for infiniband, see 938d30aa98df887797c9e05074a562ddacdcdf5e */ + NAMING_ZERO_ACPI_INDEX = 1 << 3, /* Allow zero acpi_index field, see d81186ef4f6a888a70f20a1e73a812d6acb9e22f */ + NAMING_ALLOW_RERENAMES = 1 << 4, /* Allow re-renaming of devices, see #9006 */ + + /* And now the masks that combine the features above */ + NAMING_V238 = 0, + NAMING_V239 = NAMING_V238 | NAMING_SR_IOV_V | NAMING_NPAR_ARI, + NAMING_V240 = NAMING_V239 | NAMING_INFINIBAND | NAMING_ZERO_ACPI_INDEX | NAMING_ALLOW_RERENAMES, + + _NAMING_SCHEME_FLAGS_INVALID = -1, +} NamingSchemeFlags; + +typedef struct NamingScheme { + const char *name; + NamingSchemeFlags flags; +} NamingScheme; + +const NamingScheme* naming_scheme(void); + +static inline bool naming_scheme_has(NamingSchemeFlags flags) { + return FLAGS_SET(naming_scheme()->flags, flags); +} diff --git a/src/udev/scsi_id/scsi_id.c b/src/udev/scsi_id/scsi_id.c index e94f2946f9..2698cdd82f 100644 --- a/src/udev/scsi_id/scsi_id.c +++ b/src/udev/scsi_id/scsi_id.c @@ -18,6 +18,7 @@ #include <unistd.h> #include "alloc-util.h" +#include "build.h" #include "fd-util.h" #include "libudev-util.h" #include "scsi_id.h" @@ -370,7 +371,7 @@ static int set_options(int argc, char **argv, break; case 'V': - printf("%s\n", PACKAGE_VERSION); + printf("%s\n", GIT_VERSION); exit(EXIT_SUCCESS); case 'x': diff --git a/src/udev/udev-builtin-blkid.c b/src/udev/udev-builtin-blkid.c index df0f95461d..69d6c4bbee 100644 --- a/src/udev/udev-builtin-blkid.c +++ b/src/udev/udev-builtin-blkid.c @@ -240,7 +240,7 @@ static int builtin_blkid(sd_device *dev, 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, -ERANGE, "Invalid offset %"PRIi64": %m", offset); + return log_device_error_errno(dev, SYNTHETIC_ERRNO(ERANGE), "Invalid offset %"PRIi64": %m", offset); break; case 'R': noraid = true; diff --git a/src/udev/udev-builtin-btrfs.c b/src/udev/udev-builtin-btrfs.c index 85dba3d099..956be59afb 100644 --- a/src/udev/udev-builtin-btrfs.c +++ b/src/udev/udev-builtin-btrfs.c @@ -18,7 +18,7 @@ static int builtin_btrfs(sd_device *dev, int argc, char *argv[], bool test) { int r; if (argc != 3 || !streq(argv[1], "ready")) - return log_device_error_errno(dev, EINVAL, "Invalid arguments"); + return log_device_error_errno(dev, SYNTHETIC_ERRNO(EINVAL), "Invalid arguments"); fd = open("/dev/btrfs-control", O_RDWR|O_CLOEXEC); if (fd < 0) diff --git a/src/udev/udev-builtin-hwdb.c b/src/udev/udev-builtin-hwdb.c index ccad98e892..225e0265a4 100644 --- a/src/udev/udev-builtin-hwdb.c +++ b/src/udev/udev-builtin-hwdb.c @@ -165,7 +165,7 @@ static int builtin_hwdb(sd_device *dev, int argc, char *argv[], bool test) { if (r < 0) return log_device_debug_errno(dev, r, "Failed to lookup hwdb: %m"); if (r == 0) - return log_device_debug_errno(dev, ENOENT, "No entry found from hwdb: %m"); + return log_device_debug_errno(dev, SYNTHETIC_ERRNO(ENODATA), "No entry found from hwdb."); return r; } @@ -180,7 +180,7 @@ static int builtin_hwdb(sd_device *dev, int argc, char *argv[], bool test) { if (r < 0) return log_device_debug_errno(dev, r, "Failed to lookup hwdb: %m"); if (r == 0) - return log_device_debug_errno(dev, ENOENT, "No entry found from hwdb: %m"); + return log_device_debug_errno(dev, SYNTHETIC_ERRNO(ENODATA), "No entry found from hwdb."); return r; } diff --git a/src/udev/udev-builtin-input_id.c b/src/udev/udev-builtin-input_id.c index 13e9f0108d..e3db55b1a9 100644 --- a/src/udev/udev-builtin-input_id.c +++ b/src/udev/udev-builtin-input_id.c @@ -42,7 +42,7 @@ static const struct range high_key_blocks[] = { { KEY_ALS_TOGGLE, BTN_TRIGGER_HAPPY } }; -static inline int abs_size_mm(const struct input_absinfo *absinfo) { +static int abs_size_mm(const struct input_absinfo *absinfo) { /* Resolution is defined to be in units/mm for ABS_X/Y */ return (absinfo->maximum - absinfo->minimum) / absinfo->resolution; } diff --git a/src/udev/udev-builtin-keyboard.c b/src/udev/udev-builtin-keyboard.c index cb49a17c33..d80cdd26aa 100644 --- a/src/udev/udev-builtin-keyboard.c +++ b/src/udev/udev-builtin-keyboard.c @@ -74,7 +74,7 @@ static int map_keycode(sd_device *dev, int fd, int scancode, const char *keycode /* check if it's a numeric code already */ keycode_num = strtoul(keycode, &endptr, 0); if (endptr[0] !='\0') - return log_device_error_errno(dev, EINVAL, "Failed to parse key identifier '%s'", keycode); + return log_device_error_errno(dev, SYNTHETIC_ERRNO(EINVAL), "Failed to parse key identifier '%s'", keycode); } map.scan = scancode; @@ -89,7 +89,7 @@ static int map_keycode(sd_device *dev, int fd, int scancode, const char *keycode return 0; } -static inline char* parse_token(const char *current, int32_t *val_out) { +static char* parse_token(const char *current, int32_t *val_out) { char *next; int32_t val; @@ -152,7 +152,7 @@ static int set_trackpoint_sensitivity(sd_device *dev, const char *value) { if (r < 0) return log_device_error_errno(dev, r, "Failed to parse POINTINGSTICK_SENSITIVITY '%s': %m", value); else if (val_i < 0 || val_i > 255) - return log_device_error_errno(dev, ERANGE, "POINTINGSTICK_SENSITIVITY %d outside range [0..255]", val_i); + return log_device_error_errno(dev, SYNTHETIC_ERRNO(ERANGE), "POINTINGSTICK_SENSITIVITY %d outside range [0..255]", val_i); xsprintf(val_s, "%d", val_i); diff --git a/src/udev/udev-builtin-net_id.c b/src/udev/udev-builtin-net_id.c index 0292c4973c..03b281a771 100644 --- a/src/udev/udev-builtin-net_id.c +++ b/src/udev/udev-builtin-net_id.c @@ -106,6 +106,7 @@ #include "fd-util.h" #include "fileio.h" #include "fs-util.h" +#include "naming-scheme.h" #include "parse-util.h" #include "proc-cmdline.h" #include "stdio-util.h" @@ -116,48 +117,6 @@ #define ONBOARD_INDEX_MAX (16*1024-1) -/* So here's the deal: net_id is supposed to be an excercise in providing stable names for network devices. However, we - * also want to keep updating the naming scheme used in future versions of net_id. These two goals of course are - * contradictory: on one hand we want things to not change and on the other hand we want them to improve. Our way out - * of this dilemma is to introduce the "naming scheme" concept: each time we improve the naming logic we define a new - * flag for it. Then, we keep a list of schemes, each identified by a name associated with the flags it implements. Via - * a kernel command line and environment variable we then allow the user to pick the scheme they want us to follow: - * installers could "freeze" the used scheme at the moment of installation this way. - * - * Developers: each time you tweak the naming logic here, define a new flag below, and condition the tweak with - * it. Each time we do a release we'll then add a new scheme entry and include all newly defined flags. - * - * Note that this is only half a solution to the problem though: not only udev/net_id gets updated all the time, the - * kernel gets too. And thus a kernel that previously didn't expose some sysfs attribute we look for might eventually - * do, and thus affect our naming scheme too. Thus, enforcing a naming scheme will make interfacing more stable across - * OS versions, but not fully stabilize them. */ -typedef enum NamingSchemeFlags { - /* First, the individual features */ - NAMING_SR_IOV_V = 1 << 0, /* Use "v" suffix for SR-IOV, see 609948c7043a40008b8299529c978ed8e11de8f6*/ - NAMING_NPAR_ARI = 1 << 1, /* Use NPAR "ARI", see 6bc04997b6eab35d1cb9fa73889892702c27be09 */ - NAMING_INFINIBAND = 1 << 2, /* Use "ib" prefix for infiniband, see 938d30aa98df887797c9e05074a562ddacdcdf5e */ - NAMING_ZERO_ACPI_INDEX = 1 << 3, /* Allow zero acpi_index field, see d81186ef4f6a888a70f20a1e73a812d6acb9e22f */ - - /* And now the masks that combine the features above */ - NAMING_V238 = 0, - NAMING_V239 = NAMING_V238|NAMING_SR_IOV_V|NAMING_NPAR_ARI, - NAMING_V240 = NAMING_V239|NAMING_INFINIBAND|NAMING_ZERO_ACPI_INDEX, - - _NAMING_SCHEME_FLAGS_INVALID = -1, -} NamingSchemeFlags; - -typedef struct NamingScheme { - const char *name; - NamingSchemeFlags flags; -} NamingScheme; - -static const NamingScheme naming_schemes[] = { - { "v238", NAMING_V238 }, - { "v239", NAMING_V239 }, - { "v240", NAMING_V240 }, - /* … add more schemes here, as the logic to name devices is updated … */ -}; - enum netname_type{ NET_UNDEF, NET_PCI, @@ -193,62 +152,6 @@ struct virtfn_info { char suffix[IFNAMSIZ]; }; -static const NamingScheme* naming_scheme_from_name(const char *name) { - size_t i; - - if (streq(name, "latest")) - return naming_schemes + ELEMENTSOF(naming_schemes) - 1; - - for (i = 0; i < ELEMENTSOF(naming_schemes); i++) - if (streq(naming_schemes[i].name, name)) - return naming_schemes + i; - - return NULL; -} - -static const NamingScheme* naming_scheme(void) { - static const NamingScheme *cache = NULL; - _cleanup_free_ char *buffer = NULL; - const char *e, *k; - - if (cache) - return cache; - - /* Acquire setting from the kernel command line */ - (void) proc_cmdline_get_key("net.naming-scheme", 0, &buffer); - - /* Also acquire it from an env var */ - e = getenv("NET_NAMING_SCHEME"); - if (e) { - if (*e == ':') { - /* If prefixed with ':' the kernel cmdline takes precedence */ - k = buffer ?: e + 1; - } else - k = e; /* Otherwise the env var takes precedence */ - } else - k = buffer; - - if (k) { - cache = naming_scheme_from_name(k); - if (cache) { - log_info("Using interface naming scheme '%s'.", cache->name); - return cache; - } - - log_warning("Unknown interface naming scheme '%s' requested, ignoring.", k); - } - - cache = naming_scheme_from_name(DEFAULT_NET_NAMING_SCHEME); - assert(cache); - log_info("Using default interface naming scheme '%s'.", cache->name); - - return cache; -} - -static bool naming_scheme_has(NamingSchemeFlags flags) { - return FLAGS_SET(naming_scheme()->flags, flags); -} - /* skip intermediate virtio devices */ static sd_device *skip_virtio(sd_device *dev) { sd_device *parent; @@ -460,7 +363,7 @@ static int dev_pci_slot(sd_device *dev, struct netnames *names) { } } - /* kernel provided front panel port name for multiple port PCI device */ + /* kernel provided front panel port name for multi-port PCI device */ (void) sd_device_get_sysattr_value(dev, "phys_port_name", &port_name); /* compose a name based on the raw kernel's PCI bus, slot numbers */ @@ -478,7 +381,7 @@ static int dev_pci_slot(sd_device *dev, struct netnames *names) { if (l == 0) names->pci_path[0] = '\0'; - /* ACPI _SUN — slot user number */ + /* ACPI _SUN — slot user number */ r = sd_device_new_from_subsystem_sysname(&pci, "subsystem", "pci"); if (r < 0) return r; diff --git a/src/udev/udev-builtin-net_setup_link.c b/src/udev/udev-builtin-net_setup_link.c index c0d3d4aa01..a845dfa5c1 100644 --- a/src/udev/udev-builtin-net_setup_link.c +++ b/src/udev/udev-builtin-net_setup_link.c @@ -16,7 +16,7 @@ static int builtin_net_setup_link(sd_device *dev, int argc, char **argv, bool te int r; if (argc > 1) - return log_device_error_errno(dev, EINVAL, "This program takes no arguments."); + return log_device_error_errno(dev, SYNTHETIC_ERRNO(EINVAL), "This program takes no arguments."); r = link_get_driver(ctx, dev, &driver); if (r >= 0) diff --git a/src/udev/udev-builtin-path_id.c b/src/udev/udev-builtin-path_id.c index 94f2740592..7ce1c5644f 100644 --- a/src/udev/udev-builtin-path_id.c +++ b/src/udev/udev-builtin-path_id.c @@ -110,7 +110,6 @@ static sd_device *handle_scsi_fibre_channel(sd_device *parent, char **path) { assert(parent); assert(path); - if (sd_device_get_parent_with_subsystem_devtype(parent, "scsi", "scsi_target", &targetdev) < 0) return NULL; if (sd_device_get_sysname(targetdev, &sysname) < 0) diff --git a/src/udev/udev-builtin.c b/src/udev/udev-builtin.c index 3a61be10ca..48ce295a46 100644 --- a/src/udev/udev-builtin.c +++ b/src/udev/udev-builtin.c @@ -139,7 +139,7 @@ int udev_builtin_add_property(sd_device *dev, bool test, const char *key, const key, val ? "=" : "", strempty(val)); if (test) - printf("%s=%s\n", key, val); + printf("%s=%s\n", key, strempty(val)); return 0; } diff --git a/src/udev/udev-ctrl.c b/src/udev/udev-ctrl.c index d90ebb7259..c217815ac6 100644 --- a/src/udev/udev-ctrl.c +++ b/src/udev/udev-ctrl.c @@ -213,14 +213,12 @@ static struct udev_ctrl_connection *udev_ctrl_connection_free(struct udev_ctrl_c DEFINE_TRIVIAL_REF_UNREF_FUNC(struct udev_ctrl_connection, udev_ctrl_connection, udev_ctrl_connection_free); -static int ctrl_send(struct udev_ctrl *uctrl, enum udev_ctrl_msg_type type, int intval, const char *buf, int timeout) { - struct udev_ctrl_msg_wire ctrl_msg_wire; - int err = 0; - - memzero(&ctrl_msg_wire, sizeof(struct udev_ctrl_msg_wire)); - strcpy(ctrl_msg_wire.version, "udev-" PACKAGE_VERSION); - ctrl_msg_wire.magic = UDEV_CTRL_MAGIC; - ctrl_msg_wire.type = type; +static int ctrl_send(struct udev_ctrl *uctrl, enum udev_ctrl_msg_type type, int intval, const char *buf, usec_t timeout) { + struct udev_ctrl_msg_wire ctrl_msg_wire = { + .version = "udev-" STRINGIFY(PROJECT_VERSION), + .magic = UDEV_CTRL_MAGIC, + .type = type, + }; if (buf) strscpy(ctrl_msg_wire.buf, sizeof(ctrl_msg_wire.buf), buf); @@ -228,74 +226,64 @@ static int ctrl_send(struct udev_ctrl *uctrl, enum udev_ctrl_msg_type type, int ctrl_msg_wire.intval = intval; if (!uctrl->connected) { - if (connect(uctrl->sock, &uctrl->saddr.sa, uctrl->addrlen) < 0) { - err = -errno; - goto out; - } + if (connect(uctrl->sock, &uctrl->saddr.sa, uctrl->addrlen) < 0) + return -errno; uctrl->connected = true; } - if (send(uctrl->sock, &ctrl_msg_wire, sizeof(ctrl_msg_wire), 0) < 0) { - err = -errno; - goto out; - } + if (send(uctrl->sock, &ctrl_msg_wire, sizeof(ctrl_msg_wire), 0) < 0) + return -errno; /* wait for peer message handling or disconnect */ for (;;) { - struct pollfd pfd[1]; + struct pollfd pfd = { + .fd = uctrl->sock, + .events = POLLIN, + }; int r; - pfd[0].fd = uctrl->sock; - pfd[0].events = POLLIN; - r = poll(pfd, 1, timeout * MSEC_PER_SEC); + r = poll(&pfd, 1, DIV_ROUND_UP(timeout, USEC_PER_MSEC)); if (r < 0) { if (errno == EINTR) continue; - err = -errno; - break; - } - - if (r > 0 && pfd[0].revents & POLLERR) { - err = -EIO; - break; + return -errno; } - if (r == 0) - err = -ETIMEDOUT; - break; + return -ETIMEDOUT; + if (pfd.revents & POLLERR) + return -EIO; + return 0; } -out: - return err; } -int udev_ctrl_send_set_log_level(struct udev_ctrl *uctrl, int priority, int timeout) { +int udev_ctrl_send_set_log_level(struct udev_ctrl *uctrl, int priority, usec_t timeout) { return ctrl_send(uctrl, UDEV_CTRL_SET_LOG_LEVEL, priority, NULL, timeout); } -int udev_ctrl_send_stop_exec_queue(struct udev_ctrl *uctrl, int timeout) { +int udev_ctrl_send_stop_exec_queue(struct udev_ctrl *uctrl, usec_t timeout) { return ctrl_send(uctrl, UDEV_CTRL_STOP_EXEC_QUEUE, 0, NULL, timeout); } -int udev_ctrl_send_start_exec_queue(struct udev_ctrl *uctrl, int timeout) { +int udev_ctrl_send_start_exec_queue(struct udev_ctrl *uctrl, usec_t timeout) { return ctrl_send(uctrl, UDEV_CTRL_START_EXEC_QUEUE, 0, NULL, timeout); } -int udev_ctrl_send_reload(struct udev_ctrl *uctrl, int timeout) { +int udev_ctrl_send_reload(struct udev_ctrl *uctrl, usec_t timeout) { return ctrl_send(uctrl, UDEV_CTRL_RELOAD, 0, NULL, timeout); } -int udev_ctrl_send_set_env(struct udev_ctrl *uctrl, const char *key, int timeout) { +int udev_ctrl_send_set_env(struct udev_ctrl *uctrl, const char *key, usec_t timeout) { return ctrl_send(uctrl, UDEV_CTRL_SET_ENV, 0, key, timeout); } -int udev_ctrl_send_set_children_max(struct udev_ctrl *uctrl, int count, int timeout) { +int udev_ctrl_send_set_children_max(struct udev_ctrl *uctrl, int count, usec_t timeout) { return ctrl_send(uctrl, UDEV_CTRL_SET_CHILDREN_MAX, count, NULL, timeout); } -int udev_ctrl_send_ping(struct udev_ctrl *uctrl, int timeout) { +int udev_ctrl_send_ping(struct udev_ctrl *uctrl, usec_t timeout) { return ctrl_send(uctrl, UDEV_CTRL_PING, 0, NULL, timeout); } -int udev_ctrl_send_exit(struct udev_ctrl *uctrl, int timeout) { +int udev_ctrl_send_exit(struct udev_ctrl *uctrl, usec_t timeout) { return ctrl_send(uctrl, UDEV_CTRL_EXIT, 0, NULL, timeout); } diff --git a/src/udev/udev-ctrl.h b/src/udev/udev-ctrl.h index 87021cb880..8e452a4249 100644 --- a/src/udev/udev-ctrl.h +++ b/src/udev/udev-ctrl.h @@ -2,6 +2,7 @@ #pragma once #include "macro.h" +#include "time-util.h" struct udev_ctrl; struct udev_ctrl *udev_ctrl_new(void); @@ -10,14 +11,14 @@ int udev_ctrl_enable_receiving(struct udev_ctrl *uctrl); struct udev_ctrl *udev_ctrl_unref(struct udev_ctrl *uctrl); int udev_ctrl_cleanup(struct udev_ctrl *uctrl); int udev_ctrl_get_fd(struct udev_ctrl *uctrl); -int udev_ctrl_send_set_log_level(struct udev_ctrl *uctrl, int priority, int timeout); -int udev_ctrl_send_stop_exec_queue(struct udev_ctrl *uctrl, int timeout); -int udev_ctrl_send_start_exec_queue(struct udev_ctrl *uctrl, int timeout); -int udev_ctrl_send_reload(struct udev_ctrl *uctrl, int timeout); -int udev_ctrl_send_ping(struct udev_ctrl *uctrl, int timeout); -int udev_ctrl_send_exit(struct udev_ctrl *uctrl, int timeout); -int udev_ctrl_send_set_env(struct udev_ctrl *uctrl, const char *key, int timeout); -int udev_ctrl_send_set_children_max(struct udev_ctrl *uctrl, int count, int timeout); +int udev_ctrl_send_set_log_level(struct udev_ctrl *uctrl, int priority, usec_t timeout); +int udev_ctrl_send_stop_exec_queue(struct udev_ctrl *uctrl, usec_t timeout); +int udev_ctrl_send_start_exec_queue(struct udev_ctrl *uctrl, usec_t timeout); +int udev_ctrl_send_reload(struct udev_ctrl *uctrl, usec_t timeout); +int udev_ctrl_send_ping(struct udev_ctrl *uctrl, usec_t timeout); +int udev_ctrl_send_exit(struct udev_ctrl *uctrl, usec_t timeout); +int udev_ctrl_send_set_env(struct udev_ctrl *uctrl, const char *key, usec_t timeout); +int udev_ctrl_send_set_children_max(struct udev_ctrl *uctrl, int count, usec_t timeout); struct udev_ctrl_connection; struct udev_ctrl_connection *udev_ctrl_get_connection(struct udev_ctrl *uctrl); diff --git a/src/udev/udev-event.c b/src/udev/udev-event.c index e28d6a5d08..07b7365e3a 100644 --- a/src/udev/udev-event.c +++ b/src/udev/udev-event.c @@ -504,38 +504,34 @@ static int on_spawn_timeout_warning(sd_event_source *s, uint64_t usec, void *use static int on_spawn_sigchld(sd_event_source *s, const siginfo_t *si, void *userdata) { Spawn *spawn = userdata; + int ret = -EIO; assert(spawn); switch (si->si_code) { case CLD_EXITED: - if (si->si_status == 0) { + if (si->si_status == 0) log_debug("Process '%s' succeeded.", spawn->cmd); - sd_event_exit(sd_event_source_get_event(s), 0); - - return 1; - } - - log_full(spawn->accept_failure ? LOG_DEBUG : LOG_WARNING, - "Process '%s' failed with exit code %i.", spawn->cmd, si->si_status); + else + log_full(spawn->accept_failure ? LOG_DEBUG : LOG_WARNING, + "Process '%s' failed with exit code %i.", spawn->cmd, si->si_status); + ret = si->si_status; break; case CLD_KILLED: case CLD_DUMPED: - log_warning("Process '%s' terminated by signal %s.", spawn->cmd, signal_to_string(si->si_status)); - + log_error("Process '%s' terminated by signal %s.", spawn->cmd, signal_to_string(si->si_status)); break; default: log_error("Process '%s' failed due to unknown reason.", spawn->cmd); } - sd_event_exit(sd_event_source_get_event(s), -EIO); - + sd_event_exit(sd_event_source_get_event(s), ret); return 1; } static int spawn_wait(Spawn *spawn) { _cleanup_(sd_event_unrefp) sd_event *e = NULL; - int r, ret; + int r; assert(spawn); @@ -570,27 +566,23 @@ static int spawn_wait(Spawn *spawn) { } } - r = sd_event_add_io(e, NULL, spawn->fd_stdout, EPOLLIN, on_spawn_io, spawn); - if (r < 0) - return r; + if (spawn->fd_stdout >= 0) { + r = sd_event_add_io(e, NULL, spawn->fd_stdout, EPOLLIN, on_spawn_io, spawn); + if (r < 0) + return r; + } - r = sd_event_add_io(e, NULL, spawn->fd_stderr, EPOLLIN, on_spawn_io, spawn); - if (r < 0) - return r; + if (spawn->fd_stderr >= 0) { + r = sd_event_add_io(e, NULL, spawn->fd_stderr, EPOLLIN, on_spawn_io, spawn); + if (r < 0) + return r; + } r = sd_event_add_child(e, NULL, spawn->pid, WEXITED, on_spawn_sigchld, spawn); if (r < 0) return r; - r = sd_event_loop(e); - if (r < 0) - return r; - - r = sd_event_get_exit_code(e, &ret); - if (r < 0) - return r; - - return ret; + return sd_event_loop(e); } int udev_event_spawn(UdevEvent *event, @@ -675,12 +667,12 @@ int udev_event_spawn(UdevEvent *event, }; r = spawn_wait(&spawn); if (r < 0) - return log_error_errno(r, "Failed to wait spawned command '%s': %m", cmd); + return log_error_errno(r, "Failed to wait for spawned command '%s': %m", cmd); if (result) result[spawn.result_len] = '\0'; - return r; + return r; /* 0 for success, and positive if the program failed */ } static int rename_netif(UdevEvent *event) { @@ -895,7 +887,7 @@ void udev_event_execute_run(UdevEvent *event, usec_t timeout_usec) { (void) usleep(event->exec_delay_usec); } - udev_event_spawn(event, timeout_usec, false, command, NULL, 0); + (void) udev_event_spawn(event, timeout_usec, false, command, NULL, 0); } } } diff --git a/src/udev/udev-node.c b/src/udev/udev-node.c index c11eb8c1ac..1c00dd1e9e 100644 --- a/src/udev/udev-node.c +++ b/src/udev/udev-node.c @@ -181,6 +181,9 @@ static int link_find_prioritized(sd_device *dev, bool add, const char *stackdir, priority = db_prio; } + if (!target) + return -ENOENT; + *ret = TAKE_PTR(target); return 0; } @@ -297,7 +300,7 @@ static int node_permissions_apply(sd_device *dev, bool apply, return log_device_debug_errno(dev, errno, "cannot stat() node '%s' (%m)", devnode); if (((stats.st_mode & S_IFMT) != (mode & S_IFMT)) || (stats.st_rdev != devnum)) - return log_device_debug_errno(dev, EEXIST, "Found node '%s' with non-matching devnum %s, skip handling", + return log_device_debug_errno(dev, SYNTHETIC_ERRNO(EEXIST), "Found node '%s' with non-matching devnum %s, skip handling", devnode, id_filename); if (apply) { diff --git a/src/udev/udev-rules.c b/src/udev/udev-rules.c index 53c68d254a..bc9c6c26c5 100644 --- a/src/udev/udev-rules.c +++ b/src/udev/udev-rules.c @@ -441,8 +441,8 @@ static void dump_rules(UdevRules *rules) { dump_token(rules, &rules->tokens[i]); } #else -static inline void dump_token(UdevRules *rules, struct token *token) {} -static inline void dump_rules(UdevRules *rules) {} +static void dump_token(UdevRules *rules, struct token *token) {} +static void dump_rules(UdevRules *rules) {} #endif /* ENABLE_DEBUG_UDEV */ static int add_token(UdevRules *rules, struct token *token) { @@ -645,11 +645,13 @@ static int import_program_into_properties(UdevEvent *event, const char *program) { char result[UTIL_LINE_SIZE]; char *line; - int err; + int r; - err = udev_event_spawn(event, timeout_usec, true, program, result, sizeof(result)); - if (err < 0) - return err; + r = udev_event_spawn(event, timeout_usec, false, program, result, sizeof result); + if (r < 0) + return r; + if (r > 0) + return -EIO; line = result; while (line) { @@ -831,13 +833,15 @@ static const char *get_key_attribute(char *str) { return NULL; } -static void rule_add_key(struct rule_tmp *rule_tmp, enum token_type type, - enum operation_type op, - const char *value, const void *data) { +static int rule_add_key(struct rule_tmp *rule_tmp, enum token_type type, + enum operation_type op, + const char *value, const void *data) { struct token *token = rule_tmp->token + rule_tmp->token_cur; const char *attr = NULL; - assert(rule_tmp->token_cur < ELEMENTSOF(rule_tmp->token)); + if (rule_tmp->token_cur >= ELEMENTSOF(rule_tmp->token)) + return -E2BIG; + memzero(token, sizeof(struct token)); switch (type) { @@ -968,6 +972,8 @@ static void rule_add_key(struct rule_tmp *rule_tmp, enum token_type type, token->key.type = type; token->key.op = op; rule_tmp->token_cur++; + + return 0; } static int sort_token(UdevRules *rules, struct rule_tmp *rule_tmp) { @@ -1009,6 +1015,7 @@ static int sort_token(UdevRules *rules, struct rule_tmp *rule_tmp) { #define LOG_RULE_WARNING(fmt, ...) LOG_RULE_FULL(LOG_WARNING, fmt, ##__VA_ARGS__) #define LOG_RULE_DEBUG(fmt, ...) LOG_RULE_FULL(LOG_DEBUG, fmt, ##__VA_ARGS__) #define LOG_AND_RETURN(fmt, ...) { LOG_RULE_ERROR(fmt, __VA_ARGS__); return; } +#define LOG_AND_RETURN_ADD_KEY LOG_AND_RETURN("Temporary rule array too small, aborting event processing with %u items", rule_tmp.token_cur); static void add_rule(UdevRules *rules, char *line, const char *filename, unsigned filename_off, unsigned lineno) { @@ -1018,6 +1025,7 @@ static void add_rule(UdevRules *rules, char *line, .rules = rules, .rule.type = TK_RULE, }; + int r; /* the offset in the rule is limited to unsigned short */ if (filename_off < USHRT_MAX) @@ -1051,26 +1059,26 @@ static void add_rule(UdevRules *rules, char *line, break; } - if (rule_tmp.token_cur >= ELEMENTSOF(rule_tmp.token)) - LOG_AND_RETURN("Temporary rule array too small, aborting event processing with %u items", rule_tmp.token_cur); - if (streq(key, "ACTION")) { if (op > OP_MATCH_MAX) LOG_AND_RETURN("Invalid %s operation", key); - rule_add_key(&rule_tmp, TK_M_ACTION, op, value, NULL); + if (rule_add_key(&rule_tmp, TK_M_ACTION, op, value, NULL) < 0) + LOG_AND_RETURN_ADD_KEY; } else if (streq(key, "DEVPATH")) { if (op > OP_MATCH_MAX) LOG_AND_RETURN("Invalid %s operation", key); - rule_add_key(&rule_tmp, TK_M_DEVPATH, op, value, NULL); + if (rule_add_key(&rule_tmp, TK_M_DEVPATH, op, value, NULL) < 0) + LOG_AND_RETURN_ADD_KEY; } else if (streq(key, "KERNEL")) { if (op > OP_MATCH_MAX) LOG_AND_RETURN("Invalid %s operation", key); - rule_add_key(&rule_tmp, TK_M_KERNEL, op, value, NULL); + if (rule_add_key(&rule_tmp, TK_M_KERNEL, op, value, NULL) < 0) + LOG_AND_RETURN_ADD_KEY; } else if (streq(key, "SUBSYSTEM")) { if (op > OP_MATCH_MAX) @@ -1081,15 +1089,18 @@ static void add_rule(UdevRules *rules, char *line, if (!streq(value, "subsystem")) LOG_RULE_WARNING("'%s' must be specified as 'subsystem'; please fix", value); - rule_add_key(&rule_tmp, TK_M_SUBSYSTEM, op, "subsystem|class|bus", NULL); + r = rule_add_key(&rule_tmp, TK_M_SUBSYSTEM, op, "subsystem|class|bus", NULL); } else - rule_add_key(&rule_tmp, TK_M_SUBSYSTEM, op, value, NULL); + r = rule_add_key(&rule_tmp, TK_M_SUBSYSTEM, op, value, NULL); + if (r < 0) + LOG_AND_RETURN_ADD_KEY; } else if (streq(key, "DRIVER")) { if (op > OP_MATCH_MAX) LOG_AND_RETURN("Invalid %s operation", key); - rule_add_key(&rule_tmp, TK_M_DRIVER, op, value, NULL); + if (rule_add_key(&rule_tmp, TK_M_DRIVER, op, value, NULL) < 0) + LOG_AND_RETURN_ADD_KEY; } else if (startswith(key, "ATTR{")) { attr = get_key_attribute(key + STRLEN("ATTR")); @@ -1100,9 +1111,11 @@ static void add_rule(UdevRules *rules, char *line, LOG_AND_RETURN("Invalid %s operation", "ATTR"); if (op < OP_MATCH_MAX) - rule_add_key(&rule_tmp, TK_M_ATTR, op, value, attr); + r = rule_add_key(&rule_tmp, TK_M_ATTR, op, value, attr); else - rule_add_key(&rule_tmp, TK_A_ATTR, op, value, attr); + r = rule_add_key(&rule_tmp, TK_A_ATTR, op, value, attr); + if (r < 0) + LOG_AND_RETURN_ADD_KEY; } else if (startswith(key, "SYSCTL{")) { attr = get_key_attribute(key + STRLEN("SYSCTL")); @@ -1113,9 +1126,11 @@ static void add_rule(UdevRules *rules, char *line, LOG_AND_RETURN("Invalid %s operation", "ATTR"); if (op < OP_MATCH_MAX) - rule_add_key(&rule_tmp, TK_M_SYSCTL, op, value, attr); + r = rule_add_key(&rule_tmp, TK_M_SYSCTL, op, value, attr); else - rule_add_key(&rule_tmp, TK_A_SYSCTL, op, value, attr); + r = rule_add_key(&rule_tmp, TK_A_SYSCTL, op, value, attr); + if (r < 0) + LOG_AND_RETURN_ADD_KEY; } else if (startswith(key, "SECLABEL{")) { attr = get_key_attribute(key + STRLEN("SECLABEL")); @@ -1125,25 +1140,29 @@ static void add_rule(UdevRules *rules, char *line, if (op == OP_REMOVE) LOG_AND_RETURN("Invalid %s operation", "SECLABEL"); - rule_add_key(&rule_tmp, TK_A_SECLABEL, op, value, attr); + if (rule_add_key(&rule_tmp, TK_A_SECLABEL, op, value, attr) < 0) + LOG_AND_RETURN_ADD_KEY; } else if (streq(key, "KERNELS")) { if (op > OP_MATCH_MAX) LOG_AND_RETURN("Invalid %s operation", key); - rule_add_key(&rule_tmp, TK_M_KERNELS, op, value, NULL); + if (rule_add_key(&rule_tmp, TK_M_KERNELS, op, value, NULL) < 0) + LOG_AND_RETURN_ADD_KEY; } else if (streq(key, "SUBSYSTEMS")) { if (op > OP_MATCH_MAX) LOG_AND_RETURN("Invalid %s operation", key); - rule_add_key(&rule_tmp, TK_M_SUBSYSTEMS, op, value, NULL); + if (rule_add_key(&rule_tmp, TK_M_SUBSYSTEMS, op, value, NULL) < 0) + LOG_AND_RETURN_ADD_KEY; } else if (streq(key, "DRIVERS")) { if (op > OP_MATCH_MAX) LOG_AND_RETURN("Invalid %s operation", key); - rule_add_key(&rule_tmp, TK_M_DRIVERS, op, value, NULL); + if (rule_add_key(&rule_tmp, TK_M_DRIVERS, op, value, NULL) < 0) + LOG_AND_RETURN_ADD_KEY; } else if (startswith(key, "ATTRS{")) { if (op > OP_MATCH_MAX) @@ -1157,13 +1176,15 @@ static void add_rule(UdevRules *rules, char *line, LOG_RULE_WARNING("'device' link may not be available in future kernels; please fix"); if (strstr(attr, "../")) LOG_RULE_WARNING("Direct reference to parent sysfs directory, may break in future kernels; please fix"); - rule_add_key(&rule_tmp, TK_M_ATTRS, op, value, attr); + if (rule_add_key(&rule_tmp, TK_M_ATTRS, op, value, attr) < 0) + LOG_AND_RETURN_ADD_KEY; } else if (streq(key, "TAGS")) { if (op > OP_MATCH_MAX) LOG_AND_RETURN("Invalid %s operation", key); - rule_add_key(&rule_tmp, TK_M_TAGS, op, value, NULL); + if (rule_add_key(&rule_tmp, TK_M_TAGS, op, value, NULL) < 0) + LOG_AND_RETURN_ADD_KEY; } else if (startswith(key, "ENV{")) { attr = get_key_attribute(key + STRLEN("ENV")); @@ -1174,7 +1195,7 @@ static void add_rule(UdevRules *rules, char *line, LOG_AND_RETURN("Invalid %s operation", "ENV"); if (op < OP_MATCH_MAX) - rule_add_key(&rule_tmp, TK_M_ENV, op, value, attr); + r = rule_add_key(&rule_tmp, TK_M_ENV, op, value, attr); else { if (STR_IN_SET(attr, "ACTION", @@ -1190,26 +1211,32 @@ static void add_rule(UdevRules *rules, char *line, "TAGS")) LOG_AND_RETURN("Invalid ENV attribute, '%s' cannot be set", attr); - rule_add_key(&rule_tmp, TK_A_ENV, op, value, attr); + r = rule_add_key(&rule_tmp, TK_A_ENV, op, value, attr); } + if (r < 0) + LOG_AND_RETURN_ADD_KEY; } else if (streq(key, "TAG")) { if (op < OP_MATCH_MAX) - rule_add_key(&rule_tmp, TK_M_TAG, op, value, NULL); + r = rule_add_key(&rule_tmp, TK_M_TAG, op, value, NULL); else - rule_add_key(&rule_tmp, TK_A_TAG, op, value, NULL); + r = rule_add_key(&rule_tmp, TK_A_TAG, op, value, NULL); + if (r < 0) + LOG_AND_RETURN_ADD_KEY; } else if (streq(key, "PROGRAM")) { if (op == OP_REMOVE) LOG_AND_RETURN("Invalid %s operation", key); - rule_add_key(&rule_tmp, TK_M_PROGRAM, op, value, NULL); + if (rule_add_key(&rule_tmp, TK_M_PROGRAM, op, value, NULL) < 0) + LOG_AND_RETURN_ADD_KEY; } else if (streq(key, "RESULT")) { if (op > OP_MATCH_MAX) LOG_AND_RETURN("Invalid %s operation", key); - rule_add_key(&rule_tmp, TK_M_RESULT, op, value, NULL); + if (rule_add_key(&rule_tmp, TK_M_RESULT, op, value, NULL) < 0) + LOG_AND_RETURN_ADD_KEY; } else if (startswith(key, "IMPORT")) { attr = get_key_attribute(key + STRLEN("IMPORT")); @@ -1227,28 +1254,34 @@ static void add_rule(UdevRules *rules, char *line, if (cmd >= 0) { LOG_RULE_DEBUG("IMPORT found builtin '%s', replacing", value); - rule_add_key(&rule_tmp, TK_M_IMPORT_BUILTIN, op, value, &cmd); + if (rule_add_key(&rule_tmp, TK_M_IMPORT_BUILTIN, op, value, &cmd) < 0) + LOG_AND_RETURN_ADD_KEY; continue; } } - rule_add_key(&rule_tmp, TK_M_IMPORT_PROG, op, value, NULL); + r = rule_add_key(&rule_tmp, TK_M_IMPORT_PROG, op, value, NULL); } else if (streq(attr, "builtin")) { const enum udev_builtin_cmd cmd = udev_builtin_lookup(value); - if (cmd < 0) - LOG_RULE_WARNING("IMPORT{builtin} '%s' unknown", value); - else - rule_add_key(&rule_tmp, TK_M_IMPORT_BUILTIN, op, value, &cmd); + if (cmd < 0) { + LOG_RULE_WARNING("IMPORT{builtin} '%s' unknown, ignoring", value); + continue; + } else + r = rule_add_key(&rule_tmp, TK_M_IMPORT_BUILTIN, op, value, &cmd); } else if (streq(attr, "file")) - rule_add_key(&rule_tmp, TK_M_IMPORT_FILE, op, value, NULL); + r = rule_add_key(&rule_tmp, TK_M_IMPORT_FILE, op, value, NULL); else if (streq(attr, "db")) - rule_add_key(&rule_tmp, TK_M_IMPORT_DB, op, value, NULL); + r = rule_add_key(&rule_tmp, TK_M_IMPORT_DB, op, value, NULL); else if (streq(attr, "cmdline")) - rule_add_key(&rule_tmp, TK_M_IMPORT_CMDLINE, op, value, NULL); + r = rule_add_key(&rule_tmp, TK_M_IMPORT_CMDLINE, op, value, NULL); else if (streq(attr, "parent")) - rule_add_key(&rule_tmp, TK_M_IMPORT_PARENT, op, value, NULL); - else + r = rule_add_key(&rule_tmp, TK_M_IMPORT_PARENT, op, value, NULL); + else { LOG_RULE_ERROR("Ignoring unknown %s{} type '%s'", "IMPORT", attr); + continue; + } + if (r < 0) + LOG_AND_RETURN_ADD_KEY; } else if (startswith(key, "TEST")) { mode_t mode = 0; @@ -1259,9 +1292,11 @@ static void add_rule(UdevRules *rules, char *line, attr = get_key_attribute(key + STRLEN("TEST")); if (attr) { mode = strtol(attr, NULL, 8); - rule_add_key(&rule_tmp, TK_M_TEST, op, value, &mode); + r = rule_add_key(&rule_tmp, TK_M_TEST, op, value, &mode); } else - rule_add_key(&rule_tmp, TK_M_TEST, op, value, NULL); + r = rule_add_key(&rule_tmp, TK_M_TEST, op, value, NULL); + if (r < 0) + LOG_AND_RETURN_ADD_KEY; } else if (startswith(key, "RUN")) { attr = get_key_attribute(key + STRLEN("RUN")); @@ -1273,16 +1308,21 @@ static void add_rule(UdevRules *rules, char *line, if (streq(attr, "builtin")) { const enum udev_builtin_cmd cmd = udev_builtin_lookup(value); - if (cmd < 0) - LOG_RULE_ERROR("RUN{builtin}: '%s' unknown", value); - else - rule_add_key(&rule_tmp, TK_A_RUN_BUILTIN, op, value, &cmd); + if (cmd < 0) { + LOG_RULE_ERROR("RUN{builtin}: '%s' unknown, ignoring", value); + continue; + } else + r = rule_add_key(&rule_tmp, TK_A_RUN_BUILTIN, op, value, &cmd); } else if (streq(attr, "program")) { const enum udev_builtin_cmd cmd = _UDEV_BUILTIN_MAX; - rule_add_key(&rule_tmp, TK_A_RUN_PROGRAM, op, value, &cmd); - } else + r = rule_add_key(&rule_tmp, TK_A_RUN_PROGRAM, op, value, &cmd); + } else { LOG_RULE_ERROR("Ignoring unknown %s{} type '%s'", "RUN", attr); + continue; + } + if (r < 0) + LOG_AND_RETURN_ADD_KEY; } else if (streq(key, "LABEL")) { if (op == OP_REMOVE) @@ -1294,14 +1334,15 @@ static void add_rule(UdevRules *rules, char *line, if (op == OP_REMOVE) LOG_AND_RETURN("Invalid %s operation", key); - rule_add_key(&rule_tmp, TK_A_GOTO, 0, value, NULL); + if (rule_add_key(&rule_tmp, TK_A_GOTO, 0, value, NULL) < 0) + LOG_AND_RETURN_ADD_KEY; } else if (startswith(key, "NAME")) { if (op == OP_REMOVE) LOG_AND_RETURN("Invalid %s operation", key); if (op < OP_MATCH_MAX) - rule_add_key(&rule_tmp, TK_M_NAME, op, value, NULL); + r = rule_add_key(&rule_tmp, TK_M_NAME, op, value, NULL); else { if (streq(value, "%k")) { LOG_RULE_WARNING("NAME=\"%%k\" is ignored, because it breaks kernel supplied names; please remove"); @@ -1311,8 +1352,10 @@ static void add_rule(UdevRules *rules, char *line, LOG_RULE_DEBUG("NAME=\"\" is ignored, because udev will not delete any device nodes; please remove"); continue; } - rule_add_key(&rule_tmp, TK_A_NAME, op, value, NULL); + r = rule_add_key(&rule_tmp, TK_A_NAME, op, value, NULL); } + if (r < 0) + LOG_AND_RETURN_ADD_KEY; rule_tmp.rule.rule.can_set_name = true; } else if (streq(key, "SYMLINK")) { @@ -1320,9 +1363,11 @@ static void add_rule(UdevRules *rules, char *line, LOG_AND_RETURN("Invalid %s operation", key); if (op < OP_MATCH_MAX) - rule_add_key(&rule_tmp, TK_M_DEVLINK, op, value, NULL); + r = rule_add_key(&rule_tmp, TK_M_DEVLINK, op, value, NULL); else - rule_add_key(&rule_tmp, TK_A_DEVLINK, op, value, NULL); + r = rule_add_key(&rule_tmp, TK_A_DEVLINK, op, value, NULL); + if (r < 0) + LOG_AND_RETURN_ADD_KEY; rule_tmp.rule.rule.can_set_name = true; } else if (streq(key, "OWNER")) { @@ -1334,12 +1379,18 @@ static void add_rule(UdevRules *rules, char *line, uid = strtoul(value, &endptr, 10); if (endptr[0] == '\0') - rule_add_key(&rule_tmp, TK_A_OWNER_ID, op, NULL, &uid); + r = rule_add_key(&rule_tmp, TK_A_OWNER_ID, op, NULL, &uid); else if (rules->resolve_name_timing == RESOLVE_NAME_EARLY && !strchr("$%", value[0])) { uid = add_uid(rules, value); - rule_add_key(&rule_tmp, TK_A_OWNER_ID, op, NULL, &uid); + r = rule_add_key(&rule_tmp, TK_A_OWNER_ID, op, NULL, &uid); } else if (rules->resolve_name_timing != RESOLVE_NAME_NEVER) - rule_add_key(&rule_tmp, TK_A_OWNER, op, value, NULL); + r = rule_add_key(&rule_tmp, TK_A_OWNER, op, value, NULL); + else { + LOG_RULE_ERROR("Invalid %s operation", key); + continue; + } + if (r < 0) + LOG_AND_RETURN_ADD_KEY; rule_tmp.rule.rule.can_set_name = true; @@ -1352,12 +1403,18 @@ static void add_rule(UdevRules *rules, char *line, gid = strtoul(value, &endptr, 10); if (endptr[0] == '\0') - rule_add_key(&rule_tmp, TK_A_GROUP_ID, op, NULL, &gid); + r = rule_add_key(&rule_tmp, TK_A_GROUP_ID, op, NULL, &gid); else if ((rules->resolve_name_timing == RESOLVE_NAME_EARLY) && !strchr("$%", value[0])) { gid = add_gid(rules, value); - rule_add_key(&rule_tmp, TK_A_GROUP_ID, op, NULL, &gid); + r = rule_add_key(&rule_tmp, TK_A_GROUP_ID, op, NULL, &gid); } else if (rules->resolve_name_timing != RESOLVE_NAME_NEVER) - rule_add_key(&rule_tmp, TK_A_GROUP, op, value, NULL); + r = rule_add_key(&rule_tmp, TK_A_GROUP, op, value, NULL); + else { + LOG_RULE_ERROR("Invalid %s operation", key); + continue; + } + if (r < 0) + LOG_AND_RETURN_ADD_KEY; rule_tmp.rule.rule.can_set_name = true; @@ -1370,9 +1427,12 @@ static void add_rule(UdevRules *rules, char *line, mode = strtol(value, &endptr, 8); if (endptr[0] == '\0') - rule_add_key(&rule_tmp, TK_A_MODE_ID, op, NULL, &mode); + r = rule_add_key(&rule_tmp, TK_A_MODE_ID, op, NULL, &mode); else - rule_add_key(&rule_tmp, TK_A_MODE, op, value, NULL); + r = rule_add_key(&rule_tmp, TK_A_MODE, op, value, NULL); + if (r < 0) + LOG_AND_RETURN_ADD_KEY; + rule_tmp.rule.rule.can_set_name = true; } else if (streq(key, "OPTIONS")) { @@ -1385,37 +1445,48 @@ static void add_rule(UdevRules *rules, char *line, if (pos) { int prio = atoi(pos + STRLEN("link_priority=")); - rule_add_key(&rule_tmp, TK_A_DEVLINK_PRIO, op, NULL, &prio); + if (rule_add_key(&rule_tmp, TK_A_DEVLINK_PRIO, op, NULL, &prio) < 0) + LOG_AND_RETURN_ADD_KEY; } pos = strstr(value, "string_escape="); if (pos) { pos += STRLEN("string_escape="); if (startswith(pos, "none")) - rule_add_key(&rule_tmp, TK_A_STRING_ESCAPE_NONE, op, NULL, NULL); + r = rule_add_key(&rule_tmp, TK_A_STRING_ESCAPE_NONE, op, NULL, NULL); else if (startswith(pos, "replace")) - rule_add_key(&rule_tmp, TK_A_STRING_ESCAPE_REPLACE, op, NULL, NULL); + r = rule_add_key(&rule_tmp, TK_A_STRING_ESCAPE_REPLACE, op, NULL, NULL); + else { + LOG_RULE_ERROR("OPTIONS: unknown string_escape mode '%s', ignoring", pos); + r = 0; + } + if (r < 0) + LOG_AND_RETURN_ADD_KEY; } pos = strstr(value, "db_persist"); if (pos) - rule_add_key(&rule_tmp, TK_A_DB_PERSIST, op, NULL, NULL); + if (rule_add_key(&rule_tmp, TK_A_DB_PERSIST, op, NULL, NULL) < 0) + LOG_AND_RETURN_ADD_KEY; pos = strstr(value, "nowatch"); if (pos) { static const int zero = 0; - rule_add_key(&rule_tmp, TK_A_INOTIFY_WATCH, op, NULL, &zero); + if (rule_add_key(&rule_tmp, TK_A_INOTIFY_WATCH, op, NULL, &zero) < 0) + LOG_AND_RETURN_ADD_KEY; } else { static const int one = 1; pos = strstr(value, "watch"); if (pos) - rule_add_key(&rule_tmp, TK_A_INOTIFY_WATCH, op, NULL, &one); + if (rule_add_key(&rule_tmp, TK_A_INOTIFY_WATCH, op, NULL, &one) < 0) + LOG_AND_RETURN_ADD_KEY; } pos = strstr(value, "static_node="); if (pos) { pos += STRLEN("static_node="); - rule_add_key(&rule_tmp, TK_A_STATIC_NODE, op, pos, NULL); + if (rule_add_key(&rule_tmp, TK_A_STATIC_NODE, op, pos, NULL) < 0) + LOG_AND_RETURN_ADD_KEY; rule_tmp.rule.rule.has_static_node = true; } @@ -1959,7 +2030,7 @@ int udev_rules_apply_to_event( rules_str(rules, rule->rule.filename_off), rule->rule.filename_line); - if (udev_event_spawn(event, timeout_usec, true, program, result, sizeof(result)) < 0) { + if (udev_event_spawn(event, timeout_usec, true, program, result, sizeof(result)) != 0) { if (cur->key.op != OP_NOMATCH) goto nomatch; } else { @@ -2229,13 +2300,12 @@ int udev_rules_apply_to_event( r = hashmap_put(event->seclabel_list, name, label); if (r < 0) return log_oom(); - - name = label = NULL; - log_device_debug(dev, "SECLABEL{%s}='%s' %s:%u", name, label, rules_str(rules, rule->rule.filename_off), rule->rule.filename_line); + name = label = NULL; + break; } case TK_A_ENV: { diff --git a/src/udev/udev.pc.in b/src/udev/udev.pc.in index e384a6f7c9..5acbb2d01a 100644 --- a/src/udev/udev.pc.in +++ b/src/udev/udev.pc.in @@ -1,5 +1,5 @@ Name: udev Description: udev -Version: @PACKAGE_VERSION@ +Version: @PROJECT_VERSION@ udevdir=@udevlibexecdir@ diff --git a/src/udev/udevadm-control.c b/src/udev/udevadm-control.c index d9320418cf..7cfc4c929d 100644 --- a/src/udev/udevadm-control.c +++ b/src/udev/udevadm-control.c @@ -26,6 +26,7 @@ #include "udevadm.h" #include "udev-ctrl.h" #include "util.h" +#include "virt.h" static int help(void) { printf("%s control OPTION\n\n" @@ -39,6 +40,7 @@ static int help(void) { " -R --reload Reload rules and databases\n" " -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" , program_invocation_short_name); @@ -47,22 +49,27 @@ static int help(void) { int control_main(int argc, char *argv[], void *userdata) { _cleanup_(udev_ctrl_unrefp) struct udev_ctrl *uctrl = NULL; - int timeout = 60; + usec_t timeout = 60 * USEC_PER_SEC; int c, r; + enum { + ARG_PING = 0x100, + }; + static const struct option options[] = { - { "exit", no_argument, NULL, 'e' }, - { "log-priority", required_argument, NULL, 'l' }, - { "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' }, - { "timeout", required_argument, NULL, 't' }, - { "version", no_argument, NULL, 'V' }, - { "help", no_argument, NULL, 'h' }, + { "exit", no_argument, NULL, 'e' }, + { "log-priority", required_argument, NULL, 'l' }, + { "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' }, {} }; @@ -70,12 +77,18 @@ int control_main(int argc, char *argv[], void *userdata) { if (r < 0) return r; + if (running_in_chroot() > 0) { + log_info("Running in chroot, ignoring request."); + return 0; + } + if (argc <= 1) - log_error("Option missing"); + return log_error_errno(SYNTHETIC_ERRNO(EINVAL), + "This command expects one or more options."); uctrl = udev_ctrl_new(); if (!uctrl) - return -ENOMEM; + return log_oom(); while ((c = getopt_long(argc, argv, "el:sSRp:m:t:Vh", options, NULL)) >= 0) switch (c) { @@ -109,10 +122,9 @@ int control_main(int argc, char *argv[], void *userdata) { return r; break; case 'p': - if (!strchr(optarg, '=')) { - log_error("expect <KEY>=<value> instead of '%s'", optarg); - return -EINVAL; - } + if (!strchr(optarg, '=')) + return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "expect <KEY>=<value> instead of '%s'", optarg); + r = udev_ctrl_send_set_env(uctrl, optarg, timeout); if (r < 0) return r; @@ -129,19 +141,16 @@ int control_main(int argc, char *argv[], void *userdata) { return r; break; } - case 't': { - usec_t s; - - r = parse_sec(optarg, &s); + case ARG_PING: + r = udev_ctrl_send_ping(uctrl, timeout); if (r < 0) - return log_error_errno(r, "Failed to parse timeout value '%s'.", optarg); - - if (DIV_ROUND_UP(s, USEC_PER_SEC) > INT_MAX) - log_error("Timeout value is out of range, ignoring."); - else - timeout = s != USEC_INFINITY ? (int) DIV_ROUND_UP(s, USEC_PER_SEC) : INT_MAX; + return log_error_errno(r, "Failed to connect to udev daemon: %m"); + break; + case 't': + r = parse_sec(optarg, &timeout); + if (r < 0) + return log_error_errno(r, "Failed to parse timeout value '%s': %m", optarg); break; - } case 'V': return print_version(); case 'h': @@ -152,13 +161,9 @@ int control_main(int argc, char *argv[], void *userdata) { assert_not_reached("Unknown option."); } - if (optind < argc) { - log_error("Extraneous argument: %s", argv[optind]); - return -EINVAL; - } else if (optind == 1) { - log_error("Option missing"); - return -EINVAL; - } + if (optind < argc) + return log_error_errno(SYNTHETIC_ERRNO(EINVAL), + "Extraneous argument: %s", argv[optind]); return 0; } diff --git a/src/udev/udevadm-info.c b/src/udev/udevadm-info.c index d141bc74b2..ebd15d384a 100644 --- a/src/udev/udevadm-info.c +++ b/src/udev/udevadm-info.c @@ -61,12 +61,15 @@ static bool skip_attribute(const char *name) { static void print_all_attributes(sd_device *device, const char *key) { const char *name, *value; - FOREACH_DEVICE_PROPERTY(device, name, value) { + FOREACH_DEVICE_SYSATTR(device, name) { size_t len; if (skip_attribute(name)) continue; + if (sd_device_get_sysattr_value(device, name, &value) < 0) + continue; + /* skip any values that look like a path */ if (value[0] == '/') continue; @@ -387,10 +390,8 @@ int info_main(int argc, char *argv[], void *userdata) { query = QUERY_PATH; else if (streq(optarg, "all")) query = QUERY_ALL; - else { - log_error("unknown query type"); - return -EINVAL; - } + else + return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "unknown query type"); break; case 'r': arg_root = true; @@ -413,6 +414,7 @@ int info_main(int argc, char *argv[], void *userdata) { arg_export = true; break; case 'P': + arg_export = true; arg_export_prefix = optarg; break; case 'V': @@ -425,7 +427,6 @@ int info_main(int argc, char *argv[], void *userdata) { assert_not_reached("Unknown option"); } - if (action == ACTION_DEVICE_ID_FILE) { if (argv[optind]) return log_error_errno(SYNTHETIC_ERRNO(EINVAL), diff --git a/src/udev/udevadm-monitor.c b/src/udev/udevadm-monitor.c index f7737d0790..3dde3f338a 100644 --- a/src/udev/udevadm-monitor.c +++ b/src/udev/udevadm-monitor.c @@ -17,6 +17,7 @@ #include "signal-util.h" #include "string-util.h" #include "udevadm.h" +#include "virt.h" static bool arg_show_property = false; static bool arg_print_kernel = false; @@ -143,11 +144,11 @@ static int parse_argv(int argc, char *argv[]) { slash = strchr(optarg, '/'); if (slash) { - devtype = strdup(devtype + 1); + devtype = strdup(slash + 1); if (!devtype) return -ENOMEM; - subsystem = strndup(optarg, devtype - optarg); + subsystem = strndup(optarg, slash - optarg); } else subsystem = strdup(optarg); @@ -210,6 +211,11 @@ int monitor_main(int argc, char *argv[], void *userdata) { if (r <= 0) goto finalize; + if (running_in_chroot() > 0) { + log_info("Running in chroot, ignoring request."); + return 0; + } + /* Callers are expecting to see events as they happen: Line buffering */ setlinebuf(stdout); diff --git a/src/udev/udevadm-settle.c b/src/udev/udevadm-settle.c index 4ae237d430..8d9c4509ff 100644 --- a/src/udev/udevadm-settle.c +++ b/src/udev/udevadm-settle.c @@ -18,6 +18,7 @@ #include "udevadm.h" #include "udev-ctrl.h" #include "util.h" +#include "virt.h" static usec_t arg_timeout = 120 * USEC_PER_SEC; static const char *arg_exists = NULL; @@ -88,6 +89,11 @@ int settle_main(int argc, char *argv[], void *userdata) { if (r <= 0) return r; + if (running_in_chroot() > 0) { + log_info("Running in chroot, ignoring request."); + return 0; + } + deadline = now(CLOCK_MONOTONIC) + arg_timeout; /* guarantee that the udev daemon isn't pre-processing */ @@ -96,9 +102,9 @@ int settle_main(int argc, char *argv[], void *userdata) { uctrl = udev_ctrl_new(); if (uctrl) { - r = udev_ctrl_send_ping(uctrl, MAX(5U, arg_timeout / USEC_PER_SEC)); + r = udev_ctrl_send_ping(uctrl, MAX(5 * USEC_PER_SEC, arg_timeout)); if (r < 0) { - log_debug_errno(r, "Failed to connect to udev daemon."); + log_debug_errno(r, "Failed to connect to udev daemon: %m"); return 0; } } diff --git a/src/udev/udevadm-trigger.c b/src/udev/udevadm-trigger.c index f13a08f3f9..95329469e3 100644 --- a/src/udev/udevadm-trigger.c +++ b/src/udev/udevadm-trigger.c @@ -10,11 +10,14 @@ #include "fd-util.h" #include "fileio.h" #include "path-util.h" +#include "process-util.h" #include "set.h" #include "string-util.h" #include "strv.h" #include "udevadm.h" #include "udevadm-util.h" +#include "udev-ctrl.h" +#include "virt.h" static bool arg_verbose = false; static bool arg_dry_run = false; @@ -117,6 +120,8 @@ static int help(void) { " --name-match=NAME Trigger devices with this /dev name\n" " -b --parent-match=NAME Trigger devices with that parent device\n" " -w --settle Wait for the triggered events to complete\n" + " --wait-daemon[=SECONDS] Wait for udevd daemon to be initialized\n" + " before triggering uevents\n" , program_invocation_short_name); return 0; @@ -125,6 +130,7 @@ static int help(void) { int trigger_main(int argc, char *argv[], void *userdata) { enum { ARG_NAME = 0x100, + ARG_PING, }; static const struct option options[] = { @@ -142,6 +148,7 @@ int trigger_main(int argc, char *argv[], void *userdata) { { "name-match", required_argument, NULL, ARG_NAME }, { "parent-match", required_argument, NULL, 'b' }, { "settle", no_argument, NULL, 'w' }, + { "wait-daemon", optional_argument, NULL, ARG_PING }, { "version", no_argument, NULL, 'V' }, { "help", no_argument, NULL, 'h' }, {} @@ -155,9 +162,15 @@ int trigger_main(int argc, char *argv[], void *userdata) { _cleanup_(sd_device_monitor_unrefp) sd_device_monitor *m = NULL; _cleanup_(sd_event_unrefp) sd_event *event = NULL; _cleanup_set_free_free_ Set *settle_set = NULL; - bool settle = false; + usec_t ping_timeout_usec = 5 * USEC_PER_SEC; + bool settle = false, ping = false; int c, r; + if (running_in_chroot() > 0) { + log_info("Running in chroot, ignoring request."); + return 0; + } + r = sd_device_enumerator_new(&e); if (r < 0) return r; @@ -182,18 +195,14 @@ int trigger_main(int argc, char *argv[], void *userdata) { device_type = TYPE_DEVICES; else if (streq(optarg, "subsystems")) device_type = TYPE_SUBSYSTEMS; - else { - log_error("Unknown type --type=%s", optarg); - return -EINVAL; - } + else + return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Unknown type --type=%s", optarg); break; case 'c': if (STR_IN_SET(optarg, "add", "remove", "change")) action = optarg; - else { - log_error("Unknown action '%s'", optarg); - return -EINVAL; - } + else + log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Unknown action '%s'", optarg); break; case 's': @@ -269,6 +278,16 @@ int trigger_main(int argc, char *argv[], void *userdata) { break; } + case ARG_PING: { + ping = true; + if (optarg) { + r = parse_sec(optarg, &ping_timeout_usec); + if (r < 0) + log_error_errno(r, "Failed to parse timeout value '%s', ignoring: %m", optarg); + } + break; + } + case 'V': return print_version(); case 'h': @@ -280,6 +299,24 @@ int trigger_main(int argc, char *argv[], void *userdata) { } } + if (!arg_dry_run || ping) { + r = must_be_root(); + if (r < 0) + return r; + } + + if (ping) { + _cleanup_(udev_ctrl_unrefp) struct udev_ctrl *uctrl = NULL; + + uctrl = udev_ctrl_new(); + if (!uctrl) + return log_oom(); + + r = udev_ctrl_send_ping(uctrl, ping_timeout_usec); + if (r < 0) + return log_error_errno(r, "Failed to connect to udev daemon: %m"); + } + for (; optind < argc; optind++) { _cleanup_(sd_device_unrefp) sd_device *dev = NULL; diff --git a/src/udev/udevadm.c b/src/udev/udevadm.c index 1125c54b9f..28194314de 100644 --- a/src/udev/udevadm.c +++ b/src/udev/udevadm.c @@ -113,12 +113,13 @@ static int run(int argc, char *argv[]) { udev_parse_config(); log_parse_environment(); log_open(); - log_set_max_level_realm(LOG_REALM_SYSTEMD, log_get_max_level()); r = parse_argv(argc, argv); if (r <= 0) return r; + log_set_max_level_realm(LOG_REALM_SYSTEMD, log_get_max_level()); + mac_selinux_init(); return udevadm_main(argc, argv); } diff --git a/src/udev/udevadm.h b/src/udev/udevadm.h index 98f9019a48..86b24af086 100644 --- a/src/udev/udevadm.h +++ b/src/udev/udevadm.h @@ -3,6 +3,9 @@ #include <stdio.h> +#include "build.h" +#include "macro.h" + int info_main(int argc, char *argv[], void *userdata); int trigger_main(int argc, char *argv[], void *userdata); int settle_main(int argc, char *argv[], void *userdata); @@ -13,6 +16,7 @@ int test_main(int argc, char *argv[], void *userdata); int builtin_main(int argc, char *argv[], void *userdata); static inline int print_version(void) { - puts(PACKAGE_VERSION); + /* Dracut relies on the version being a single integer */ + puts(STRINGIFY(PROJECT_VERSION)); return 0; } diff --git a/src/udev/udevd.c b/src/udev/udevd.c index fb8724ea87..0303f36b4f 100644 --- a/src/udev/udevd.c +++ b/src/udev/udevd.c @@ -31,6 +31,7 @@ #include "sd-event.h" #include "alloc-util.h" +#include "build.h" #include "cgroup-util.h" #include "cpu-set-util.h" #include "dev-setup.h" @@ -185,20 +186,11 @@ static void worker_free(struct worker *worker) { free(worker); } -static void manager_workers_free(Manager *manager) { - struct worker *worker; - Iterator i; - - assert(manager); - - HASHMAP_FOREACH(worker, manager->workers, i) - worker_free(worker); - - manager->workers = hashmap_free(manager->workers); -} +DEFINE_TRIVIAL_CLEANUP_FUNC(struct worker *, worker_free); +DEFINE_PRIVATE_HASH_OPS_WITH_VALUE_DESTRUCTOR(worker_hash_op, void, trivial_hash_func, trivial_compare_func, struct worker, worker_free); static int worker_new(struct worker **ret, Manager *manager, sd_device_monitor *worker_monitor, pid_t pid) { - _cleanup_free_ struct worker *worker = NULL; + _cleanup_(worker_freep) struct worker *worker = NULL; int r; assert(ret); @@ -206,17 +198,20 @@ static int worker_new(struct worker **ret, Manager *manager, sd_device_monitor * assert(worker_monitor); assert(pid > 1); - worker = new0(struct worker, 1); + /* close monitor, but keep address around */ + device_monitor_disconnect(worker_monitor); + + worker = new(struct worker, 1); if (!worker) return -ENOMEM; - worker->manager = manager; - /* close monitor, but keep address around */ - device_monitor_disconnect(worker_monitor); - worker->monitor = sd_device_monitor_ref(worker_monitor); - worker->pid = pid; + *worker = (struct worker) { + .manager = manager, + .monitor = sd_device_monitor_ref(worker_monitor), + .pid = pid, + }; - r = hashmap_ensure_allocated(&manager->workers, NULL); + r = hashmap_ensure_allocated(&manager->workers, &worker_hash_op); if (r < 0) return r; @@ -290,7 +285,7 @@ static void manager_clear_for_worker(Manager *manager) { manager->event = sd_event_unref(manager->event); - manager_workers_free(manager); + manager->workers = hashmap_free(manager->workers); event_queue_cleanup(manager, EVENT_UNDEF); manager->monitor = sd_device_monitor_unref(manager->monitor); @@ -396,7 +391,7 @@ static int worker_lock_block_device(sd_device *dev, int *ret_fd) { static int worker_process_device(Manager *manager, sd_device *dev) { _cleanup_(udev_event_freep) UdevEvent *udev_event = NULL; _cleanup_close_ int fd_lock = -1; - const char *seqnum; + const char *seqnum, *action; int r; assert(manager); @@ -404,9 +399,13 @@ static int worker_process_device(Manager *manager, sd_device *dev) { r = sd_device_get_property_value(dev, "SEQNUM", &seqnum); if (r < 0) - log_device_debug_errno(dev, r, "Failed to get SEQNUM: %m"); + return log_device_debug_errno(dev, r, "Failed to get SEQNUM: %m"); - log_device_debug(dev, "Processing device (SEQNUM=%s)", seqnum); + r = sd_device_get_property_value(dev, "ACTION", &action); + if (r < 0) + return log_device_debug_errno(dev, r, "Failed to get ACTION: %m"); + + log_device_debug(dev, "Processing device (SEQNUM=%s, ACTION=%s)", seqnum, action); udev_event = udev_event_new(dev, arg_exec_delay_usec, manager->rtnl); if (!udev_event) @@ -432,7 +431,7 @@ static int worker_process_device(Manager *manager, sd_device *dev) { return log_device_debug_errno(dev, r, "Failed to update database under /run/udev/data/: %m"); } - log_device_debug(dev, "Device (SEQNUM=%s) processed", seqnum); + log_device_debug(dev, "Device (SEQNUM=%s, ACTION=%s) processed", seqnum, action); return 0; } @@ -464,7 +463,7 @@ static int worker_device_monitor_handler(sd_device_monitor *monitor, sd_device * static int worker_main(Manager *_manager, sd_device_monitor *monitor, sd_device *first_device) { _cleanup_(sd_device_unrefp) sd_device *dev = first_device; _cleanup_(manager_freep) Manager *manager = _manager; - int r, ret; + int r; assert(manager); assert(monitor); @@ -507,11 +506,7 @@ static int worker_main(Manager *_manager, sd_device_monitor *monitor, sd_device if (r < 0) return log_error_errno(r, "Event loop failed: %m"); - r = sd_event_get_exit_code(manager->event, &ret); - if (r < 0) - return log_error_errno(r, "Failed to get exit code: %m"); - - return ret; + return 0; } static int worker_spawn(Manager *manager, struct event *event) { @@ -534,7 +529,7 @@ static int worker_spawn(Manager *manager, struct event *event) { if (r < 0) return log_error_errno(r, "Worker: Failed to enable receiving of device: %m"); - r = safe_fork("(worker)", FORK_DEATHSIG, &pid); + r = safe_fork(NULL, FORK_DEATHSIG, &pid); if (r < 0) { event->state = EVENT_QUEUED; return log_error_errno(r, "Failed to fork() worker: %m"); @@ -592,8 +587,8 @@ static void event_run(Manager *manager, struct event *event) { static int event_queue_insert(Manager *manager, sd_device *dev) { _cleanup_(sd_device_unrefp) sd_device *clone = NULL; + const char *val, *action; struct event *event; - const char *val; uint64_t seqnum; int r; @@ -618,6 +613,11 @@ static int event_queue_insert(Manager *manager, sd_device *dev) { if (seqnum == 0) return -EINVAL; + /* Refuse devices do not have ACTION property. */ + r = sd_device_get_property_value(dev, "ACTION", &action); + if (r < 0) + return r; + /* Save original device to restore the state on failures. */ r = device_shallow_clone(dev, &clone); if (r < 0) @@ -647,12 +647,7 @@ static int event_queue_insert(Manager *manager, sd_device *dev) { LIST_APPEND(event, manager->events, event); - if (DEBUG_LOGGING) { - if (sd_device_get_property_value(dev, "ACTION", &val) < 0) - val = NULL; - - log_device_debug(dev, "Device (SEQNUM=%"PRIu64", ACTION=%s) is queued", seqnum, strnull(val)); - } + log_device_debug(dev, "Device (SEQNUM=%"PRIu64", ACTION=%s) is queued", seqnum, action); return 0; } @@ -875,7 +870,7 @@ static void event_queue_start(Manager *manager) { assert_se(sd_event_now(manager->event, CLOCK_MONOTONIC, &usec) >= 0); /* check for changed config, every 3 seconds at most */ if (manager->last_usec == 0 || - (usec - manager->last_usec) > 3 * USEC_PER_SEC) { + usec - manager->last_usec > 3 * USEC_PER_SEC) { if (udev_rules_check_timestamp(manager->rules) || udev_builtin_validate()) manager_reload(manager); @@ -960,12 +955,11 @@ static int on_worker(sd_event_source *s, int fd, uint32_t revents, void *userdat continue; } - CMSG_FOREACH(cmsg, &msghdr) { + CMSG_FOREACH(cmsg, &msghdr) if (cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_CREDENTIALS && cmsg->cmsg_len == CMSG_LEN(sizeof(struct ucred))) ucred = (struct ucred*) CMSG_DATA(cmsg); - } if (!ucred || ucred->pid <= 0) { log_warning("Ignoring worker message without valid PID"); @@ -1033,7 +1027,8 @@ static int on_ctrl_msg(sd_event_source *s, int fd, uint32_t revents, void *userd i = udev_ctrl_get_set_log_level(ctrl_msg); if (i >= 0) { log_debug("Received udev control message (SET_LOG_LEVEL), setting log_priority=%i", i); - log_set_max_level(i); + log_set_max_level_realm(LOG_REALM_UDEV, i); + log_set_max_level_realm(LOG_REALM_SYSTEMD, i); manager_kill_workers(manager); } @@ -1118,7 +1113,7 @@ static int on_ctrl_msg(sd_event_source *s, int fd, uint32_t revents, void *userd } if (udev_ctrl_get_ping(ctrl_msg) > 0) - log_debug("Received udev control message (SYNC)"); + log_debug("Received udev control message (PING)"); if (udev_ctrl_get_exit(ctrl_msg) > 0) { log_debug("Received udev control message (EXIT)"); @@ -1338,9 +1333,9 @@ static int on_sigchld(sd_event_source *s, const struct signalfd_siginfo *si, voi log_debug("Worker ["PID_FMT"] exited", pid); else log_warning("Worker ["PID_FMT"] exited with return code %i", pid, WEXITSTATUS(status)); - } else if (WIFSIGNALED(status)) { + } else if (WIFSIGNALED(status)) log_warning("Worker ["PID_FMT"] terminated by signal %i (%s)", pid, WTERMSIG(status), signal_to_string(WTERMSIG(status))); - } else if (WIFSTOPPED(status)) { + else if (WIFSTOPPED(status)) { log_info("Worker ["PID_FMT"] stopped", pid); continue; } else if (WIFCONTINUED(status)) { @@ -1579,7 +1574,7 @@ static int parse_argv(int argc, char *argv[]) { case 'h': return help(); case 'V': - printf("%s\n", PACKAGE_VERSION); + printf("%s\n", GIT_VERSION); return 0; case '?': return -EINVAL; @@ -1594,7 +1589,7 @@ static int parse_argv(int argc, char *argv[]) { static int manager_new(Manager **ret, int fd_ctrl, int fd_uevent, const char *cgroup) { _cleanup_(manager_freep) Manager *manager = NULL; - int r, fd_worker; + int r; assert(ret); @@ -1608,25 +1603,13 @@ static int manager_new(Manager **ret, int fd_ctrl, int fd_uevent, const char *cg .cgroup = cgroup, }; - udev_builtin_init(); - - r = udev_rules_new(&manager->rules, arg_resolve_name_timing); - if (!manager->rules) - return log_error_errno(r, "Failed to read udev rules: %m"); - manager->ctrl = udev_ctrl_new_from_fd(fd_ctrl); if (!manager->ctrl) return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Failed to initialize udev control socket"); - if (fd_ctrl < 0) { - r = udev_ctrl_enable_receiving(manager->ctrl); - if (r < 0) - return log_error_errno(r, "Failed to bind udev control socket: %m"); - } - - fd_ctrl = udev_ctrl_get_fd(manager->ctrl); - if (fd_ctrl < 0) - return log_error_errno(fd_ctrl, "Failed to get udev control socket fd: %m"); + r = udev_ctrl_enable_receiving(manager->ctrl); + if (r < 0) + return log_error_errno(r, "Failed to bind udev control socket: %m"); r = device_monitor_new_full(&manager->monitor, MONITOR_GROUP_KERNEL, fd_uevent); if (r < 0) @@ -1634,6 +1617,18 @@ static int manager_new(Manager **ret, int fd_ctrl, int fd_uevent, const char *cg (void) sd_device_monitor_set_receive_buffer_size(manager->monitor, 128 * 1024 * 1024); + r = device_monitor_enable_receiving(manager->monitor); + if (r < 0) + return log_error_errno(r, "Failed to bind netlink socket: %m"); + + *ret = TAKE_PTR(manager); + + return 0; +} + +static int main_loop(Manager *manager) { + int fd_worker, fd_ctrl, r; + /* unnamed socket from workers to the main daemon */ r = socketpair(AF_LOCAL, SOCK_DGRAM|SOCK_CLOEXEC, 0, manager->worker_watch); if (r < 0) @@ -1679,6 +1674,10 @@ static int manager_new(Manager **ret, int fd_ctrl, int fd_uevent, const char *cg if (r < 0) return log_error_errno(r, "Failed to create watchdog event source: %m"); + fd_ctrl = udev_ctrl_get_fd(manager->ctrl); + if (fd_ctrl < 0) + return log_error_errno(fd_ctrl, "Failed to get udev control socket fd: %m"); + r = sd_event_add_io(manager->event, &manager->ctrl_event, fd_ctrl, EPOLLIN, on_ctrl_msg, manager); if (r < 0) return log_error_errno(r, "Failed to create udev control event source: %m"); @@ -1713,20 +1712,11 @@ static int manager_new(Manager **ret, int fd_ctrl, int fd_uevent, const char *cg if (r < 0) return log_error_errno(r, "Failed to create post event source: %m"); - *ret = TAKE_PTR(manager); - - return 0; -} - -static int main_loop(int fd_ctrl, int fd_uevent, const char *cgroup) { - _cleanup_(manager_freep) Manager *manager = NULL; - int r; + udev_builtin_init(); - r = manager_new(&manager, fd_ctrl, fd_uevent, cgroup); - if (r < 0) { - r = log_error_errno(r, "Failed to allocate manager object: %m"); - goto exit; - } + r = udev_rules_new(&manager->rules, arg_resolve_name_timing); + if (!manager->rules) + return log_error_errno(r, "Failed to read udev rules: %m"); r = udev_rules_apply_static_dev_perms(manager->rules); if (r < 0) @@ -1737,24 +1727,18 @@ static int main_loop(int fd_ctrl, int fd_uevent, const char *cgroup) { "STATUS=Processing with %u children at max", arg_children_max); r = sd_event_loop(manager->event); - if (r < 0) { + if (r < 0) log_error_errno(r, "Event loop failed: %m"); - goto exit; - } - sd_event_get_exit_code(manager->event, &r); - -exit: sd_notify(false, "STOPPING=1\n" "STATUS=Shutting down..."); - if (manager) - udev_ctrl_cleanup(manager->ctrl); return r; } static int run(int argc, char *argv[]) { _cleanup_free_ char *cgroup = NULL; + _cleanup_(manager_freep) Manager *manager = NULL; int fd_ctrl = -1, fd_uevent = -1; int r; @@ -1814,10 +1798,10 @@ static int run(int argc, char *argv[]) { dev_setup(NULL, UID_INVALID, GID_INVALID); - if (getppid() == 1) { - /* get our own cgroup, we regularly kill everything udev has left behind - we only do this on systemd systems, and only if we are directly spawned - by PID1. otherwise we are not guaranteed to have a dedicated cgroup */ + if (getppid() == 1 && sd_booted() > 0) { + /* Get our own cgroup, we regularly kill everything udev has left behind. + * We only do this on systemd systems, and only if we are directly spawned + * by PID1. Otherwise we are not guaranteed to have a dedicated cgroup. */ r = cg_pid_get_path(SYSTEMD_CGROUP_CONTROLLER, 0, &cgroup); if (r < 0) { if (IN_SET(r, -ENOENT, -ENOMEDIUM)) @@ -1831,10 +1815,14 @@ static int run(int argc, char *argv[]) { if (r < 0) return log_error_errno(r, "Failed to listen on fds: %m"); + r = manager_new(&manager, fd_ctrl, fd_uevent, cgroup); + if (r < 0) + return log_error_errno(r, "Failed to create manager: %m"); + if (arg_daemonize) { pid_t pid; - log_info("starting version " PACKAGE_VERSION); + log_info("Starting version " GIT_VERSION); /* connect /dev/null to stdin, stdout, stderr */ if (log_get_max_level() < LOG_DEBUG) { @@ -1858,7 +1846,10 @@ static int run(int argc, char *argv[]) { log_debug_errno(r, "Failed to adjust OOM score, ignoring: %m"); } - return main_loop(fd_ctrl, fd_uevent, cgroup); + r = main_loop(manager); + /* FIXME: move this into manager_free() */ + udev_ctrl_cleanup(manager->ctrl); + return r; } DEFINE_MAIN_FUNCTION(run); |