Merge pull request #11144 from keszybz/dissect-image-fix

Fix for dissect-image use in nspawn
This commit is contained in:
Lennart Poettering 2018-12-17 19:36:36 +01:00 committed by GitHub
commit 4f9cf94c4a
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
9 changed files with 287 additions and 408 deletions

View file

@ -5,12 +5,14 @@
#include "hashmap.h"
#include "set.h"
#include "time-util.h"
struct sd_device {
unsigned n_ref;
int watch_handle;
sd_device *parent;
bool parent_set; /* no need to try to reload parent */
OrderedHashmap *properties;
Iterator properties_iterator;
@ -24,60 +26,59 @@ struct sd_device {
Set *sysattrs; /* names of sysattrs */
Iterator sysattrs_iterator;
bool sysattrs_read; /* don't try to re-read sysattrs once read */
Set *tags;
Iterator tags_iterator;
uint64_t tags_generation; /* changes whenever the tags are changed */
uint64_t tags_iterator_generation; /* generation when iteration was started */
bool property_tags_outdated; /* need to update TAGS= property */
Set *devlinks;
Iterator devlinks_iterator;
uint64_t devlinks_generation; /* changes whenever the devlinks are changed */
uint64_t devlinks_iterator_generation; /* generation when iteration was started */
bool property_devlinks_outdated; /* need to update DEVLINKS= property */
int devlink_priority;
int ifindex;
char *devtype;
char *devname;
dev_t devnum;
char **properties_strv; /* the properties hashmap as a strv */
uint8_t *properties_nulstr; /* the same as a nulstr */
size_t properties_nulstr_len;
bool properties_buf_outdated; /* need to reread hashmap */
int watch_handle;
char *syspath;
const char *devpath;
const char *sysnum;
char *sysname;
bool sysname_set; /* don't reread sysname */
char *devtype;
int ifindex;
char *devname;
dev_t devnum;
char *subsystem;
bool subsystem_set; /* don't reread subsystem */
char *driver_subsystem; /* only set for the 'drivers' subsystem */
bool driver_subsystem_set; /* don't reread subsystem */
char *driver;
bool driver_set; /* don't reread driver */
char *id_filename;
bool is_initialized;
uint64_t usec_initialized;
mode_t devmode;
uid_t devuid;
gid_t devgid;
bool uevent_loaded; /* don't reread uevent */
bool parent_set:1; /* no need to try to reload parent */
bool sysattrs_read:1; /* don't try to re-read sysattrs once read */
bool property_tags_outdated:1; /* need to update TAGS= property */
bool property_devlinks_outdated:1; /* need to update DEVLINKS= property */
bool properties_buf_outdated:1; /* need to reread hashmap */
bool sysname_set:1; /* don't reread sysname */
bool subsystem_set:1; /* don't reread subsystem */
bool driver_subsystem_set:1; /* don't reread subsystem */
bool driver_set:1; /* don't reread driver */
bool uevent_loaded:1; /* don't reread uevent */
bool db_loaded; /* don't reread db */
bool sealed; /* don't read more information from uevent/db */
bool db_persist; /* don't clean up the db when switching from initrd to real root */
bool is_initialized:1;
bool sealed:1; /* don't read more information from uevent/db */
bool db_persist:1; /* don't clean up the db when switching from initrd to real root */
};
typedef enum DeviceAction {
@ -97,7 +98,6 @@ int device_new_aux(sd_device **ret);
int device_add_property_aux(sd_device *device, const char *key, const char *value, bool db);
int device_add_property_internal(sd_device *device, const char *key, const char *value);
int device_read_uevent_file(sd_device *device);
int device_read_db_aux(sd_device *device, bool force);
int device_set_syspath(sd_device *device, const char *_syspath, bool verify);
int device_set_ifindex(sd_device *device, const char *ifindex);
@ -107,7 +107,7 @@ int device_set_devtype(sd_device *device, const char *_devtype);
int device_set_devnum(sd_device *device, const char *major, const char *minor);
int device_set_subsystem(sd_device *device, const char *_subsystem);
int device_set_driver(sd_device *device, const char *_driver);
int device_set_usec_initialized(sd_device *device, const char *initialized);
int device_set_usec_initialized(sd_device *device, usec_t when);
DeviceAction device_action_from_string(const char *s) _pure_;
const char *device_action_to_string(DeviceAction a) _const_;

View file

@ -47,81 +47,6 @@ int device_add_property(sd_device *device, const char *key, const char *value) {
return 0;
}
static int device_add_property_internal_from_string(sd_device *device, const char *str) {
_cleanup_free_ char *key = NULL;
char *value;
assert(device);
assert(str);
key = strdup(str);
if (!key)
return -ENOMEM;
value = strchr(key, '=');
if (!value)
return -EINVAL;
*value = '\0';
if (isempty(++value))
value = NULL;
return device_add_property_internal(device, key, value);
}
static int handle_db_line(sd_device *device, char key, const char *value) {
char *path;
int r;
assert(device);
assert(value);
switch (key) {
case 'S':
path = strjoina("/dev/", value);
r = device_add_devlink(device, path);
if (r < 0)
return r;
break;
case 'L':
r = safe_atoi(value, &device->devlink_priority);
if (r < 0)
return r;
break;
case 'E':
r = device_add_property_internal_from_string(device, value);
if (r < 0)
return r;
break;
case 'G':
r = device_add_tag(device, value);
if (r < 0)
return r;
break;
case 'W':
r = safe_atoi(value, &device->watch_handle);
if (r < 0)
return r;
break;
case 'I':
r = device_set_usec_initialized(device, value);
if (r < 0)
return r;
break;
default:
log_device_debug(device, "sd-device: Unknown key '%c' in device db, ignoring", key);
}
return 0;
}
void device_set_devlink_priority(sd_device *device, int priority) {
assert(device);
@ -135,119 +60,16 @@ void device_set_is_initialized(sd_device *device) {
}
int device_ensure_usec_initialized(sd_device *device, sd_device *device_old) {
char num[DECIMAL_STR_MAX(usec_t)];
usec_t usec_initialized;
int r;
usec_t when;
assert(device);
if (device_old && device_old->usec_initialized > 0)
usec_initialized = device_old->usec_initialized;
when = device_old->usec_initialized;
else
usec_initialized = now(CLOCK_MONOTONIC);
when = now(CLOCK_MONOTONIC);
r = snprintf(num, sizeof(num), USEC_FMT, usec_initialized);
if (r < 0)
return -errno;
r = device_set_usec_initialized(device, num);
if (r < 0)
return r;
return 0;
}
static int device_read_db(sd_device *device) {
_cleanup_free_ char *db = NULL;
char *path;
const char *id, *value;
char key;
size_t db_len;
unsigned i;
int r;
enum {
PRE_KEY,
KEY,
PRE_VALUE,
VALUE,
INVALID_LINE,
} state = PRE_KEY;
assert(device);
if (device->db_loaded || device->sealed)
return 0;
r = device_get_id_filename(device, &id);
if (r < 0)
return r;
path = strjoina("/run/udev/data/", id);
r = read_full_file(path, &db, &db_len);
if (r < 0) {
if (r == -ENOENT)
return 0;
else
return log_device_debug_errno(device, r, "sd-device: Failed to read db '%s': %m", path);
}
/* devices with a database entry are initialized */
device_set_is_initialized(device);
for (i = 0; i < db_len; i++) {
switch (state) {
case PRE_KEY:
if (!strchr(NEWLINE, db[i])) {
key = db[i];
state = KEY;
}
break;
case KEY:
if (db[i] != ':') {
log_device_debug(device, "sd-device: Invalid db entry with key '%c', ignoring", key);
state = INVALID_LINE;
} else {
db[i] = '\0';
state = PRE_VALUE;
}
break;
case PRE_VALUE:
value = &db[i];
state = VALUE;
break;
case INVALID_LINE:
if (strchr(NEWLINE, db[i]))
state = PRE_KEY;
break;
case VALUE:
if (strchr(NEWLINE, db[i])) {
db[i] = '\0';
r = handle_db_line(device, key, value);
if (r < 0)
log_device_debug_errno(device, r, "sd-device: Failed to handle db entry '%c:%s', ignoring: %m", key, value);
state = PRE_KEY;
}
break;
default:
assert_not_reached("Invalid state when parsing db");
}
}
device->db_loaded = true;
return 0;
return device_set_usec_initialized(device, when);
}
uint64_t device_get_properties_generation(sd_device *device) {
@ -391,7 +213,13 @@ static int device_amend(sd_device *device, const char *key, const char *value) {
if (r < 0)
return log_device_debug_errno(device, r, "sd-device: Failed to set devname to '%s': %m", value);
} else if (streq(key, "USEC_INITIALIZED")) {
r = device_set_usec_initialized(device, value);
usec_t t;
r = safe_atou64(value, &t);
if (r < 0)
return log_device_debug_errno(device, r, "sd-device: Failed to parse timestamp '%s': %m", value);
r = device_set_usec_initialized(device, t);
if (r < 0)
return log_device_debug_errno(device, r, "sd-device: Failed to set usec-initialized to '%s': %m", value);
} else if (streq(key, "DRIVER")) {
@ -1115,9 +943,3 @@ int device_delete_db(sd_device *device) {
return 0;
}
int device_read_db_force(sd_device *device) {
assert(device);
return device_read_db_aux(device, true);
}

View file

@ -49,4 +49,7 @@ int device_new_from_synthetic_event(sd_device **new_device, const char *syspath,
int device_tag_index(sd_device *dev, sd_device *dev_old, bool add);
int device_update_db(sd_device *device);
int device_delete_db(sd_device *device);
int device_read_db_force(sd_device *device);
int device_read_db_internal(sd_device *device, bool force);
static inline int device_read_db(sd_device *device) {
return device_read_db_internal(device, false);
}

View file

@ -22,6 +22,7 @@
#include "set.h"
#include "socket-util.h"
#include "stat-util.h"
#include "stdio-util.h"
#include "string-util.h"
#include "strv.h"
#include "strxcpyx.h"
@ -498,8 +499,6 @@ int device_read_uevent_file(sd_device *device) {
if (device->uevent_loaded || device->sealed)
return 0;
device->uevent_loaded = true;
r = sd_device_get_syspath(device, &syspath);
if (r < 0)
return r;
@ -507,15 +506,19 @@ int device_read_uevent_file(sd_device *device) {
path = strjoina(syspath, "/uevent");
r = read_full_file(path, &uevent, &uevent_len);
if (r == -EACCES)
if (r == -EACCES) {
/* empty uevent files may be write-only */
device->uevent_loaded = true;
return 0;
else if (r == -ENOENT)
}
if (r == -ENOENT)
/* some devices may not have uevent files, see set_syspath() */
return 0;
else if (r < 0)
if (r < 0)
return log_device_debug_errno(device, r, "sd-device: Failed to read uevent file '%s': %m", path);
device->uevent_loaded = true;
for (i = 0; i < uevent_len; i++)
switch (state) {
case PRE_KEY:
@ -1147,23 +1150,19 @@ static int device_add_property_internal_from_string(sd_device *device, const cha
return device_add_property_internal(device, key, value);
}
int device_set_usec_initialized(sd_device *device, const char *initialized) {
uint64_t usec_initialized;
int device_set_usec_initialized(sd_device *device, usec_t when) {
char s[DECIMAL_STR_MAX(usec_t)];
int r;
assert(device);
assert(initialized);
r = safe_atou64(initialized, &usec_initialized);
xsprintf(s, USEC_FMT, when);
r = device_add_property_internal(device, "USEC_INITIALIZED", s);
if (r < 0)
return r;
r = device_add_property_internal(device, "USEC_INITIALIZED", initialized);
if (r < 0)
return r;
device->usec_initialized = usec_initialized;
device->usec_initialized = when;
return 0;
}
@ -1194,12 +1193,19 @@ static int handle_db_line(sd_device *device, char key, const char *value) {
return r;
break;
case 'I':
r = device_set_usec_initialized(device, value);
case 'I': {
usec_t t;
r = safe_atou64(value, &t);
if (r < 0)
return r;
r = device_set_usec_initialized(device, t);
if (r < 0)
return r;
break;
}
case 'L':
r = safe_atoi(value, &device->devlink_priority);
if (r < 0)
@ -1281,7 +1287,7 @@ int device_get_id_filename(sd_device *device, const char **ret) {
return 0;
}
int device_read_db_aux(sd_device *device, bool force) {
int device_read_db_internal(sd_device *device, bool force) {
_cleanup_free_ char *db = NULL;
char *path;
const char *id, *value;
@ -1298,11 +1304,11 @@ int device_read_db_aux(sd_device *device, bool force) {
INVALID_LINE,
} state = PRE_KEY;
assert(device);
if (device->db_loaded || (!force && device->sealed))
return 0;
device->db_loaded = true;
r = device_get_id_filename(device, &id);
if (r < 0)
return r;
@ -1320,6 +1326,8 @@ int device_read_db_aux(sd_device *device, bool force) {
/* devices with a database entry are initialized */
device->is_initialized = true;
device->db_loaded = true;
for (i = 0; i < db_len; i++) {
switch (state) {
case PRE_KEY:
@ -1372,10 +1380,6 @@ int device_read_db_aux(sd_device *device, bool force) {
return 0;
}
static int device_read_db(sd_device *device) {
return device_read_db_aux(device, false);
}
_public_ int sd_device_get_is_initialized(sd_device *device) {
int r;

View file

@ -18,6 +18,7 @@
#include "proc-cmdline.h"
#include "string-table.h"
#include "string-util.h"
#include "udev-util.h"
#include "util.h"
#include "list.h"
@ -88,89 +89,6 @@ static int find_device(
return 0;
}
struct DeviceMonitorData {
const char *sysname;
sd_device *device;
};
static int device_monitor_handler(sd_device_monitor *monitor, sd_device *device, void *userdata) {
struct DeviceMonitorData *data = userdata;
const char *sysname;
assert(device);
assert(data);
assert(data->sysname);
if (sd_device_get_sysname(device, &sysname) >= 0 && streq(sysname, data->sysname)) {
data->device = sd_device_ref(device);
return sd_event_exit(sd_device_monitor_get_event(monitor), 0);
}
return 0;
}
static int wait_for_initialized(
sd_device *device,
sd_device **ret) {
_cleanup_(sd_device_monitor_unrefp) sd_device_monitor *monitor = NULL;
_cleanup_(sd_event_unrefp) sd_event *event = NULL;
_cleanup_(sd_device_unrefp) sd_device *d = NULL;
struct DeviceMonitorData data = {};
int r;
assert(device);
assert(ret);
if (sd_device_get_is_initialized(device) > 0) {
*ret = sd_device_ref(device);
return 0;
}
assert_se(sd_device_get_sysname(device, &data.sysname) >= 0);
/* Wait until the device is initialized, so that we can get
* access to the ID_PATH property */
r = sd_event_default(&event);
if (r < 0)
return log_error_errno(r, "Failed to get default event: %m");
r = sd_device_monitor_new(&monitor);
if (r < 0)
return log_error_errno(r, "Failed to acquire monitor: %m");
r = sd_device_monitor_filter_add_match_subsystem_devtype(monitor, "rfkill", NULL);
if (r < 0)
return log_error_errno(r, "Failed to add rfkill device match to monitor: %m");
r = sd_device_monitor_attach_event(monitor, event);
if (r < 0)
return log_error_errno(r, "Failed to attach event to device monitor: %m");
r = sd_device_monitor_start(monitor, device_monitor_handler, &data);
if (r < 0)
return log_error_errno(r, "Failed to start device monitor: %m");
/* Check again, maybe things changed */
r = sd_device_new_from_subsystem_sysname(&d, "rfkill", data.sysname);
if (r < 0)
return log_full_errno(IN_SET(r, -ENOENT, -ENXIO, -ENODEV) ? LOG_DEBUG : LOG_ERR, r,
"Failed to open device '%s': %m", data.sysname);
if (sd_device_get_is_initialized(d) > 0) {
*ret = TAKE_PTR(d);
return 0;
}
r = sd_event_loop(event);
if (r < 0)
return log_error_errno(r, "Event loop failed: %m");
*ret = TAKE_PTR(data.device);
return 0;
}
static int determine_state_file(
const struct rfkill_event *event,
char **ret) {
@ -187,7 +105,7 @@ static int determine_state_file(
if (r < 0)
return r;
r = wait_for_initialized(d, &device);
r = device_wait_for_initialization(d, "rfkill", &device);
if (r < 0)
return r;

View file

@ -40,6 +40,7 @@
#include "string-util.h"
#include "strv.h"
#include "tmpfile-util.h"
#include "udev-util.h"
#include "user-util.h"
#include "xattr-util.h"
@ -116,6 +117,133 @@ static bool device_is_block(sd_device *d) {
return streq(ss, "block");
}
static int enumerator_for_parent(sd_device *d, sd_device_enumerator **ret) {
_cleanup_(sd_device_enumerator_unrefp) sd_device_enumerator *e = NULL;
int r;
r = sd_device_enumerator_new(&e);
if (r < 0)
return r;
r = sd_device_enumerator_allow_uninitialized(e);
if (r < 0)
return r;
r = sd_device_enumerator_add_match_parent(e, d);
if (r < 0)
return r;
*ret = TAKE_PTR(e);
return 0;
}
/* how many times to wait for the device nodes to appear */
#define N_DEVICE_NODE_LIST_ATTEMPTS 10
static int wait_for_partitions_to_appear(
int fd,
sd_device *d,
unsigned num_partitions,
sd_device_enumerator **ret_enumerator) {
_cleanup_(sd_device_enumerator_unrefp) sd_device_enumerator *e = NULL;
sd_device *q;
unsigned n;
int r;
r = enumerator_for_parent(d, &e);
if (r < 0)
return r;
/* Count the partitions enumerated by the kernel */
n = 0;
FOREACH_DEVICE(e, q) {
if (sd_device_get_devnum(q, NULL) < 0)
continue;
if (!device_is_block(q))
continue;
if (device_is_mmc_special_partition(q))
continue;
r = device_wait_for_initialization(q, "block", NULL);
if (r < 0)
return r;
n++;
}
if (n == num_partitions + 1) {
*ret_enumerator = TAKE_PTR(e);
return 0; /* success! */
}
if (n > num_partitions + 1)
return log_debug_errno(SYNTHETIC_ERRNO(EIO),
"blkid and kernel partition lists do not match.");
/* The kernel has probed fewer partitions than blkid? Maybe the kernel prober is still running or it
* got EBUSY because udev already opened the device. Let's reprobe the device, which is a synchronous
* call that waits until probing is complete. */
for (unsigned j = 0; ; j++) {
if (j++ > 20)
return -EBUSY;
if (ioctl(fd, BLKRRPART, 0) >= 0)
break;
r = -errno;
if (r == -EINVAL) {
struct loop_info64 info;
/* If we are running on a loop device that has partition scanning off, return
* an explicit recognizable error about this, so that callers can generate a
* proper message explaining the situation. */
if (ioctl(fd, LOOP_GET_STATUS64, &info) >= 0 && (info.lo_flags & LO_FLAGS_PARTSCAN) == 0) {
log_debug("Device is a loop device and partition scanning is off!");
return -EPROTONOSUPPORT;
}
}
if (r != -EBUSY)
return r;
/* If something else has the device open, such as an udev rule, the ioctl will return
* EBUSY. Since there's no way to wait until it isn't busy anymore, let's just wait a bit,
* and try again.
*
* This is really something they should fix in the kernel! */
(void) usleep(50 * USEC_PER_MSEC);
}
return -EAGAIN; /* no success yet, try again */
}
static int loop_wait_for_partitions_to_appear(
int fd,
sd_device *d,
unsigned num_partitions,
sd_device_enumerator **ret_enumerator) {
_cleanup_(sd_device_unrefp) sd_device *device = NULL;
int r;
log_debug("Waiting for device (parent + %d partitions) to appear...", num_partitions);
r = device_wait_for_initialization(d, "block", &device);
if (r < 0)
return r;
for (unsigned i = 0; i < N_DEVICE_NODE_LIST_ATTEMPTS; i++) {
r = wait_for_partitions_to_appear(fd, device, num_partitions, ret_enumerator);
if (r != -EAGAIN)
return r;
}
return log_debug_errno(SYNTHETIC_ERRNO(ENXIO),
"Kernel partitions dit not appear within %d attempts",
N_DEVICE_NODE_LIST_ATTEMPTS);
}
#endif
int dissect_image(
@ -204,6 +332,10 @@ int dissect_image(
if (!m)
return -ENOMEM;
r = sd_device_new_from_devnum(&d, 'b', st.st_rdev);
if (r < 0)
return r;
if (!(flags & DISSECT_IMAGE_GPT_ONLY) &&
(flags & DISSECT_IMAGE_REQUIRE_ROOT)) {
const char *usage = NULL;
@ -237,6 +369,10 @@ int dissect_image(
m->encrypted = streq_ptr(fstype, "crypto_LUKS");
r = loop_wait_for_partitions_to_appear(fd, d, 0, &e);
if (r < 0)
return r;
*ret = TAKE_PTR(m);
return 0;
@ -258,96 +394,10 @@ int dissect_image(
if (!pl)
return -errno ?: -ENOMEM;
r = sd_device_new_from_devnum(&d, 'b', st.st_rdev);
r = loop_wait_for_partitions_to_appear(fd, d, blkid_partlist_numof_partitions(pl), &e);
if (r < 0)
return r;
for (i = 0;; i++) {
int n, z;
if (i >= 10) {
log_debug("Kernel partitions never appeared.");
return -ENXIO;
}
r = sd_device_enumerator_new(&e);
if (r < 0)
return r;
r = sd_device_enumerator_allow_uninitialized(e);
if (r < 0)
return r;
r = sd_device_enumerator_add_match_parent(e, d);
if (r < 0)
return r;
/* Count the partitions enumerated by the kernel */
n = 0;
FOREACH_DEVICE(e, q) {
if (sd_device_get_devnum(q, NULL) < 0)
continue;
if (!device_is_block(q))
continue;
if (device_is_mmc_special_partition(q))
continue;
n++;
}
/* Count the partitions enumerated by blkid */
z = blkid_partlist_numof_partitions(pl);
if (n == z + 1)
break;
if (n > z + 1) {
log_debug("blkid and kernel partition list do not match.");
return -EIO;
}
if (n < z + 1) {
unsigned j = 0;
/* The kernel has probed fewer partitions than blkid? Maybe the kernel prober is still running
* or it got EBUSY because udev already opened the device. Let's reprobe the device, which is a
* synchronous call that waits until probing is complete. */
for (;;) {
if (j++ > 20)
return -EBUSY;
if (ioctl(fd, BLKRRPART, 0) < 0) {
r = -errno;
if (r == -EINVAL) {
struct loop_info64 info;
/* If we are running on a loop device that has partition scanning off,
* return an explicit recognizable error about this, so that callers
* can generate a proper message explaining the situation. */
if (ioctl(fd, LOOP_GET_STATUS64, &info) >= 0 && (info.lo_flags & LO_FLAGS_PARTSCAN) == 0) {
log_debug("Device is loop device and partition scanning is off!");
return -EPROTONOSUPPORT;
}
}
if (r != -EBUSY)
return r;
} else
break;
/* If something else has the device open, such as an udev rule, the ioctl will return
* EBUSY. Since there's no way to wait until it isn't busy anymore, let's just wait a
* bit, and try again.
*
* This is really something they should fix in the kernel! */
(void) usleep(50 * USEC_PER_MSEC);
}
}
e = sd_device_enumerator_unref(e);
}
FOREACH_DEVICE(e, q) {
unsigned long long pflags;
blkid_partition pp;

View file

@ -91,3 +91,81 @@ int udev_parse_config_full(
return 0;
}
struct DeviceMonitorData {
const char *sysname;
sd_device *device;
};
static int device_monitor_handler(sd_device_monitor *monitor, sd_device *device, void *userdata) {
struct DeviceMonitorData *data = userdata;
const char *sysname;
assert(device);
assert(data);
assert(data->sysname);
assert(!data->device);
if (sd_device_get_sysname(device, &sysname) >= 0 && streq(sysname, data->sysname)) {
data->device = sd_device_ref(device);
return sd_event_exit(sd_device_monitor_get_event(monitor), 0);
}
return 0;
}
int device_wait_for_initialization(sd_device *device, const char *subsystem, sd_device **ret) {
_cleanup_(sd_device_monitor_unrefp) sd_device_monitor *monitor = NULL;
_cleanup_(sd_event_unrefp) sd_event *event = NULL;
struct DeviceMonitorData data = {};
int r;
assert(device);
assert(subsystem);
if (sd_device_get_is_initialized(device) > 0) {
if (ret)
*ret = sd_device_ref(device);
return 0;
}
assert_se(sd_device_get_sysname(device, &data.sysname) >= 0);
/* Wait until the device is initialized, so that we can get access to the ID_PATH property */
r = sd_event_default(&event);
if (r < 0)
return log_error_errno(r, "Failed to get default event: %m");
r = sd_device_monitor_new(&monitor);
if (r < 0)
return log_error_errno(r, "Failed to acquire monitor: %m");
r = sd_device_monitor_filter_add_match_subsystem_devtype(monitor, subsystem, NULL);
if (r < 0)
return log_error_errno(r, "Failed to add %s subsystem match to monitor: %m", subsystem);
r = sd_device_monitor_attach_event(monitor, event);
if (r < 0)
return log_error_errno(r, "Failed to attach event to device monitor: %m");
r = sd_device_monitor_start(monitor, device_monitor_handler, &data);
if (r < 0)
return log_error_errno(r, "Failed to start device monitor: %m");
/* Check again, maybe things changed. Udev will re-read the db if the device wasn't initialized
* yet. */
if (sd_device_get_is_initialized(device) > 0) {
if (ret)
*ret = sd_device_ref(device);
return 0;
}
r = sd_event_loop(event);
if (r < 0)
return log_error_errno(r, "Event loop failed: %m");
if (ret)
*ret = TAKE_PTR(data.device);
return 0;
}

View file

@ -1,6 +1,8 @@
/* SPDX-License-Identifier: LGPL-2.1+ */
#pragma once
#include "sd-device.h"
#include "time-util.h"
typedef enum ResolveNameTiming {
@ -23,3 +25,5 @@ int udev_parse_config_full(
static inline int udev_parse_config(void) {
return udev_parse_config_full(NULL, NULL, NULL, NULL);
}
int device_wait_for_initialization(sd_device *device, const char *subsystem, sd_device **ret);

View file

@ -785,7 +785,7 @@ static void event_execute_rules_on_remove(
sd_device *dev = event->dev;
int r;
r = device_read_db_force(dev);
r = device_read_db_internal(dev, true);
if (r < 0)
log_device_debug_errno(dev, r, "Failed to read database under /run/udev/data/: %m");