diff --git a/man/udevadm.xml b/man/udevadm.xml index ec26cc3c07..b731f808bc 100644 --- a/man/udevadm.xml +++ b/man/udevadm.xml @@ -212,6 +212,13 @@ Do not actually trigger the event. + + + + + Suppress error logging in triggering events. + + diff --git a/shell-completion/bash/udevadm b/shell-completion/bash/udevadm index 8b1b962f2d..33d998395e 100644 --- a/shell-completion/bash/udevadm +++ b/shell-completion/bash/udevadm @@ -51,7 +51,7 @@ _udevadm() { [INFO_STANDALONE]='-r --root -a --attribute-walk -x --export -e --export-db -c --cleanup-db -w --wait-for-initialization' [INFO_ARG]='-q --query -p --path -n --name -P --export-prefix -d --device-id-of-file' - [TRIGGER_STANDALONE]='-v --verbose -n --dry-run -w --settle --wait-daemon' + [TRIGGER_STANDALONE]='-v --verbose -n --dry-run -q --quiet -w --settle --wait-daemon' [TRIGGER_ARG]='-t --type -c --action -s --subsystem-match -S --subsystem-nomatch -a --attr-match -A --attr-nomatch -p --property-match -g --tag-match -y --sysname-match --name-match -b --parent-match' diff --git a/shell-completion/zsh/_udevadm b/shell-completion/zsh/_udevadm index ae82d8aa70..5e989b4a1d 100644 --- a/shell-completion/zsh/_udevadm +++ b/shell-completion/zsh/_udevadm @@ -21,6 +21,7 @@ _udevadm_trigger(){ _arguments \ '--verbose[Print the list of devices which will be triggered.]' \ '--dry-run[Do not actually trigger the event.]' \ + '--quiet[Suppress error logging in triggering events.]' \ '--type=[Trigger a specific type of devices.]:types:(devices subsystems failed)' \ '--action=[Type of event to be triggered.]:actions:(add change remove)' \ '--subsystem-match=[Trigger events for devices which belong to a matching subsystem.]' \ diff --git a/src/libsystemd/libsystemd.sym b/src/libsystemd/libsystemd.sym index 78454acbc0..74eff7fcf0 100644 --- a/src/libsystemd/libsystemd.sym +++ b/src/libsystemd/libsystemd.sym @@ -749,4 +749,5 @@ global: sd_device_get_action; sd_device_get_seqnum; sd_device_new_from_stat_rdev; + sd_device_trigger; } LIBSYSTEMD_247; diff --git a/src/libsystemd/sd-device/device-enumerator.c b/src/libsystemd/sd-device/device-enumerator.c index e3c0af3429..c98b029af2 100644 --- a/src/libsystemd/sd-device/device-enumerator.c +++ b/src/libsystemd/sd-device/device-enumerator.c @@ -285,13 +285,11 @@ int device_enumerator_add_device(sd_device_enumerator *enumerator, sd_device *de static bool match_sysattr_value(sd_device *device, const char *sysattr, const char *match_value) { const char *value; - int r; assert(device); assert(sysattr); - r = sd_device_get_sysattr_value(device, sysattr, &value); - if (r < 0) + if (sd_device_get_sysattr_value(device, sysattr, &value) < 0) return false; if (!match_value) diff --git a/src/libsystemd/sd-device/sd-device.c b/src/libsystemd/sd-device/sd-device.c index bf9397c03d..1ef7f4d69c 100644 --- a/src/libsystemd/sd-device/sd-device.c +++ b/src/libsystemd/sd-device/sd-device.c @@ -198,7 +198,7 @@ int device_set_syspath(sd_device *device, const char *_syspath, bool verify) { devpath = syspath + STRLEN("/sys"); - if (devpath[0] == '\0') + if (devpath[0] != '/') /* '/sys' alone is not a valid device path */ return -ENODEV; @@ -519,7 +519,7 @@ int device_read_uevent_file(sd_device *device) { return 0; } if (r == -ENOENT) - /* some devices may not have uevent files, see set_syspath() */ + /* some devices may not have uevent files, see device_set_syspath() */ return 0; if (r < 0) return log_device_debug_errno(device, r, "sd-device: Failed to read uevent file '%s': %m", path); @@ -674,11 +674,11 @@ _public_ int sd_device_new_from_device_id(sd_device **ret, const char *id) { _public_ int sd_device_get_syspath(sd_device *device, const char **ret) { assert_return(device, -EINVAL); - assert_return(ret, -EINVAL); assert(path_startswith(device->syspath, "/sys/")); - *ret = device->syspath; + if (ret) + *ret = device->syspath; return 0; } @@ -720,8 +720,6 @@ static int device_new_from_child(sd_device **ret, sd_device *child) { } _public_ int sd_device_get_parent(sd_device *child, sd_device **ret) { - - assert_return(ret, -EINVAL); assert_return(child, -EINVAL); if (!child->parent_set) { @@ -733,7 +731,8 @@ _public_ int sd_device_get_parent(sd_device *child, sd_device **ret) { if (!child->parent) return -ENOENT; - *ret = child->parent; + if (ret) + *ret = child->parent; return 0; } @@ -779,7 +778,6 @@ _public_ int sd_device_get_subsystem(sd_device *device, const char **ret) { const char *syspath, *drivers = NULL; int r; - assert_return(ret, -EINVAL); assert_return(device, -EINVAL); r = sd_device_get_syspath(device, &syspath); @@ -836,7 +834,8 @@ _public_ int sd_device_get_subsystem(sd_device *device, const char **ret) { if (!device->subsystem) return -ENOENT; - *ret = device->subsystem; + if (ret) + *ret = device->subsystem; return 0; } @@ -868,10 +867,11 @@ _public_ int sd_device_get_parent_with_subsystem_devtype(sd_device *child, const r = sd_device_get_parent(child, &parent); while (r >= 0) { const char *parent_subsystem = NULL; - const char *parent_devtype = NULL; (void) sd_device_get_subsystem(parent, &parent_subsystem); if (streq_ptr(parent_subsystem, subsystem)) { + const char *parent_devtype = NULL; + if (!devtype) break; @@ -885,7 +885,8 @@ _public_ int sd_device_get_parent_with_subsystem_devtype(sd_device *child, const if (r < 0) return r; - *ret = parent; + if (ret) + *ret = parent; return 0; } @@ -928,7 +929,6 @@ int device_set_driver(sd_device *device, const char *_driver) { _public_ int sd_device_get_driver(sd_device *device, const char **ret) { assert_return(device, -EINVAL); - assert_return(ret, -EINVAL); if (!device->driver_set) { _cleanup_free_ char *driver = NULL; @@ -955,18 +955,19 @@ _public_ int sd_device_get_driver(sd_device *device, const char **ret) { if (!device->driver) return -ENOENT; - *ret = device->driver; + if (ret) + *ret = device->driver; return 0; } _public_ int sd_device_get_devpath(sd_device *device, const char **devpath) { assert_return(device, -EINVAL); - assert_return(devpath, -EINVAL); assert(device->devpath); assert(device->devpath[0] == '/'); - *devpath = device->devpath; + if (devpath) + *devpath = device->devpath; return 0; } @@ -974,7 +975,6 @@ _public_ int sd_device_get_devname(sd_device *device, const char **devname) { int r; assert_return(device, -EINVAL); - assert_return(devname, -EINVAL); r = device_read_uevent_file(device); if (r < 0) @@ -985,7 +985,8 @@ _public_ int sd_device_get_devname(sd_device *device, const char **devname) { assert(path_startswith(device->devname, "/dev/")); - *devname = device->devname; + if (devname) + *devname = device->devname; return 0; } @@ -1035,7 +1036,6 @@ _public_ int sd_device_get_sysname(sd_device *device, const char **ret) { int r; assert_return(device, -EINVAL); - assert_return(ret, -EINVAL); if (!device->sysname_set) { r = device_set_sysname(device); @@ -1045,7 +1045,8 @@ _public_ int sd_device_get_sysname(sd_device *device, const char **ret) { assert_return(device->sysname, -ENOENT); - *ret = device->sysname; + if (ret) + *ret = device->sysname; return 0; } @@ -1053,7 +1054,6 @@ _public_ int sd_device_get_sysnum(sd_device *device, const char **ret) { int r; assert_return(device, -EINVAL); - assert_return(ret, -EINVAL); if (!device->sysname_set) { r = device_set_sysname(device); @@ -1064,7 +1064,8 @@ _public_ int sd_device_get_sysnum(sd_device *device, const char **ret) { if (!device->sysnum) return -ENOENT; - *ret = device->sysnum; + if (ret) + *ret = device->sysnum; return 0; } @@ -1434,7 +1435,6 @@ _public_ int sd_device_get_usec_since_initialized(sd_device *device, uint64_t *u int r; assert_return(device, -EINVAL); - assert_return(usec, -EINVAL); r = device_read_db(device); if (r < 0) @@ -1451,7 +1451,8 @@ _public_ int sd_device_get_usec_since_initialized(sd_device *device, uint64_t *u if (now_ts < device->usec_initialized) return -EIO; - *usec = now_ts - device->usec_initialized; + if (usec) + *usec = now_ts - device->usec_initialized; return 0; } @@ -1799,8 +1800,8 @@ _public_ int sd_device_has_current_tag(sd_device *device, const char *tag) { return set_contains(device->current_tags, tag); } -_public_ int sd_device_get_property_value(sd_device *device, const char *key, const char **_value) { - char *value; +_public_ int sd_device_get_property_value(sd_device *device, const char *key, const char **ret_value) { + const char *value; int r; assert_return(device, -EINVAL); @@ -1814,12 +1815,12 @@ _public_ int sd_device_get_property_value(sd_device *device, const char *key, co if (!value) return -ENOENT; - if (_value) - *_value = value; + if (ret_value) + *ret_value = value; return 0; } -static int device_add_sysattr_value(sd_device *device, const char *key, char *value) { +static int device_cache_sysattr_value(sd_device *device, const char *key, char *value) { _cleanup_free_ char *new_key = NULL, *old_value = NULL; int r; @@ -1829,6 +1830,7 @@ static int device_add_sysattr_value(sd_device *device, const char *key, char *va /* This takes the reference of the input value. The input value may be NULL. * This replaces the value if it already exists. */ + /* First, remove the old cache entry. So, we do not need to clear cache on error. */ old_value = hashmap_remove2(device->sysattr_values, key, (void **) &new_key); if (!new_key) { new_key = strdup(key); @@ -1845,7 +1847,7 @@ static int device_add_sysattr_value(sd_device *device, const char *key, char *va return 0; } -static int device_get_sysattr_value(sd_device *device, const char *_key, const char **_value) { +static int device_get_cached_sysattr_value(sd_device *device, const char *_key, const char **_value) { const char *key = NULL, *value; assert(device); @@ -1862,7 +1864,7 @@ static int device_get_sysattr_value(sd_device *device, const char *_key, const c /* We cache all sysattr lookups. If an attribute does not exist, it is stored * with a NULL value in the cache, otherwise the returned string is stored */ -_public_ int sd_device_get_sysattr_value(sd_device *device, const char *sysattr, const char **_value) { +_public_ int sd_device_get_sysattr_value(sd_device *device, const char *sysattr, const char **ret_value) { _cleanup_free_ char *value = NULL; const char *path, *syspath, *cached_value = NULL; struct stat statbuf; @@ -1872,7 +1874,7 @@ _public_ int sd_device_get_sysattr_value(sd_device *device, const char *sysattr, assert_return(sysattr, -EINVAL); /* look for possibly already cached result */ - r = device_get_sysattr_value(device, sysattr, &cached_value); + r = device_get_cached_sysattr_value(device, sysattr, &cached_value); if (r != -ENOENT) { if (r < 0) return r; @@ -1881,8 +1883,8 @@ _public_ int sd_device_get_sysattr_value(sd_device *device, const char *sysattr, /* we looked up the sysattr before and it did not exist */ return -ENOENT; - if (_value) - *_value = cached_value; + if (ret_value) + *ret_value = cached_value; return 0; } @@ -1894,12 +1896,16 @@ _public_ int sd_device_get_sysattr_value(sd_device *device, const char *sysattr, path = prefix_roota(syspath, sysattr); r = lstat(path, &statbuf); if (r < 0) { - /* remember that we could not access the sysattr */ - r = device_add_sysattr_value(device, sysattr, NULL); - if (r < 0) - return r; + int k; - return -ENOENT; + /* remember that we could not access the sysattr */ + k = device_cache_sysattr_value(device, sysattr, NULL); + if (k < 0) + log_device_debug_errno(device, k, + "sd-device: failed to cache attribute '%s' with NULL, ignoring: %m", + sysattr); + + return r; } else if (S_ISLNK(statbuf.st_mode)) { /* Some core links return only the last element of the target path, * these are just values, the paths should not be exposed. */ @@ -1909,35 +1915,38 @@ _public_ int sd_device_get_sysattr_value(sd_device *device, const char *sysattr, return r; } else return -EINVAL; - } else if (S_ISDIR(statbuf.st_mode)) { + } else if (S_ISDIR(statbuf.st_mode)) /* skip directories */ - return -EINVAL; - } else if (!(statbuf.st_mode & S_IRUSR)) { + return -EISDIR; + else if (!(statbuf.st_mode & S_IRUSR)) /* skip non-readable files */ return -EPERM; - } else { - size_t size; - + else { /* read attribute value */ - r = read_full_virtual_file(path, &value, &size); + r = read_full_virtual_file(path, &value, NULL); if (r < 0) return r; /* drop trailing newlines */ - while (size > 0 && value[--size] == '\n') - value[size] = '\0'; + delete_trailing_chars(value, "\n"); } - r = device_add_sysattr_value(device, sysattr, value); - if (r < 0) - return r; - - *_value = TAKE_PTR(value); + /* Unfortunately, we need to return 'const char*' instead of 'char*'. Hence, failure in caching + * sysattr value is critical unlike the other places. */ + r = device_cache_sysattr_value(device, sysattr, value); + if (r < 0) { + log_device_debug_errno(device, r, + "sd-device: failed to cache attribute '%s' with '%s'%s: %m", + sysattr, value, ret_value ? "" : ", ignoring"); + if (ret_value) + return r; + } else if (ret_value) + *ret_value = TAKE_PTR(value); return 0; } -static void device_remove_sysattr_value(sd_device *device, const char *_key) { +static void device_remove_cached_sysattr_value(sd_device *device, const char *_key) { _cleanup_free_ char *key = NULL; assert(device); @@ -1946,8 +1955,6 @@ static void device_remove_sysattr_value(sd_device *device, const char *_key) { free(hashmap_remove2(device->sysattr_values, _key, (void **) &key)); } -/* set the attribute and save it in the cache. If a NULL value is passed the - * attribute is cleared from the cache */ _public_ int sd_device_set_sysattr_value(sd_device *device, const char *sysattr, const char *_value) { _cleanup_free_ char *value = NULL; const char *syspath, *path; @@ -1957,8 +1964,11 @@ _public_ int sd_device_set_sysattr_value(sd_device *device, const char *sysattr, assert_return(device, -EINVAL); assert_return(sysattr, -EINVAL); + /* Set the attribute and save it in the cache. */ + if (!_value) { - device_remove_sysattr_value(device, sysattr); + /* If input value is NULL, then clear cache and not write anything. */ + device_remove_cached_sysattr_value(device, sysattr); return 0; } @@ -1971,7 +1981,7 @@ _public_ int sd_device_set_sysattr_value(sd_device *device, const char *sysattr, len = strlen(_value); /* drop trailing newlines */ - while (len > 0 && _value[len - 1] == '\n') + while (len > 0 && strchr(NEWLINE, _value[len - 1])) len --; /* value length is limited to 4k */ @@ -1984,27 +1994,22 @@ _public_ int sd_device_set_sysattr_value(sd_device *device, const char *sysattr, r = write_string_file(path, value, WRITE_STRING_FILE_DISABLE_BUFFER | WRITE_STRING_FILE_NOFOLLOW); if (r < 0) { - if (r == -ELOOP) - return -EINVAL; - if (r == -EISDIR) - return r; - - r = free_and_strdup(&value, ""); - if (r < 0) - return r; - - r = device_add_sysattr_value(device, sysattr, value); - if (r < 0) - return r; - TAKE_PTR(value); - - return -ENXIO; + /* On failure, clear cache entry, as we do not know how it fails. */ + device_remove_cached_sysattr_value(device, sysattr); + return r; } - r = device_add_sysattr_value(device, sysattr, value); + /* Do not cache action string written into uevent file. */ + if (streq(sysattr, "uevent")) + return 0; + + r = device_cache_sysattr_value(device, sysattr, value); if (r < 0) - return r; - TAKE_PTR(value); + log_device_debug_errno(device, r, + "sd-device: failed to cache attribute '%s' with '%s', ignoring: %m", + sysattr, value); + else + TAKE_PTR(value); return 0; } @@ -2018,7 +2023,7 @@ _public_ int sd_device_set_sysattr_valuef(sd_device *device, const char *sysattr assert_return(sysattr, -EINVAL); if (!format) { - device_remove_sysattr_value(device, sysattr); + device_remove_cached_sysattr_value(device, sysattr); return 0; } @@ -2031,3 +2036,15 @@ _public_ int sd_device_set_sysattr_valuef(sd_device *device, const char *sysattr return sd_device_set_sysattr_value(device, sysattr, value); } + +_public_ int sd_device_trigger(sd_device *device, sd_device_action_t action) { + const char *s; + + assert_return(device, -EINVAL); + + s = device_action_to_string(action); + if (!s) + return -EINVAL; + + return sd_device_set_sysattr_value(device, "uevent", s); +} diff --git a/src/libsystemd/sd-device/test-sd-device.c b/src/libsystemd/sd-device/test-sd-device.c index fd30d1a1d0..aaa16f740d 100644 --- a/src/libsystemd/sd-device/test-sd-device.c +++ b/src/libsystemd/sd-device/test-sd-device.c @@ -4,6 +4,7 @@ #include "device-internal.h" #include "device-private.h" #include "device-util.h" +#include "errno-util.h" #include "hashmap.h" #include "nulstr-util.h" #include "string-util.h" @@ -51,7 +52,7 @@ static void test_sd_device_one(sd_device *d) { } r = sd_device_get_sysattr_value(d, "name_assign_type", &val); - assert_se(r >= 0 || IN_SET(r, -ENOENT, -EINVAL)); + assert_se(r >= 0 || ERRNO_IS_PRIVILEGE(r) || IN_SET(r, -ENOENT, -EINVAL)); r = sd_device_get_property_value(d, "ID_NET_DRIVER", &val); assert_se(r >= 0 || r == -ENOENT); diff --git a/src/mount/mount-tool.c b/src/mount/mount-tool.c index c1be0e0afb..153f67f93b 100644 --- a/src/mount/mount-tool.c +++ b/src/mount/mount-tool.c @@ -1197,7 +1197,7 @@ static int acquire_removable(sd_device *d) { return 0; for (;;) { - if (sd_device_get_sysattr_value(d, "removable", &v) > 0) + if (sd_device_get_sysattr_value(d, "removable", &v) >= 0) break; if (sd_device_get_parent(d, &d) < 0) diff --git a/src/shared/dissect-image.c b/src/shared/dissect-image.c index 6d24c3fd9f..8de1738264 100644 --- a/src/shared/dissect-image.c +++ b/src/shared/dissect-image.c @@ -150,7 +150,8 @@ static int device_is_partition(sd_device *d, blkid_partition pp) { return false; r = sd_device_get_sysattr_value(d, "partition", &v); - if (r == -ENOENT) /* Not a partition device */ + if (r == -ENOENT || /* Not a partition device */ + ERRNO_IS_PRIVILEGE(r)) /* Not ready to access? */ return false; if (r < 0) return r; diff --git a/src/shared/udev-util.c b/src/shared/udev-util.c index 3a3f0198fd..80b70c18a0 100644 --- a/src/shared/udev-util.c +++ b/src/shared/udev-util.c @@ -10,6 +10,7 @@ #include "device-private.h" #include "device-util.h" #include "env-file.h" +#include "errno-util.h" #include "escape.h" #include "fd-util.h" #include "log.h" @@ -525,12 +526,12 @@ int udev_resolve_subsys_kernel(const char *string, char *result, size_t maxsize, if (read_value) { r = sd_device_get_sysattr_value(dev, attr, &val); - if (r < 0 && r != -ENOENT) + if (r < 0 && !ERRNO_IS_PRIVILEGE(r) && r != -ENOENT) return r; - if (r == -ENOENT) - result[0] = '\0'; - else + if (r >= 0) strscpy(result, maxsize, val); + else + result[0] = '\0'; log_debug("value '[%s/%s]%s' is '%s'", subsys, sysname, attr, result); } else { r = sd_device_get_syspath(dev, &val); diff --git a/src/systemd/sd-device.h b/src/systemd/sd-device.h index af0e26e2d7..310fcaa278 100644 --- a/src/systemd/sd-device.h +++ b/src/systemd/sd-device.h @@ -99,6 +99,7 @@ int sd_device_get_sysattr_value(sd_device *device, const char *sysattr, const ch int sd_device_set_sysattr_value(sd_device *device, const char *sysattr, const char *value); int sd_device_set_sysattr_valuef(sd_device *device, const char *sysattr, const char *format, ...) _sd_printf_(3, 4); +int sd_device_trigger(sd_device *device, sd_device_action_t action); /* device enumerator */ diff --git a/src/test/test-path-util.c b/src/test/test-path-util.c index 58b185494d..59308473c1 100644 --- a/src/test/test-path-util.c +++ b/src/test/test-path-util.c @@ -481,6 +481,9 @@ static void test_path_startswith(void) { assert_se(!path_startswith("/foo/bar/barfoo/", "")); assert_se(!path_startswith("/foo/bar/barfoo/", "/bar/foo")); assert_se(!path_startswith("/foo/bar/barfoo/", "/f/b/b/")); + assert_se(!path_startswith("/foo/bar/barfoo/", "/foo/bar/barfo")); + assert_se(!path_startswith("/foo/bar/barfoo/", "/foo/bar/bar")); + assert_se(!path_startswith("/foo/bar/barfoo/", "/fo")); } static void test_prefix_root_one(const char *r, const char *p, const char *expected) { diff --git a/src/udev/udevadm-trigger.c b/src/udev/udevadm-trigger.c index 2d16f34d86..ade92286d4 100644 --- a/src/udev/udevadm-trigger.c +++ b/src/udev/udevadm-trigger.c @@ -8,6 +8,7 @@ #include "device-enumerator-private.h" #include "device-private.h" +#include "device-util.h" #include "fd-util.h" #include "fileio.h" #include "path-util.h" @@ -22,36 +23,63 @@ static bool arg_verbose = false; static bool arg_dry_run = false; +static bool arg_quiet = false; -static int exec_list(sd_device_enumerator *e, const char *action, Set **settle_set) { +static int exec_list(sd_device_enumerator *e, sd_device_action_t action, Set **settle_set) { + const char *action_str; sd_device *d; int r, ret = 0; + action_str = device_action_to_string(action); + FOREACH_DEVICE_AND_SUBSYSTEM(e, d) { - _cleanup_free_ char *filename = NULL; const char *syspath; if (sd_device_get_syspath(d, &syspath) < 0) continue; if (arg_verbose) - printf("%s\n", syspath); + printf("%s\n", strna(syspath)); + if (arg_dry_run) continue; - filename = path_join(syspath, "uevent"); - if (!filename) - return log_oom(); - - r = write_string_file(filename, action, WRITE_STRING_FILE_DISABLE_BUFFER); + r = sd_device_trigger(d, action); if (r < 0) { - bool ignore = IN_SET(r, -ENOENT, -ENODEV); + /* ENOENT may be returned when a device does not have /uevent or is already + * removed. Hence, this is logged at debug level and ignored. + * + * ENODEV may be returned by some buggy device drivers e.g. /sys/devices/vio. + * See, + * https://github.com/systemd/systemd/issues/13652#issuecomment-535129791 and + * https://bugs.launchpad.net/ubuntu/+source/linux/+bug/1845319. + * So, this error is ignored, but logged at warning level to encourage people to + * fix the driver. + * + * EROFS is returned when /sys is read only. In that case, all subsequent + * writes will also fail, hence return immediately. + * + * EACCES or EPERM may be returned when this is invoked by non-priviledged user. + * We do NOT return immediately, but continue operation and propagate the error. + * Why? Some device can be owned by a user, e.g., network devices configured in + * a network namespace. See, https://github.com/systemd/systemd/pull/18559 and + * https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=ebb4a4bf76f164457184a3f43ebc1552416bc823 + * + * All other errors are logged at error level, but let's continue the operation, + * and propagate the error. + */ - log_full_errno(ignore ? LOG_DEBUG : LOG_ERR, r, - "Failed to write '%s' to '%s'%s: %m", - action, filename, ignore ? ", ignoring" : ""); - if (IN_SET(r, -EACCES, -EROFS)) - /* Inovoked by unprivileged user, or read only filesystem. Return earlier. */ + bool ignore = IN_SET(r, -ENOENT, -ENODEV); + int level = + arg_quiet ? LOG_DEBUG : + r == -ENOENT ? LOG_DEBUG : + r == -ENODEV ? LOG_WARNING : LOG_ERR; + + log_device_full_errno(d, level, r, + "Failed to write '%s' to '%s/uevent'%s: %m", + action_str, syspath, ignore ? ", ignoring" : ""); + + if (r == -EROFS) return r; if (ret == 0 && !ignore) ret = r; @@ -118,6 +146,7 @@ static int help(void) { " -V --version Show package version\n" " -v --verbose Print the list of devices while running\n" " -n --dry-run Do not actually trigger the events\n" + " -q --quiet Suppress error logging in triggering events\n" " -t --type= Type of events to trigger\n" " devices sysfs devices (default)\n" " subsystems sysfs subsystems and drivers\n" @@ -148,6 +177,7 @@ int trigger_main(int argc, char *argv[], void *userdata) { static const struct option options[] = { { "verbose", no_argument, NULL, 'v' }, { "dry-run", no_argument, NULL, 'n' }, + { "quiet", no_argument, NULL, 'q' }, { "type", required_argument, NULL, 't' }, { "action", required_argument, NULL, 'c' }, { "subsystem-match", required_argument, NULL, 's' }, @@ -169,7 +199,7 @@ int trigger_main(int argc, char *argv[], void *userdata) { TYPE_DEVICES, TYPE_SUBSYSTEMS, } device_type = TYPE_DEVICES; - const char *action = "change"; + sd_device_action_t action = SD_DEVICE_CHANGE; _cleanup_(sd_device_enumerator_unrefp) sd_device_enumerator *e = NULL; _cleanup_(sd_device_monitor_unrefp) sd_device_monitor *m = NULL; _cleanup_(sd_event_unrefp) sd_event *event = NULL; @@ -191,7 +221,7 @@ int trigger_main(int argc, char *argv[], void *userdata) { if (r < 0) return r; - while ((c = getopt_long(argc, argv, "vnt:c:s:S:a:A:p:g:y:b:wVh", options, NULL)) >= 0) { + while ((c = getopt_long(argc, argv, "vnqt:c:s:S:a:A:p:g:y:b:wVh", options, NULL)) >= 0) { _cleanup_free_ char *buf = NULL; const char *key, *val; @@ -202,6 +232,9 @@ int trigger_main(int argc, char *argv[], void *userdata) { case 'n': arg_dry_run = true; break; + case 'q': + arg_quiet = true; + break; case 't': if (streq(optarg, "devices")) device_type = TYPE_DEVICES; @@ -211,18 +244,14 @@ int trigger_main(int argc, char *argv[], void *userdata) { return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Unknown type --type=%s", optarg); break; case 'c': { - sd_device_action_t a; - if (streq(optarg, "help")) { dump_device_action_table(); return 0; } - a = device_action_from_string(optarg); - if (a < 0) - return log_error_errno(a, "Unknown action '%s'", optarg); - - action = device_action_to_string(a); + action = device_action_from_string(optarg); + if (action < 0) + return log_error_errno(action, "Unknown action '%s'", optarg); break; } case 's': diff --git a/src/udev/udevd.c b/src/udev/udevd.c index 0657bf1b6d..6fffd8407b 100644 --- a/src/udev/udevd.c +++ b/src/udev/udevd.c @@ -1155,56 +1155,54 @@ static int on_ctrl_msg(struct udev_ctrl *uctrl, enum udev_ctrl_msg_type type, co return 1; } -static int synthesize_change_one(sd_device *dev, const char *syspath) { - const char *filename; +static int synthesize_change_one(sd_device *dev, sd_device *target) { int r; - filename = strjoina(syspath, "/uevent"); - log_device_debug(dev, "device is closed, synthesising 'change' on %s", syspath); - r = write_string_file(filename, "change", WRITE_STRING_FILE_DISABLE_BUFFER); + if (DEBUG_LOGGING) { + const char *syspath = NULL; + (void) sd_device_get_syspath(target, &syspath); + log_device_debug(dev, "device is closed, synthesising 'change' on %s", strna(syspath)); + } + + r = sd_device_trigger(target, SD_DEVICE_CHANGE); if (r < 0) - return log_device_debug_errno(dev, r, "Failed to write 'change' to %s: %m", filename); + return log_device_debug_errno(target, r, "Failed to trigger 'change' uevent: %m"); + return 0; } static int synthesize_change(sd_device *dev) { - const char *subsystem, *sysname, *devname, *syspath, *devtype; + const char *subsystem, *sysname, *devtype; int r; r = sd_device_get_subsystem(dev, &subsystem); if (r < 0) return r; - r = sd_device_get_sysname(dev, &sysname); - if (r < 0) - return r; - - r = sd_device_get_devname(dev, &devname); - if (r < 0) - return r; - - r = sd_device_get_syspath(dev, &syspath); - if (r < 0) - return r; - r = sd_device_get_devtype(dev, &devtype); if (r < 0) return r; - if (streq_ptr("block", subsystem) && - streq_ptr("disk", devtype) && + r = sd_device_get_sysname(dev, &sysname); + if (r < 0) + return r; + + if (streq_ptr(subsystem, "block") && + streq_ptr(devtype, "disk") && !startswith(sysname, "dm-")) { _cleanup_(sd_device_enumerator_unrefp) sd_device_enumerator *e = NULL; bool part_table_read = false, has_partitions = false; + const char *devname; sd_device *d; int fd; - /* - * Try to re-read the partition table. This only succeeds if - * none of the devices is busy. The kernel returns 0 if no - * partition table is found, and we will not get an event for - * the disk. - */ + r = sd_device_get_devname(dev, &devname); + if (r < 0) + return r; + + /* Try to re-read the partition table. This only succeeds if none of the devices is + * busy. The kernel returns 0 if no partition table is found, and we will not get an + * event for the disk. */ fd = open(devname, O_RDONLY|O_CLOEXEC|O_NOFOLLOW|O_NONBLOCK); if (fd >= 0) { r = flock(fd, LOCK_EX|LOCK_NB); @@ -1236,44 +1234,33 @@ static int synthesize_change(sd_device *dev) { FOREACH_DEVICE(e, d) { const char *t; - if (sd_device_get_devtype(d, &t) < 0 || - !streq("partition", t)) + if (sd_device_get_devtype(d, &t) < 0 || !streq(t, "partition")) continue; has_partitions = true; break; } - /* - * We have partitions and re-read the table, the kernel already sent - * out a "change" event for the disk, and "remove/add" for all - * partitions. - */ + /* We have partitions and re-read the table, the kernel already sent out a "change" + * event for the disk, and "remove/add" for all partitions. */ if (part_table_read && has_partitions) return 0; - /* - * We have partitions but re-reading the partition table did not - * work, synthesize "change" for the disk and all partitions. - */ - (void) synthesize_change_one(dev, syspath); + /* We have partitions but re-reading the partition table did not work, synthesize + * "change" for the disk and all partitions. */ + (void) synthesize_change_one(dev, dev); FOREACH_DEVICE(e, d) { - const char *t, *n, *s; + const char *t; - if (sd_device_get_devtype(d, &t) < 0 || - !streq("partition", t)) + if (sd_device_get_devtype(d, &t) < 0 || !streq(t, "partition")) continue; - if (sd_device_get_devname(d, &n) < 0 || - sd_device_get_syspath(d, &s) < 0) - continue; - - (void) synthesize_change_one(dev, s); + (void) synthesize_change_one(dev, d); } } else - (void) synthesize_change_one(dev, syspath); + (void) synthesize_change_one(dev, dev); return 0; } diff --git a/units/systemd-udev-trigger.service b/units/systemd-udev-trigger.service index 8b2d88e185..3d0f7b4f20 100644 --- a/units/systemd-udev-trigger.service +++ b/units/systemd-udev-trigger.service @@ -19,5 +19,5 @@ ConditionPathIsReadWrite=/sys [Service] Type=oneshot RemainAfterExit=yes -ExecStart=udevadm trigger --type=subsystems --action=add -ExecStart=udevadm trigger --type=devices --action=add +ExecStart=-udevadm trigger --type=subsystems --action=add +ExecStart=-udevadm trigger --type=devices --action=add