1
0
mirror of https://github.com/systemd/systemd synced 2025-10-02 02:04:45 +02:00

Compare commits

..

No commits in common. "b332778b30d23193c792d5f5c5dcccd61f4a489c" and "a1f782e44c363ee1c2e8fd0cdd54ea523d72807c" have entirely different histories.

16 changed files with 158 additions and 206 deletions

View File

@ -275,7 +275,6 @@ mouse:usb:v04b3p3107:name:*
# Kensington Expert Mouse trackball # Kensington Expert Mouse trackball
mouse:usb:v047dp1020:*Kensington Expert Mouse*:* mouse:usb:v047dp1020:*Kensington Expert Mouse*:*
ID_INPUT_TRACKBALL=1 ID_INPUT_TRACKBALL=1
MOUSE_DPI=400@125
########################################## ##########################################
# Lenovo # Lenovo

View File

@ -212,13 +212,6 @@
<para>Do not actually trigger the event.</para> <para>Do not actually trigger the event.</para>
</listitem> </listitem>
</varlistentry> </varlistentry>
<varlistentry>
<term><option>-q</option></term>
<term><option>--quiet</option></term>
<listitem>
<para>Suppress error logging in triggering events.</para>
</listitem>
</varlistentry>
<varlistentry> <varlistentry>
<term><option>-t</option></term> <term><option>-t</option></term>
<term><option>--type=<replaceable>TYPE</replaceable></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 [INFO_STANDALONE]='-r --root -a --attribute-walk -x --export -e --export-db -c --cleanup-db
-w --wait-for-initialization' -w --wait-for-initialization'
[INFO_ARG]='-q --query -p --path -n --name -P --export-prefix -d --device-id-of-file' [INFO_ARG]='-q --query -p --path -n --name -P --export-prefix -d --device-id-of-file'
[TRIGGER_STANDALONE]='-v --verbose -n --dry-run -q --quiet -w --settle --wait-daemon' [TRIGGER_STANDALONE]='-v --verbose -n --dry-run -w --settle --wait-daemon'
[TRIGGER_ARG]='-t --type -c --action -s --subsystem-match -S --subsystem-nomatch [TRIGGER_ARG]='-t --type -c --action -s --subsystem-match -S --subsystem-nomatch
-a --attr-match -A --attr-nomatch -p --property-match -a --attr-match -A --attr-nomatch -p --property-match
-g --tag-match -y --sysname-match --name-match -b --parent-match' -g --tag-match -y --sysname-match --name-match -b --parent-match'

View File

@ -21,7 +21,6 @@ _udevadm_trigger(){
_arguments \ _arguments \
'--verbose[Print the list of devices which will be triggered.]' \ '--verbose[Print the list of devices which will be triggered.]' \
'--dry-run[Do not actually trigger the event.]' \ '--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)' \ '--type=[Trigger a specific type of devices.]:types:(devices subsystems failed)' \
'--action=[Type of event to be triggered.]:actions:(add change remove)' \ '--action=[Type of event to be triggered.]:actions:(add change remove)' \
'--subsystem-match=[Trigger events for devices which belong to a matching subsystem.]' \ '--subsystem-match=[Trigger events for devices which belong to a matching subsystem.]' \

View File

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

View File

@ -285,11 +285,13 @@ 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) { static bool match_sysattr_value(sd_device *device, const char *sysattr, const char *match_value) {
const char *value; const char *value;
int r;
assert(device); assert(device);
assert(sysattr); assert(sysattr);
if (sd_device_get_sysattr_value(device, sysattr, &value) < 0) r = sd_device_get_sysattr_value(device, sysattr, &value);
if (r < 0)
return false; return false;
if (!match_value) 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"); devpath = syspath + STRLEN("/sys");
if (devpath[0] != '/') if (devpath[0] == '\0')
/* '/sys' alone is not a valid device path */ /* '/sys' alone is not a valid device path */
return -ENODEV; return -ENODEV;
@ -519,7 +519,7 @@ int device_read_uevent_file(sd_device *device) {
return 0; return 0;
} }
if (r == -ENOENT) if (r == -ENOENT)
/* some devices may not have uevent files, see device_set_syspath() */ /* some devices may not have uevent files, see set_syspath() */
return 0; return 0;
if (r < 0) if (r < 0)
return log_device_debug_errno(device, r, "sd-device: Failed to read uevent file '%s': %m", path); return log_device_debug_errno(device, r, "sd-device: Failed to read uevent file '%s': %m", path);
@ -674,10 +674,10 @@ _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) { _public_ int sd_device_get_syspath(sd_device *device, const char **ret) {
assert_return(device, -EINVAL); assert_return(device, -EINVAL);
assert_return(ret, -EINVAL);
assert(path_startswith(device->syspath, "/sys/")); assert(path_startswith(device->syspath, "/sys/"));
if (ret)
*ret = device->syspath; *ret = device->syspath;
return 0; return 0;
@ -720,6 +720,8 @@ static int device_new_from_child(sd_device **ret, sd_device *child) {
} }
_public_ int sd_device_get_parent(sd_device *child, sd_device **ret) { _public_ int sd_device_get_parent(sd_device *child, sd_device **ret) {
assert_return(ret, -EINVAL);
assert_return(child, -EINVAL); assert_return(child, -EINVAL);
if (!child->parent_set) { if (!child->parent_set) {
@ -731,7 +733,6 @@ _public_ int sd_device_get_parent(sd_device *child, sd_device **ret) {
if (!child->parent) if (!child->parent)
return -ENOENT; return -ENOENT;
if (ret)
*ret = child->parent; *ret = child->parent;
return 0; return 0;
} }
@ -778,6 +779,7 @@ _public_ int sd_device_get_subsystem(sd_device *device, const char **ret) {
const char *syspath, *drivers = NULL; const char *syspath, *drivers = NULL;
int r; int r;
assert_return(ret, -EINVAL);
assert_return(device, -EINVAL); assert_return(device, -EINVAL);
r = sd_device_get_syspath(device, &syspath); r = sd_device_get_syspath(device, &syspath);
@ -834,7 +836,6 @@ _public_ int sd_device_get_subsystem(sd_device *device, const char **ret) {
if (!device->subsystem) if (!device->subsystem)
return -ENOENT; return -ENOENT;
if (ret)
*ret = device->subsystem; *ret = device->subsystem;
return 0; return 0;
} }
@ -867,11 +868,10 @@ _public_ int sd_device_get_parent_with_subsystem_devtype(sd_device *child, const
r = sd_device_get_parent(child, &parent); r = sd_device_get_parent(child, &parent);
while (r >= 0) { while (r >= 0) {
const char *parent_subsystem = NULL; const char *parent_subsystem = NULL;
const char *parent_devtype = NULL;
(void) sd_device_get_subsystem(parent, &parent_subsystem); (void) sd_device_get_subsystem(parent, &parent_subsystem);
if (streq_ptr(parent_subsystem, subsystem)) { if (streq_ptr(parent_subsystem, subsystem)) {
const char *parent_devtype = NULL;
if (!devtype) if (!devtype)
break; break;
@ -885,7 +885,6 @@ _public_ int sd_device_get_parent_with_subsystem_devtype(sd_device *child, const
if (r < 0) if (r < 0)
return r; return r;
if (ret)
*ret = parent; *ret = parent;
return 0; return 0;
} }
@ -929,6 +928,7 @@ int device_set_driver(sd_device *device, const char *_driver) {
_public_ int sd_device_get_driver(sd_device *device, const char **ret) { _public_ int sd_device_get_driver(sd_device *device, const char **ret) {
assert_return(device, -EINVAL); assert_return(device, -EINVAL);
assert_return(ret, -EINVAL);
if (!device->driver_set) { if (!device->driver_set) {
_cleanup_free_ char *driver = NULL; _cleanup_free_ char *driver = NULL;
@ -955,18 +955,17 @@ _public_ int sd_device_get_driver(sd_device *device, const char **ret) {
if (!device->driver) if (!device->driver)
return -ENOENT; return -ENOENT;
if (ret)
*ret = device->driver; *ret = device->driver;
return 0; return 0;
} }
_public_ int sd_device_get_devpath(sd_device *device, const char **devpath) { _public_ int sd_device_get_devpath(sd_device *device, const char **devpath) {
assert_return(device, -EINVAL); assert_return(device, -EINVAL);
assert_return(devpath, -EINVAL);
assert(device->devpath); assert(device->devpath);
assert(device->devpath[0] == '/'); assert(device->devpath[0] == '/');
if (devpath)
*devpath = device->devpath; *devpath = device->devpath;
return 0; return 0;
} }
@ -975,6 +974,7 @@ _public_ int sd_device_get_devname(sd_device *device, const char **devname) {
int r; int r;
assert_return(device, -EINVAL); assert_return(device, -EINVAL);
assert_return(devname, -EINVAL);
r = device_read_uevent_file(device); r = device_read_uevent_file(device);
if (r < 0) if (r < 0)
@ -985,7 +985,6 @@ _public_ int sd_device_get_devname(sd_device *device, const char **devname) {
assert(path_startswith(device->devname, "/dev/")); assert(path_startswith(device->devname, "/dev/"));
if (devname)
*devname = device->devname; *devname = device->devname;
return 0; return 0;
} }
@ -1036,6 +1035,7 @@ _public_ int sd_device_get_sysname(sd_device *device, const char **ret) {
int r; int r;
assert_return(device, -EINVAL); assert_return(device, -EINVAL);
assert_return(ret, -EINVAL);
if (!device->sysname_set) { if (!device->sysname_set) {
r = device_set_sysname(device); r = device_set_sysname(device);
@ -1045,7 +1045,6 @@ _public_ int sd_device_get_sysname(sd_device *device, const char **ret) {
assert_return(device->sysname, -ENOENT); assert_return(device->sysname, -ENOENT);
if (ret)
*ret = device->sysname; *ret = device->sysname;
return 0; return 0;
} }
@ -1054,6 +1053,7 @@ _public_ int sd_device_get_sysnum(sd_device *device, const char **ret) {
int r; int r;
assert_return(device, -EINVAL); assert_return(device, -EINVAL);
assert_return(ret, -EINVAL);
if (!device->sysname_set) { if (!device->sysname_set) {
r = device_set_sysname(device); r = device_set_sysname(device);
@ -1064,7 +1064,6 @@ _public_ int sd_device_get_sysnum(sd_device *device, const char **ret) {
if (!device->sysnum) if (!device->sysnum)
return -ENOENT; return -ENOENT;
if (ret)
*ret = device->sysnum; *ret = device->sysnum;
return 0; return 0;
} }
@ -1435,6 +1434,7 @@ _public_ int sd_device_get_usec_since_initialized(sd_device *device, uint64_t *u
int r; int r;
assert_return(device, -EINVAL); assert_return(device, -EINVAL);
assert_return(usec, -EINVAL);
r = device_read_db(device); r = device_read_db(device);
if (r < 0) if (r < 0)
@ -1451,7 +1451,6 @@ _public_ int sd_device_get_usec_since_initialized(sd_device *device, uint64_t *u
if (now_ts < device->usec_initialized) if (now_ts < device->usec_initialized)
return -EIO; return -EIO;
if (usec)
*usec = now_ts - device->usec_initialized; *usec = now_ts - device->usec_initialized;
return 0; return 0;
} }
@ -1800,8 +1799,8 @@ _public_ int sd_device_has_current_tag(sd_device *device, const char *tag) {
return set_contains(device->current_tags, tag); return set_contains(device->current_tags, tag);
} }
_public_ int sd_device_get_property_value(sd_device *device, const char *key, const char **ret_value) { _public_ int sd_device_get_property_value(sd_device *device, const char *key, const char **_value) {
const char *value; char *value;
int r; int r;
assert_return(device, -EINVAL); assert_return(device, -EINVAL);
@ -1815,12 +1814,12 @@ _public_ int sd_device_get_property_value(sd_device *device, const char *key, co
if (!value) if (!value)
return -ENOENT; return -ENOENT;
if (ret_value) if (_value)
*ret_value = value; *_value = value;
return 0; return 0;
} }
static int device_cache_sysattr_value(sd_device *device, const char *key, char *value) { static int device_add_sysattr_value(sd_device *device, const char *key, char *value) {
_cleanup_free_ char *new_key = NULL, *old_value = NULL; _cleanup_free_ char *new_key = NULL, *old_value = NULL;
int r; int r;
@ -1830,7 +1829,6 @@ static int device_cache_sysattr_value(sd_device *device, const char *key, char *
/* This takes the reference of the input value. The input value may be NULL. /* This takes the reference of the input value. The input value may be NULL.
* This replaces the value if it already exists. */ * 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); old_value = hashmap_remove2(device->sysattr_values, key, (void **) &new_key);
if (!new_key) { if (!new_key) {
new_key = strdup(key); new_key = strdup(key);
@ -1847,7 +1845,7 @@ static int device_cache_sysattr_value(sd_device *device, const char *key, char *
return 0; return 0;
} }
static int device_get_cached_sysattr_value(sd_device *device, const char *_key, const char **_value) { static int device_get_sysattr_value(sd_device *device, const char *_key, const char **_value) {
const char *key = NULL, *value; const char *key = NULL, *value;
assert(device); assert(device);
@ -1864,7 +1862,7 @@ static int device_get_cached_sysattr_value(sd_device *device, const char *_key,
/* We cache all sysattr lookups. If an attribute does not exist, it is stored /* 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 */ * 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 **ret_value) { _public_ int sd_device_get_sysattr_value(sd_device *device, const char *sysattr, const char **_value) {
_cleanup_free_ char *value = NULL; _cleanup_free_ char *value = NULL;
const char *path, *syspath, *cached_value = NULL; const char *path, *syspath, *cached_value = NULL;
struct stat statbuf; struct stat statbuf;
@ -1874,7 +1872,7 @@ _public_ int sd_device_get_sysattr_value(sd_device *device, const char *sysattr,
assert_return(sysattr, -EINVAL); assert_return(sysattr, -EINVAL);
/* look for possibly already cached result */ /* look for possibly already cached result */
r = device_get_cached_sysattr_value(device, sysattr, &cached_value); r = device_get_sysattr_value(device, sysattr, &cached_value);
if (r != -ENOENT) { if (r != -ENOENT) {
if (r < 0) if (r < 0)
return r; return r;
@ -1883,8 +1881,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 */ /* we looked up the sysattr before and it did not exist */
return -ENOENT; return -ENOENT;
if (ret_value) if (_value)
*ret_value = cached_value; *_value = cached_value;
return 0; return 0;
} }
@ -1896,16 +1894,12 @@ _public_ int sd_device_get_sysattr_value(sd_device *device, const char *sysattr,
path = prefix_roota(syspath, sysattr); path = prefix_roota(syspath, sysattr);
r = lstat(path, &statbuf); r = lstat(path, &statbuf);
if (r < 0) { if (r < 0) {
int k;
/* remember that we could not access the sysattr */ /* remember that we could not access the sysattr */
k = device_cache_sysattr_value(device, sysattr, NULL); r = device_add_sysattr_value(device, sysattr, NULL);
if (k < 0) if (r < 0)
log_device_debug_errno(device, k,
"sd-device: failed to cache attribute '%s' with NULL, ignoring: %m",
sysattr);
return r; return r;
return -ENOENT;
} else if (S_ISLNK(statbuf.st_mode)) { } else if (S_ISLNK(statbuf.st_mode)) {
/* Some core links return only the last element of the target path, /* Some core links return only the last element of the target path,
* these are just values, the paths should not be exposed. */ * these are just values, the paths should not be exposed. */
@ -1915,38 +1909,35 @@ _public_ int sd_device_get_sysattr_value(sd_device *device, const char *sysattr,
return r; return r;
} else } else
return -EINVAL; return -EINVAL;
} else if (S_ISDIR(statbuf.st_mode)) } else if (S_ISDIR(statbuf.st_mode)) {
/* skip directories */ /* skip directories */
return -EISDIR; return -EINVAL;
else if (!(statbuf.st_mode & S_IRUSR)) } else if (!(statbuf.st_mode & S_IRUSR)) {
/* skip non-readable files */ /* skip non-readable files */
return -EPERM; return -EPERM;
else { } else {
size_t size;
/* read attribute value */ /* read attribute value */
r = read_full_virtual_file(path, &value, NULL); r = read_full_virtual_file(path, &value, &size);
if (r < 0) if (r < 0)
return r; return r;
/* drop trailing newlines */ /* drop trailing newlines */
delete_trailing_chars(value, "\n"); while (size > 0 && value[--size] == '\n')
value[size] = '\0';
} }
/* Unfortunately, we need to return 'const char*' instead of 'char*'. Hence, failure in caching r = device_add_sysattr_value(device, sysattr, value);
* sysattr value is critical unlike the other places. */ if (r < 0)
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; return r;
} else if (ret_value)
*ret_value = TAKE_PTR(value); *_value = TAKE_PTR(value);
return 0; return 0;
} }
static void device_remove_cached_sysattr_value(sd_device *device, const char *_key) { static void device_remove_sysattr_value(sd_device *device, const char *_key) {
_cleanup_free_ char *key = NULL; _cleanup_free_ char *key = NULL;
assert(device); assert(device);
@ -1955,6 +1946,8 @@ static void device_remove_cached_sysattr_value(sd_device *device, const char *_k
free(hashmap_remove2(device->sysattr_values, _key, (void **) &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) { _public_ int sd_device_set_sysattr_value(sd_device *device, const char *sysattr, const char *_value) {
_cleanup_free_ char *value = NULL; _cleanup_free_ char *value = NULL;
const char *syspath, *path; const char *syspath, *path;
@ -1964,11 +1957,8 @@ _public_ int sd_device_set_sysattr_value(sd_device *device, const char *sysattr,
assert_return(device, -EINVAL); assert_return(device, -EINVAL);
assert_return(sysattr, -EINVAL); assert_return(sysattr, -EINVAL);
/* Set the attribute and save it in the cache. */
if (!_value) { if (!_value) {
/* If input value is NULL, then clear cache and not write anything. */ device_remove_sysattr_value(device, sysattr);
device_remove_cached_sysattr_value(device, sysattr);
return 0; return 0;
} }
@ -1981,7 +1971,7 @@ _public_ int sd_device_set_sysattr_value(sd_device *device, const char *sysattr,
len = strlen(_value); len = strlen(_value);
/* drop trailing newlines */ /* drop trailing newlines */
while (len > 0 && strchr(NEWLINE, _value[len - 1])) while (len > 0 && _value[len - 1] == '\n')
len --; len --;
/* value length is limited to 4k */ /* value length is limited to 4k */
@ -1994,21 +1984,26 @@ _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); r = write_string_file(path, value, WRITE_STRING_FILE_DISABLE_BUFFER | WRITE_STRING_FILE_NOFOLLOW);
if (r < 0) { if (r < 0) {
/* On failure, clear cache entry, as we do not know how it fails. */ if (r == -ELOOP)
device_remove_cached_sysattr_value(device, sysattr); return -EINVAL;
if (r == -EISDIR)
return r; 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;
} }
/* Do not cache action string written into uevent file. */ r = device_add_sysattr_value(device, sysattr, value);
if (streq(sysattr, "uevent"))
return 0;
r = device_cache_sysattr_value(device, sysattr, value);
if (r < 0) if (r < 0)
log_device_debug_errno(device, r, return r;
"sd-device: failed to cache attribute '%s' with '%s', ignoring: %m",
sysattr, value);
else
TAKE_PTR(value); TAKE_PTR(value);
return 0; return 0;
@ -2023,7 +2018,7 @@ _public_ int sd_device_set_sysattr_valuef(sd_device *device, const char *sysattr
assert_return(sysattr, -EINVAL); assert_return(sysattr, -EINVAL);
if (!format) { if (!format) {
device_remove_cached_sysattr_value(device, sysattr); device_remove_sysattr_value(device, sysattr);
return 0; return 0;
} }
@ -2036,15 +2031,3 @@ _public_ int sd_device_set_sysattr_valuef(sd_device *device, const char *sysattr
return sd_device_set_sysattr_value(device, sysattr, value); 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,7 +4,6 @@
#include "device-internal.h" #include "device-internal.h"
#include "device-private.h" #include "device-private.h"
#include "device-util.h" #include "device-util.h"
#include "errno-util.h"
#include "hashmap.h" #include "hashmap.h"
#include "nulstr-util.h" #include "nulstr-util.h"
#include "string-util.h" #include "string-util.h"
@ -52,7 +51,7 @@ static void test_sd_device_one(sd_device *d) {
} }
r = sd_device_get_sysattr_value(d, "name_assign_type", &val); r = sd_device_get_sysattr_value(d, "name_assign_type", &val);
assert_se(r >= 0 || ERRNO_IS_PRIVILEGE(r) || IN_SET(r, -ENOENT, -EINVAL)); assert_se(r >= 0 || IN_SET(r, -ENOENT, -EINVAL));
r = sd_device_get_property_value(d, "ID_NET_DRIVER", &val); r = sd_device_get_property_value(d, "ID_NET_DRIVER", &val);
assert_se(r >= 0 || r == -ENOENT); assert_se(r >= 0 || r == -ENOENT);

View File

@ -1197,7 +1197,7 @@ static int acquire_removable(sd_device *d) {
return 0; return 0;
for (;;) { for (;;) {
if (sd_device_get_sysattr_value(d, "removable", &v) >= 0) if (sd_device_get_sysattr_value(d, "removable", &v) > 0)
break; break;
if (sd_device_get_parent(d, &d) < 0) if (sd_device_get_parent(d, &d) < 0)

View File

@ -150,8 +150,7 @@ static int device_is_partition(sd_device *d, blkid_partition pp) {
return false; return false;
r = sd_device_get_sysattr_value(d, "partition", &v); 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; return false;
if (r < 0) if (r < 0)
return r; return r;

View File

@ -10,7 +10,6 @@
#include "device-private.h" #include "device-private.h"
#include "device-util.h" #include "device-util.h"
#include "env-file.h" #include "env-file.h"
#include "errno-util.h"
#include "escape.h" #include "escape.h"
#include "fd-util.h" #include "fd-util.h"
#include "log.h" #include "log.h"
@ -526,12 +525,12 @@ int udev_resolve_subsys_kernel(const char *string, char *result, size_t maxsize,
if (read_value) { if (read_value) {
r = sd_device_get_sysattr_value(dev, attr, &val); r = sd_device_get_sysattr_value(dev, attr, &val);
if (r < 0 && !ERRNO_IS_PRIVILEGE(r) && r != -ENOENT) if (r < 0 && r != -ENOENT)
return r; return r;
if (r >= 0) if (r == -ENOENT)
strscpy(result, maxsize, val);
else
result[0] = '\0'; result[0] = '\0';
else
strscpy(result, maxsize, val);
log_debug("value '[%s/%s]%s' is '%s'", subsys, sysname, attr, result); log_debug("value '[%s/%s]%s' is '%s'", subsys, sysname, attr, result);
} else { } else {
r = sd_device_get_syspath(dev, &val); r = sd_device_get_syspath(dev, &val);

View File

@ -99,7 +99,6 @@ 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_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_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 */ /* device enumerator */

View File

@ -481,9 +481,6 @@ static void test_path_startswith(void) {
assert_se(!path_startswith("/foo/bar/barfoo/", "")); assert_se(!path_startswith("/foo/bar/barfoo/", ""));
assert_se(!path_startswith("/foo/bar/barfoo/", "/bar/foo")); 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/", "/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) { static void test_prefix_root_one(const char *r, const char *p, const char *expected) {

View File

@ -8,7 +8,6 @@
#include "device-enumerator-private.h" #include "device-enumerator-private.h"
#include "device-private.h" #include "device-private.h"
#include "device-util.h"
#include "fd-util.h" #include "fd-util.h"
#include "fileio.h" #include "fileio.h"
#include "path-util.h" #include "path-util.h"
@ -23,63 +22,36 @@
static bool arg_verbose = false; static bool arg_verbose = false;
static bool arg_dry_run = false; static bool arg_dry_run = false;
static bool arg_quiet = false;
static int exec_list(sd_device_enumerator *e, sd_device_action_t action, Set **settle_set) { static int exec_list(sd_device_enumerator *e, const char *action, Set **settle_set) {
const char *action_str;
sd_device *d; sd_device *d;
int r, ret = 0; int r, ret = 0;
action_str = device_action_to_string(action);
FOREACH_DEVICE_AND_SUBSYSTEM(e, d) { FOREACH_DEVICE_AND_SUBSYSTEM(e, d) {
_cleanup_free_ char *filename = NULL;
const char *syspath; const char *syspath;
if (sd_device_get_syspath(d, &syspath) < 0) if (sd_device_get_syspath(d, &syspath) < 0)
continue; continue;
if (arg_verbose) if (arg_verbose)
printf("%s\n", strna(syspath)); printf("%s\n", syspath);
if (arg_dry_run) if (arg_dry_run)
continue; continue;
r = sd_device_trigger(d, action); filename = path_join(syspath, "uevent");
if (!filename)
return log_oom();
r = write_string_file(filename, action, WRITE_STRING_FILE_DISABLE_BUFFER);
if (r < 0) { if (r < 0) {
/* 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.
*/
bool ignore = IN_SET(r, -ENOENT, -ENODEV); 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, log_full_errno(ignore ? LOG_DEBUG : LOG_ERR, r,
"Failed to write '%s' to '%s/uevent'%s: %m", "Failed to write '%s' to '%s'%s: %m",
action_str, syspath, ignore ? ", ignoring" : ""); action, filename, ignore ? ", ignoring" : "");
if (IN_SET(r, -EACCES, -EROFS))
if (r == -EROFS) /* Inovoked by unprivileged user, or read only filesystem. Return earlier. */
return r; return r;
if (ret == 0 && !ignore) if (ret == 0 && !ignore)
ret = r; ret = r;
@ -146,7 +118,6 @@ static int help(void) {
" -V --version Show package version\n" " -V --version Show package version\n"
" -v --verbose Print the list of devices while running\n" " -v --verbose Print the list of devices while running\n"
" -n --dry-run Do not actually trigger the events\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" " -t --type= Type of events to trigger\n"
" devices sysfs devices (default)\n" " devices sysfs devices (default)\n"
" subsystems sysfs subsystems and drivers\n" " subsystems sysfs subsystems and drivers\n"
@ -177,7 +148,6 @@ int trigger_main(int argc, char *argv[], void *userdata) {
static const struct option options[] = { static const struct option options[] = {
{ "verbose", no_argument, NULL, 'v' }, { "verbose", no_argument, NULL, 'v' },
{ "dry-run", no_argument, NULL, 'n' }, { "dry-run", no_argument, NULL, 'n' },
{ "quiet", no_argument, NULL, 'q' },
{ "type", required_argument, NULL, 't' }, { "type", required_argument, NULL, 't' },
{ "action", required_argument, NULL, 'c' }, { "action", required_argument, NULL, 'c' },
{ "subsystem-match", required_argument, NULL, 's' }, { "subsystem-match", required_argument, NULL, 's' },
@ -199,7 +169,7 @@ int trigger_main(int argc, char *argv[], void *userdata) {
TYPE_DEVICES, TYPE_DEVICES,
TYPE_SUBSYSTEMS, TYPE_SUBSYSTEMS,
} device_type = TYPE_DEVICES; } device_type = TYPE_DEVICES;
sd_device_action_t action = SD_DEVICE_CHANGE; const char *action = "change";
_cleanup_(sd_device_enumerator_unrefp) sd_device_enumerator *e = NULL; _cleanup_(sd_device_enumerator_unrefp) sd_device_enumerator *e = NULL;
_cleanup_(sd_device_monitor_unrefp) sd_device_monitor *m = NULL; _cleanup_(sd_device_monitor_unrefp) sd_device_monitor *m = NULL;
_cleanup_(sd_event_unrefp) sd_event *event = NULL; _cleanup_(sd_event_unrefp) sd_event *event = NULL;
@ -221,7 +191,7 @@ int trigger_main(int argc, char *argv[], void *userdata) {
if (r < 0) if (r < 0)
return r; return r;
while ((c = getopt_long(argc, argv, "vnqt:c:s:S:a:A:p:g:y:b:wVh", options, NULL)) >= 0) { while ((c = getopt_long(argc, argv, "vnt:c:s:S:a:A:p:g:y:b:wVh", options, NULL)) >= 0) {
_cleanup_free_ char *buf = NULL; _cleanup_free_ char *buf = NULL;
const char *key, *val; const char *key, *val;
@ -232,9 +202,6 @@ int trigger_main(int argc, char *argv[], void *userdata) {
case 'n': case 'n':
arg_dry_run = true; arg_dry_run = true;
break; break;
case 'q':
arg_quiet = true;
break;
case 't': case 't':
if (streq(optarg, "devices")) if (streq(optarg, "devices"))
device_type = TYPE_DEVICES; device_type = TYPE_DEVICES;
@ -244,14 +211,18 @@ int trigger_main(int argc, char *argv[], void *userdata) {
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Unknown type --type=%s", optarg); return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Unknown type --type=%s", optarg);
break; break;
case 'c': { case 'c': {
sd_device_action_t a;
if (streq(optarg, "help")) { if (streq(optarg, "help")) {
dump_device_action_table(); dump_device_action_table();
return 0; return 0;
} }
action = device_action_from_string(optarg); a = device_action_from_string(optarg);
if (action < 0) if (a < 0)
return log_error_errno(action, "Unknown action '%s'", optarg); return log_error_errno(a, "Unknown action '%s'", optarg);
action = device_action_to_string(a);
break; break;
} }
case 's': case 's':

View File

@ -1155,54 +1155,56 @@ static int on_ctrl_msg(struct udev_ctrl *uctrl, enum udev_ctrl_msg_type type, co
return 1; return 1;
} }
static int synthesize_change_one(sd_device *dev, sd_device *target) { static int synthesize_change_one(sd_device *dev, const char *syspath) {
const char *filename;
int r; int r;
if (DEBUG_LOGGING) { filename = strjoina(syspath, "/uevent");
const char *syspath = NULL; log_device_debug(dev, "device is closed, synthesising 'change' on %s", syspath);
(void) sd_device_get_syspath(target, &syspath); r = write_string_file(filename, "change", WRITE_STRING_FILE_DISABLE_BUFFER);
log_device_debug(dev, "device is closed, synthesising 'change' on %s", strna(syspath));
}
r = sd_device_trigger(target, SD_DEVICE_CHANGE);
if (r < 0) if (r < 0)
return log_device_debug_errno(target, r, "Failed to trigger 'change' uevent: %m"); return log_device_debug_errno(dev, r, "Failed to write 'change' to %s: %m", filename);
return 0; return 0;
} }
static int synthesize_change(sd_device *dev) { static int synthesize_change(sd_device *dev) {
const char *subsystem, *sysname, *devtype; const char *subsystem, *sysname, *devname, *syspath, *devtype;
int r; int r;
r = sd_device_get_subsystem(dev, &subsystem); r = sd_device_get_subsystem(dev, &subsystem);
if (r < 0) if (r < 0)
return r; return r;
r = sd_device_get_devtype(dev, &devtype);
if (r < 0)
return r;
r = sd_device_get_sysname(dev, &sysname); r = sd_device_get_sysname(dev, &sysname);
if (r < 0) if (r < 0)
return r; 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;
r = sd_device_get_devname(dev, &devname); r = sd_device_get_devname(dev, &devname);
if (r < 0) if (r < 0)
return r; return r;
/* Try to re-read the partition table. This only succeeds if none of the devices is r = sd_device_get_syspath(dev, &syspath);
* busy. The kernel returns 0 if no partition table is found, and we will not get an if (r < 0)
* event for the disk. */ return r;
r = sd_device_get_devtype(dev, &devtype);
if (r < 0)
return r;
if (streq_ptr("block", subsystem) &&
streq_ptr("disk", devtype) &&
!startswith(sysname, "dm-")) {
_cleanup_(sd_device_enumerator_unrefp) sd_device_enumerator *e = NULL;
bool part_table_read = false, has_partitions = false;
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.
*/
fd = open(devname, O_RDONLY|O_CLOEXEC|O_NOFOLLOW|O_NONBLOCK); fd = open(devname, O_RDONLY|O_CLOEXEC|O_NOFOLLOW|O_NONBLOCK);
if (fd >= 0) { if (fd >= 0) {
r = flock(fd, LOCK_EX|LOCK_NB); r = flock(fd, LOCK_EX|LOCK_NB);
@ -1234,33 +1236,44 @@ static int synthesize_change(sd_device *dev) {
FOREACH_DEVICE(e, d) { FOREACH_DEVICE(e, d) {
const char *t; const char *t;
if (sd_device_get_devtype(d, &t) < 0 || !streq(t, "partition")) if (sd_device_get_devtype(d, &t) < 0 ||
!streq("partition", t))
continue; continue;
has_partitions = true; has_partitions = true;
break; 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) if (part_table_read && has_partitions)
return 0; return 0;
/* We have partitions but re-reading the partition table did not work, synthesize /*
* "change" for the disk and all partitions. */ * We have partitions but re-reading the partition table did not
(void) synthesize_change_one(dev, dev); * work, synthesize "change" for the disk and all partitions.
*/
(void) synthesize_change_one(dev, syspath);
FOREACH_DEVICE(e, d) { FOREACH_DEVICE(e, d) {
const char *t; const char *t, *n, *s;
if (sd_device_get_devtype(d, &t) < 0 || !streq(t, "partition")) if (sd_device_get_devtype(d, &t) < 0 ||
!streq("partition", t))
continue; continue;
(void) synthesize_change_one(dev, d); if (sd_device_get_devname(d, &n) < 0 ||
sd_device_get_syspath(d, &s) < 0)
continue;
(void) synthesize_change_one(dev, s);
} }
} else } else
(void) synthesize_change_one(dev, dev); (void) synthesize_change_one(dev, syspath);
return 0; return 0;
} }

View File

@ -19,5 +19,5 @@ ConditionPathIsReadWrite=/sys
[Service] [Service]
Type=oneshot Type=oneshot
RemainAfterExit=yes RemainAfterExit=yes
ExecStart=-udevadm trigger --type=subsystems --action=add ExecStart=udevadm trigger --type=subsystems --action=add
ExecStart=-udevadm trigger --type=devices --action=add ExecStart=udevadm trigger --type=devices --action=add