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:
commit
b332778b30
@ -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>
|
||||
|
@ -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'
|
||||
|
@ -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.]' \
|
||||
|
@ -749,4 +749,5 @@ global:
|
||||
sd_device_get_action;
|
||||
sd_device_get_seqnum;
|
||||
sd_device_new_from_stat_rdev;
|
||||
sd_device_trigger;
|
||||
} LIBSYSTEMD_247;
|
||||
|
@ -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)
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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)
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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 */
|
||||
|
||||
|
@ -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) {
|
||||
|
@ -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':
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user