mirror of
https://github.com/systemd/systemd-stable.git
synced 2024-12-22 13:33:56 +03:00
Merge pull request #11144 from keszybz/dissect-image-fix
Fix for dissect-image use in nspawn
This commit is contained in:
commit
4f9cf94c4a
@ -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_;
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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");
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user