1
0
mirror of https://github.com/systemd/systemd.git synced 2024-10-30 14:55:37 +03:00

Merge pull request #18684 from yuwata/sd-device-cleanups-and-udevadm-fix

sd-device, udev: several cleanups and one udevadm fix
This commit is contained in:
Zbigniew Jędrzejewski-Szmek 2021-02-22 11:32:38 +01:00 committed by GitHub
commit b332778b30
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 207 additions and 160 deletions

View File

@ -212,6 +212,13 @@
<para>Do not actually trigger the event.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><option>-q</option></term>
<term><option>--quiet</option></term>
<listitem>
<para>Suppress error logging in triggering events.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><option>-t</option></term>
<term><option>--type=<replaceable>TYPE</replaceable></option></term>

View File

@ -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'

View File

@ -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.]' \

View File

@ -749,4 +749,5 @@ global:
sd_device_get_action;
sd_device_get_seqnum;
sd_device_new_from_stat_rdev;
sd_device_trigger;
} LIBSYSTEMD_247;

View File

@ -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)

View File

@ -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);
}

View File

@ -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);

View File

@ -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)

View File

@ -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;

View File

@ -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);

View File

@ -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 */

View File

@ -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) {

View File

@ -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':

View File

@ -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;
}

View File

@ -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