mirror of
https://github.com/systemd/systemd
synced 2026-03-14 00:54:46 +01:00
Compare commits
26 Commits
c068a17f6a
...
d49b881eaf
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d49b881eaf | ||
|
|
0c9cdcb9d4 | ||
|
|
bff97a251d | ||
|
|
b43669a4b1 | ||
|
|
e63916ab29 | ||
|
|
e1e56f3443 | ||
|
|
e7f781e473 | ||
|
|
5e0d051067 | ||
|
|
4956f220a1 | ||
|
|
6e25642f8e | ||
|
|
ff7a8d2938 | ||
|
|
db2bad4368 | ||
|
|
fe7323815d | ||
|
|
0d77bc4a18 | ||
|
|
4cac2260c8 | ||
|
|
75b4984638 | ||
|
|
fa5d8899aa | ||
|
|
99e0c96f31 | ||
|
|
df7ee95913 | ||
|
|
36161cba7c | ||
|
|
d9fc3b0da9 | ||
|
|
04952b25e8 | ||
|
|
600b7898e8 | ||
|
|
e361398e48 | ||
|
|
ed52cce33f | ||
|
|
f282ce20aa |
@ -67,7 +67,7 @@ struct sd_device {
|
|||||||
char *driver_subsystem; /* only set for the 'drivers' subsystem */
|
char *driver_subsystem; /* only set for the 'drivers' subsystem */
|
||||||
char *driver;
|
char *driver;
|
||||||
|
|
||||||
char *id_filename;
|
char *device_id;
|
||||||
|
|
||||||
usec_t usec_initialized;
|
usec_t usec_initialized;
|
||||||
|
|
||||||
@ -84,9 +84,7 @@ struct sd_device {
|
|||||||
bool property_tags_outdated:1; /* need to update TAGS= or CURRENT_TAGS= property */
|
bool property_tags_outdated:1; /* need to update TAGS= or CURRENT_TAGS= property */
|
||||||
bool property_devlinks_outdated:1; /* need to update DEVLINKS= property */
|
bool property_devlinks_outdated:1; /* need to update DEVLINKS= property */
|
||||||
bool properties_buf_outdated:1; /* need to reread hashmap */
|
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 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 driver_set:1; /* don't reread driver */
|
||||||
bool uevent_loaded:1; /* don't reread uevent */
|
bool uevent_loaded:1; /* don't reread uevent */
|
||||||
bool db_loaded; /* don't reread db */
|
bool db_loaded; /* don't reread db */
|
||||||
|
|||||||
@ -20,6 +20,7 @@
|
|||||||
#include "parse-util.h"
|
#include "parse-util.h"
|
||||||
#include "path-util.h"
|
#include "path-util.h"
|
||||||
#include "set.h"
|
#include "set.h"
|
||||||
|
#include "stdio-util.h"
|
||||||
#include "string-table.h"
|
#include "string-table.h"
|
||||||
#include "string-util.h"
|
#include "string-util.h"
|
||||||
#include "strv.h"
|
#include "strv.h"
|
||||||
@ -568,28 +569,142 @@ int device_get_devlink_priority(sd_device *device, int *priority) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int device_get_watch_handle(sd_device *device, int *handle) {
|
int device_get_watch_handle(sd_device *device) {
|
||||||
|
char path_wd[STRLEN("/run/udev/watch/") + DECIMAL_STR_MAX(int)];
|
||||||
|
_cleanup_free_ char *buf = NULL;
|
||||||
|
const char *id, *path_id;
|
||||||
|
int wd, r;
|
||||||
|
|
||||||
|
assert(device);
|
||||||
|
|
||||||
|
if (device->watch_handle >= 0)
|
||||||
|
return device->watch_handle;
|
||||||
|
|
||||||
|
r = device_get_device_id(device, &id);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
|
||||||
|
path_id = strjoina("/run/udev/watch/", id);
|
||||||
|
r = readlink_malloc(path_id, &buf);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
|
||||||
|
r = safe_atoi(buf, &wd);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
|
||||||
|
if (wd < 0)
|
||||||
|
return -EBADF;
|
||||||
|
|
||||||
|
buf = mfree(buf);
|
||||||
|
xsprintf(path_wd, "/run/udev/watch/%d", wd);
|
||||||
|
r = readlink_malloc(path_wd, &buf);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
|
||||||
|
if (!streq(buf, id))
|
||||||
|
return -EBADF;
|
||||||
|
|
||||||
|
return device->watch_handle = wd;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void device_remove_watch_handle(sd_device *device) {
|
||||||
|
const char *id;
|
||||||
|
int wd;
|
||||||
|
|
||||||
|
assert(device);
|
||||||
|
|
||||||
|
/* First, remove the symlink from handle to device id. */
|
||||||
|
wd = device_get_watch_handle(device);
|
||||||
|
if (wd >= 0) {
|
||||||
|
char path_wd[STRLEN("/run/udev/watch/") + DECIMAL_STR_MAX(int)];
|
||||||
|
|
||||||
|
xsprintf(path_wd, "/run/udev/watch/%d", wd);
|
||||||
|
if (unlink(path_wd) < 0 && errno != ENOENT)
|
||||||
|
log_device_debug_errno(device, errno,
|
||||||
|
"sd-device: failed to remove %s, ignoring: %m",
|
||||||
|
path_wd);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Next, remove the symlink from device id to handle. */
|
||||||
|
if (device_get_device_id(device, &id) >= 0) {
|
||||||
|
const char *path_id;
|
||||||
|
|
||||||
|
path_id = strjoina("/run/udev/watch/", id);
|
||||||
|
if (unlink(path_id) < 0 && errno != ENOENT)
|
||||||
|
log_device_debug_errno(device, errno,
|
||||||
|
"sd-device: failed to remove %s, ignoring: %m",
|
||||||
|
path_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
device->watch_handle = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int device_set_watch_handle(sd_device *device, int wd) {
|
||||||
|
char path_wd[STRLEN("/run/udev/watch/") + DECIMAL_STR_MAX(int)];
|
||||||
|
const char *id, *path_id;
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
assert(device);
|
assert(device);
|
||||||
|
|
||||||
r = device_read_db(device);
|
if (wd >= 0 && wd == device->watch_handle)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
device_remove_watch_handle(device);
|
||||||
|
|
||||||
|
if (wd < 0)
|
||||||
|
/* negative wd means that the caller requests to clear saved watch handle. */
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
r = device_get_device_id(device, &id);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
if (device->watch_handle < 0)
|
path_id = strjoina("/run/udev/watch/", id);
|
||||||
return -ENOENT;
|
xsprintf(path_wd, "/run/udev/watch/%d", wd);
|
||||||
|
|
||||||
if (handle)
|
r = mkdir_parents(path_wd, 0755);
|
||||||
*handle = device->watch_handle;
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
|
||||||
|
if (symlink(id, path_wd) < 0)
|
||||||
|
return -errno;
|
||||||
|
|
||||||
|
if (symlink(path_wd + STRLEN("/run/udev/watch/"), path_id) < 0) {
|
||||||
|
r = -errno;
|
||||||
|
if (unlink(path_wd) < 0 && errno != ENOENT)
|
||||||
|
log_device_debug_errno(device, errno,
|
||||||
|
"sd-device: failed to remove %s, ignoring: %m",
|
||||||
|
path_wd);
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
device->watch_handle = wd;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void device_set_watch_handle(sd_device *device, int handle) {
|
int device_new_from_watch_handle_at(sd_device **ret, int dirfd, int wd) {
|
||||||
assert(device);
|
char path_wd[STRLEN("/run/udev/watch/") + DECIMAL_STR_MAX(int)];
|
||||||
|
_cleanup_free_ char *id = NULL;
|
||||||
|
int r;
|
||||||
|
|
||||||
device->watch_handle = handle;
|
assert(ret);
|
||||||
|
|
||||||
|
if (wd < 0)
|
||||||
|
return -EBADF;
|
||||||
|
|
||||||
|
if (dirfd >= 0) {
|
||||||
|
xsprintf(path_wd, "%d", wd);
|
||||||
|
r = readlinkat_malloc(dirfd, path_wd, &id);
|
||||||
|
} else {
|
||||||
|
xsprintf(path_wd, "/run/udev/watch/%d", wd);
|
||||||
|
r = readlink_malloc(path_wd, &id);
|
||||||
|
}
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
|
||||||
|
return sd_device_new_from_device_id(ret, id);
|
||||||
}
|
}
|
||||||
|
|
||||||
int device_rename(sd_device *device, const char *name) {
|
int device_rename(sd_device *device, const char *name) {
|
||||||
@ -761,7 +876,7 @@ static int device_tag(sd_device *device, const char *tag, bool add) {
|
|||||||
assert(device);
|
assert(device);
|
||||||
assert(tag);
|
assert(tag);
|
||||||
|
|
||||||
r = device_get_id_filename(device, &id);
|
r = device_get_device_id(device, &id);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
@ -822,9 +937,6 @@ static bool device_has_info(sd_device *device) {
|
|||||||
if (!set_isempty(device->current_tags))
|
if (!set_isempty(device->current_tags))
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
if (device->watch_handle >= 0)
|
|
||||||
return true;
|
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -846,7 +958,7 @@ int device_update_db(sd_device *device) {
|
|||||||
|
|
||||||
has_info = device_has_info(device);
|
has_info = device_has_info(device);
|
||||||
|
|
||||||
r = device_get_id_filename(device, &id);
|
r = device_get_device_id(device, &id);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
@ -899,9 +1011,6 @@ int device_update_db(sd_device *device) {
|
|||||||
|
|
||||||
if (device->devlink_priority != 0)
|
if (device->devlink_priority != 0)
|
||||||
fprintf(f, "L:%i\n", device->devlink_priority);
|
fprintf(f, "L:%i\n", device->devlink_priority);
|
||||||
|
|
||||||
if (device->watch_handle >= 0)
|
|
||||||
fprintf(f, "W:%i\n", device->watch_handle);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (device->usec_initialized > 0)
|
if (device->usec_initialized > 0)
|
||||||
@ -950,7 +1059,7 @@ int device_delete_db(sd_device *device) {
|
|||||||
|
|
||||||
assert(device);
|
assert(device);
|
||||||
|
|
||||||
r = device_get_id_filename(device, &id);
|
r = device_get_device_id(device, &id);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
|
|||||||
@ -12,18 +12,22 @@
|
|||||||
|
|
||||||
int device_new_from_nulstr(sd_device **ret, uint8_t *nulstr, size_t len);
|
int device_new_from_nulstr(sd_device **ret, uint8_t *nulstr, size_t len);
|
||||||
int device_new_from_strv(sd_device **ret, char **strv);
|
int device_new_from_strv(sd_device **ret, char **strv);
|
||||||
|
int device_new_from_watch_handle_at(sd_device **ret, int dirfd, int wd);
|
||||||
|
static inline int device_new_from_watch_handle(sd_device **ret, int wd) {
|
||||||
|
return device_new_from_watch_handle_at(ret, -1, wd);
|
||||||
|
}
|
||||||
|
|
||||||
int device_get_id_filename(sd_device *device, const char **ret);
|
int device_get_device_id(sd_device *device, const char **ret);
|
||||||
|
|
||||||
int device_get_devlink_priority(sd_device *device, int *priority);
|
int device_get_devlink_priority(sd_device *device, int *priority);
|
||||||
int device_get_watch_handle(sd_device *device, int *handle);
|
int device_get_watch_handle(sd_device *device);
|
||||||
int device_get_devnode_mode(sd_device *device, mode_t *mode);
|
int device_get_devnode_mode(sd_device *device, mode_t *mode);
|
||||||
int device_get_devnode_uid(sd_device *device, uid_t *uid);
|
int device_get_devnode_uid(sd_device *device, uid_t *uid);
|
||||||
int device_get_devnode_gid(sd_device *device, gid_t *gid);
|
int device_get_devnode_gid(sd_device *device, gid_t *gid);
|
||||||
|
|
||||||
void device_seal(sd_device *device);
|
void device_seal(sd_device *device);
|
||||||
void device_set_is_initialized(sd_device *device);
|
void device_set_is_initialized(sd_device *device);
|
||||||
void device_set_watch_handle(sd_device *device, int fd);
|
int device_set_watch_handle(sd_device *device, int wd);
|
||||||
void device_set_db_persist(sd_device *device);
|
void device_set_db_persist(sd_device *device);
|
||||||
void device_set_devlink_priority(sd_device *device, int priority);
|
void device_set_devlink_priority(sd_device *device, int priority);
|
||||||
int device_ensure_usec_initialized(sd_device *device, sd_device *device_old);
|
int device_ensure_usec_initialized(sd_device *device, sd_device *device_old);
|
||||||
|
|||||||
@ -62,7 +62,7 @@ static sd_device *device_free(sd_device *device) {
|
|||||||
free(device->subsystem);
|
free(device->subsystem);
|
||||||
free(device->driver_subsystem);
|
free(device->driver_subsystem);
|
||||||
free(device->driver);
|
free(device->driver);
|
||||||
free(device->id_filename);
|
free(device->device_id);
|
||||||
free(device->properties_strv);
|
free(device->properties_strv);
|
||||||
free(device->properties_nulstr);
|
free(device->properties_nulstr);
|
||||||
|
|
||||||
@ -623,7 +623,7 @@ _public_ int sd_device_new_from_device_id(sd_device **ret, const char *id) {
|
|||||||
struct ifreq ifr = {};
|
struct ifreq ifr = {};
|
||||||
int ifindex;
|
int ifindex;
|
||||||
|
|
||||||
r = ifr.ifr_ifindex = parse_ifindex(&id[1]);
|
r = ifr.ifr_ifindex = parse_ifindex(id + 1);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
@ -652,15 +652,14 @@ _public_ int sd_device_new_from_device_id(sd_device **ret, const char *id) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
case '+': {
|
case '+': {
|
||||||
char subsys[PATH_MAX];
|
char subsys[NAME_MAX+1]; /* NAME_MAX does not include the trailing NUL. */
|
||||||
char *sysname;
|
const char *sysname;
|
||||||
|
|
||||||
(void) strscpy(subsys, sizeof(subsys), id + 1);
|
sysname = strchr(id + 1, ':');
|
||||||
sysname = strchr(subsys, ':');
|
|
||||||
if (!sysname)
|
if (!sysname)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
sysname[0] = '\0';
|
(void) strnscpy(subsys, sizeof(subsys), id + 1, sysname - id - 1);
|
||||||
sysname++;
|
sysname++;
|
||||||
|
|
||||||
return sd_device_new_from_subsystem_sysname(ret, subsys, sysname);
|
return sd_device_new_from_subsystem_sysname(ret, subsys, sysname);
|
||||||
@ -752,15 +751,34 @@ int device_set_subsystem(sd_device *device, const char *_subsystem) {
|
|||||||
return free_and_replace(device->subsystem, subsystem);
|
return free_and_replace(device->subsystem, subsystem);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int device_set_drivers_subsystem(sd_device *device, const char *_subsystem) {
|
static int device_set_drivers_subsystem(sd_device *device) {
|
||||||
_cleanup_free_ char *subsystem = NULL;
|
_cleanup_free_ char *subsystem = NULL;
|
||||||
|
const char *syspath, *drivers, *p;
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
assert(device);
|
assert(device);
|
||||||
assert(_subsystem);
|
|
||||||
assert(*_subsystem);
|
|
||||||
|
|
||||||
subsystem = strdup(_subsystem);
|
r = sd_device_get_syspath(device, &syspath);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
|
||||||
|
drivers = strstr(syspath, "/drivers/");
|
||||||
|
if (!drivers)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
for (p = drivers - 1; p >= syspath; p--)
|
||||||
|
if (*p == '/')
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (p <= syspath)
|
||||||
|
/* syspath does not start with /sys/ ?? */
|
||||||
|
return -EINVAL;
|
||||||
|
p++;
|
||||||
|
if (p >= drivers)
|
||||||
|
/* refuse duplicated slashes */
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
subsystem = strndup(p, drivers - p);
|
||||||
if (!subsystem)
|
if (!subsystem)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
@ -772,60 +790,46 @@ static int device_set_drivers_subsystem(sd_device *device, const char *_subsyste
|
|||||||
}
|
}
|
||||||
|
|
||||||
_public_ int sd_device_get_subsystem(sd_device *device, const char **ret) {
|
_public_ int sd_device_get_subsystem(sd_device *device, const char **ret) {
|
||||||
const char *syspath, *drivers = NULL;
|
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
assert_return(device, -EINVAL);
|
assert_return(device, -EINVAL);
|
||||||
|
|
||||||
r = sd_device_get_syspath(device, &syspath);
|
|
||||||
if (r < 0)
|
|
||||||
return r;
|
|
||||||
|
|
||||||
if (!device->subsystem_set) {
|
if (!device->subsystem_set) {
|
||||||
_cleanup_free_ char *subsystem = NULL;
|
_cleanup_free_ char *subsystem = NULL;
|
||||||
|
const char *syspath;
|
||||||
char *path;
|
char *path;
|
||||||
|
|
||||||
|
r = sd_device_get_syspath(device, &syspath);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
|
||||||
/* read 'subsystem' link */
|
/* read 'subsystem' link */
|
||||||
path = strjoina(syspath, "/subsystem");
|
path = strjoina(syspath, "/subsystem");
|
||||||
r = readlink_value(path, &subsystem);
|
r = readlink_value(path, &subsystem);
|
||||||
if (r >= 0)
|
if (r < 0 && r != -ENOENT)
|
||||||
|
return log_device_debug_errno(device, r,
|
||||||
|
"sd-device: Failed to read subsystem for %s: %m",
|
||||||
|
device->devpath);
|
||||||
|
|
||||||
|
if (subsystem)
|
||||||
r = device_set_subsystem(device, subsystem);
|
r = device_set_subsystem(device, subsystem);
|
||||||
/* use implicit names */
|
/* use implicit names */
|
||||||
else if (path_startswith(device->devpath, "/module/"))
|
else if (path_startswith(device->devpath, "/module/"))
|
||||||
r = device_set_subsystem(device, "module");
|
r = device_set_subsystem(device, "module");
|
||||||
else if (!(drivers = strstr(syspath, "/drivers/")) &&
|
else if (strstr(syspath, "/drivers/"))
|
||||||
PATH_STARTSWITH_SET(device->devpath, "/subsystem/",
|
r = device_set_drivers_subsystem(device);
|
||||||
|
else if (PATH_STARTSWITH_SET(device->devpath, "/subsystem/",
|
||||||
"/class/",
|
"/class/",
|
||||||
"/bus/"))
|
"/bus/"))
|
||||||
r = device_set_subsystem(device, "subsystem");
|
r = device_set_subsystem(device, "subsystem");
|
||||||
if (r < 0 && r != -ENOENT)
|
else {
|
||||||
return log_device_debug_errno(device, r, "sd-device: Failed to set subsystem for %s: %m", device->devpath);
|
device->subsystem_set = true;
|
||||||
|
r = 0;
|
||||||
device->subsystem_set = true;
|
|
||||||
} else if (!device->driver_subsystem_set)
|
|
||||||
drivers = strstr(syspath, "/drivers/");
|
|
||||||
|
|
||||||
if (!device->driver_subsystem_set) {
|
|
||||||
if (drivers) {
|
|
||||||
_cleanup_free_ char *subpath = NULL;
|
|
||||||
|
|
||||||
subpath = strndup(syspath, drivers - syspath);
|
|
||||||
if (!subpath)
|
|
||||||
r = -ENOMEM;
|
|
||||||
else {
|
|
||||||
const char *subsys;
|
|
||||||
|
|
||||||
subsys = strrchr(subpath, '/');
|
|
||||||
if (!subsys)
|
|
||||||
r = -EINVAL;
|
|
||||||
else
|
|
||||||
r = device_set_drivers_subsystem(device, subsys + 1);
|
|
||||||
}
|
|
||||||
if (r < 0 && r != -ENOENT)
|
|
||||||
return log_device_debug_errno(device, r, "sd-device: Failed to set subsystem for driver %s: %m", device->devpath);
|
|
||||||
}
|
}
|
||||||
|
if (r < 0)
|
||||||
device->driver_subsystem_set = true;
|
return log_device_debug_errno(device, r,
|
||||||
|
"sd-device: Failed to set subsystem for %s: %m",
|
||||||
|
device->devpath);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!device->subsystem)
|
if (!device->subsystem)
|
||||||
@ -987,7 +991,7 @@ _public_ int sd_device_get_devname(sd_device *device, const char **devname) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int device_set_sysname(sd_device *device) {
|
static int device_set_sysname_and_sysnum(sd_device *device) {
|
||||||
_cleanup_free_ char *sysname = NULL;
|
_cleanup_free_ char *sysname = NULL;
|
||||||
const char *sysnum = NULL;
|
const char *sysnum = NULL;
|
||||||
const char *pos;
|
const char *pos;
|
||||||
@ -1024,7 +1028,6 @@ static int device_set_sysname(sd_device *device) {
|
|||||||
if (len == 0)
|
if (len == 0)
|
||||||
sysnum = NULL;
|
sysnum = NULL;
|
||||||
|
|
||||||
device->sysname_set = true;
|
|
||||||
device->sysnum = sysnum;
|
device->sysnum = sysnum;
|
||||||
return free_and_replace(device->sysname, sysname);
|
return free_and_replace(device->sysname, sysname);
|
||||||
}
|
}
|
||||||
@ -1034,14 +1037,12 @@ _public_ int sd_device_get_sysname(sd_device *device, const char **ret) {
|
|||||||
|
|
||||||
assert_return(device, -EINVAL);
|
assert_return(device, -EINVAL);
|
||||||
|
|
||||||
if (!device->sysname_set) {
|
if (!device->sysname) {
|
||||||
r = device_set_sysname(device);
|
r = device_set_sysname_and_sysnum(device);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
assert_return(device->sysname, -ENOENT);
|
|
||||||
|
|
||||||
if (ret)
|
if (ret)
|
||||||
*ret = device->sysname;
|
*ret = device->sysname;
|
||||||
return 0;
|
return 0;
|
||||||
@ -1052,8 +1053,8 @@ _public_ int sd_device_get_sysnum(sd_device *device, const char **ret) {
|
|||||||
|
|
||||||
assert_return(device, -EINVAL);
|
assert_return(device, -EINVAL);
|
||||||
|
|
||||||
if (!device->sysname_set) {
|
if (!device->sysname) {
|
||||||
r = device_set_sysname(device);
|
r = device_set_sysname_and_sysnum(device);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
@ -1237,10 +1238,10 @@ static int handle_db_line(sd_device *device, char key, const char *value) {
|
|||||||
|
|
||||||
break;
|
break;
|
||||||
case 'W':
|
case 'W':
|
||||||
r = safe_atoi(value, &device->watch_handle);
|
/* Deprecated. Previously, watch handle is both saved in database and /run/udev/watch.
|
||||||
if (r < 0)
|
* However, the handle saved in database may not be updated when the handle is updated
|
||||||
return r;
|
* or removed. Moreover, it is not necessary to store the handle within the database,
|
||||||
|
* as its value becomes meaningless when udevd is restarted. */
|
||||||
break;
|
break;
|
||||||
case 'V':
|
case 'V':
|
||||||
r = safe_atou(value, &device->database_version);
|
r = safe_atou(value, &device->database_version);
|
||||||
@ -1255,11 +1256,11 @@ static int handle_db_line(sd_device *device, char key, const char *value) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int device_get_id_filename(sd_device *device, const char **ret) {
|
int device_get_device_id(sd_device *device, const char **ret) {
|
||||||
assert(device);
|
assert(device);
|
||||||
assert(ret);
|
assert(ret);
|
||||||
|
|
||||||
if (!device->id_filename) {
|
if (!device->device_id) {
|
||||||
_cleanup_free_ char *id = NULL;
|
_cleanup_free_ char *id = NULL;
|
||||||
const char *subsystem;
|
const char *subsystem;
|
||||||
dev_t devnum;
|
dev_t devnum;
|
||||||
@ -1296,7 +1297,6 @@ int device_get_id_filename(sd_device *device, const char **ret) {
|
|||||||
if (!subsystem)
|
if (!subsystem)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
|
|
||||||
if (streq(subsystem, "drivers"))
|
if (streq(subsystem, "drivers"))
|
||||||
/* the 'drivers' pseudo-subsystem is special, and needs the real subsystem
|
/* the 'drivers' pseudo-subsystem is special, and needs the real subsystem
|
||||||
* encoded as well */
|
* encoded as well */
|
||||||
@ -1307,10 +1307,13 @@ int device_get_id_filename(sd_device *device, const char **ret) {
|
|||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
}
|
}
|
||||||
|
|
||||||
device->id_filename = TAKE_PTR(id);
|
if (!filename_is_valid(id))
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
device->device_id = TAKE_PTR(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
*ret = device->id_filename;
|
*ret = device->device_id;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1407,7 +1410,7 @@ int device_read_db_internal(sd_device *device, bool force) {
|
|||||||
if (device->db_loaded || (!force && device->sealed))
|
if (device->db_loaded || (!force && device->sealed))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
r = device_get_id_filename(device, &id);
|
r = device_get_device_id(device, &id);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
|
|||||||
@ -52,7 +52,7 @@ int config_parse_can_bitrate(
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int link_up_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
|
static int link_set_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
assert(link);
|
assert(link);
|
||||||
@ -60,53 +60,24 @@ static int link_up_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link)
|
|||||||
if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
|
if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
r = sd_netlink_message_get_errno(m);
|
|
||||||
if (r < 0)
|
|
||||||
/* we warn but don't fail the link, as it may be brought up later */
|
|
||||||
log_link_message_warning_errno(link, m, r, "Could not bring up interface");
|
|
||||||
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int link_up_can(Link *link) {
|
|
||||||
_cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL;
|
|
||||||
int r;
|
|
||||||
|
|
||||||
assert(link);
|
|
||||||
|
|
||||||
log_link_debug(link, "Bringing CAN link up");
|
|
||||||
|
|
||||||
r = sd_rtnl_message_new_link(link->manager->rtnl, &req, RTM_SETLINK, link->ifindex);
|
|
||||||
if (r < 0)
|
|
||||||
return log_link_error_errno(link, r, "Could not allocate RTM_SETLINK message: %m");
|
|
||||||
|
|
||||||
r = sd_rtnl_message_link_set_flags(req, IFF_UP, IFF_UP);
|
|
||||||
if (r < 0)
|
|
||||||
return log_link_error_errno(link, r, "Could not set link flags: %m");
|
|
||||||
|
|
||||||
r = netlink_call_async(link->manager->rtnl, NULL, req, link_up_handler,
|
|
||||||
link_netlink_destroy_callback, link);
|
|
||||||
if (r < 0)
|
|
||||||
return log_link_error_errno(link, r, "Could not send rtnetlink message: %m");
|
|
||||||
|
|
||||||
link_ref(link);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int link_set_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
|
|
||||||
int r;
|
|
||||||
|
|
||||||
assert(link);
|
|
||||||
|
|
||||||
log_link_debug(link, "Set link");
|
|
||||||
|
|
||||||
r = sd_netlink_message_get_errno(m);
|
r = sd_netlink_message_get_errno(m);
|
||||||
if (r < 0 && r != -EEXIST) {
|
if (r < 0 && r != -EEXIST) {
|
||||||
log_link_message_warning_errno(link, m, r, "Failed to configure CAN link");
|
log_link_message_warning_errno(link, m, r, "Failed to configure CAN link");
|
||||||
link_enter_failed(link);
|
link_enter_failed(link);
|
||||||
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
log_link_debug(link, "Link set");
|
||||||
|
|
||||||
|
r = link_activate(link);
|
||||||
|
if (r < 0) {
|
||||||
|
link_enter_failed(link);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
link->can_configured = true;
|
||||||
|
link_check_ready(link);
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -255,9 +226,6 @@ static int link_set_can(Link *link) {
|
|||||||
|
|
||||||
link_ref(link);
|
link_ref(link);
|
||||||
|
|
||||||
if (!(link->flags & IFF_UP))
|
|
||||||
return link_up_can(link);
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -290,30 +258,21 @@ int link_configure_can(Link *link) {
|
|||||||
|
|
||||||
if (streq_ptr(link->kind, "can")) {
|
if (streq_ptr(link->kind, "can")) {
|
||||||
/* The CAN interface must be down to configure bitrate, etc... */
|
/* The CAN interface must be down to configure bitrate, etc... */
|
||||||
if ((link->flags & IFF_UP)) {
|
if ((link->flags & IFF_UP))
|
||||||
r = link_down(link, link_down_handler);
|
r = link_down(link, link_down_handler);
|
||||||
if (r < 0) {
|
else
|
||||||
link_enter_failed(link);
|
|
||||||
return r;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
r = link_set_can(link);
|
r = link_set_can(link);
|
||||||
if (r < 0) {
|
if (r < 0)
|
||||||
link_enter_failed(link);
|
|
||||||
return r;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!(link->flags & IFF_UP)) {
|
|
||||||
r = link_up_can(link);
|
|
||||||
if (r < 0) {
|
|
||||||
link_enter_failed(link);
|
link_enter_failed(link);
|
||||||
return r;
|
return r;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
r = link_activate(link);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
|
||||||
|
link->can_configured = true;
|
||||||
|
link_check_ready(link);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -764,6 +764,15 @@ void link_check_ready(Link *link) {
|
|||||||
if (!link->network)
|
if (!link->network)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
if (link->iftype == ARPHRD_CAN) {
|
||||||
|
/* let's shortcut things for CAN which doesn't need most of checks below. */
|
||||||
|
if (!link->can_configured)
|
||||||
|
return (void) log_link_debug(link, "%s(): CAN device is not configured.", __func__);
|
||||||
|
|
||||||
|
link_enter_configured(link);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (!link->addresses_configured)
|
if (!link->addresses_configured)
|
||||||
return (void) log_link_debug(link, "%s(): static addresses are not configured.", __func__);
|
return (void) log_link_debug(link, "%s(): static addresses are not configured.", __func__);
|
||||||
|
|
||||||
@ -1376,7 +1385,7 @@ static int link_up_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link)
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int link_up(Link *link) {
|
int link_up(Link *link) {
|
||||||
_cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL;
|
_cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL;
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
@ -1771,7 +1780,7 @@ static void link_drop(Link *link) {
|
|||||||
link_detach_from_manager(link);
|
link_detach_from_manager(link);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int link_joined(Link *link) {
|
int link_activate(Link *link) {
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
assert(link);
|
assert(link);
|
||||||
@ -1789,10 +1798,8 @@ static int link_joined(Link *link) {
|
|||||||
_fallthrough_;
|
_fallthrough_;
|
||||||
case ACTIVATION_POLICY_ALWAYS_UP:
|
case ACTIVATION_POLICY_ALWAYS_UP:
|
||||||
r = link_up(link);
|
r = link_up(link);
|
||||||
if (r < 0) {
|
if (r < 0)
|
||||||
link_enter_failed(link);
|
|
||||||
return r;
|
return r;
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
case ACTIVATION_POLICY_DOWN:
|
case ACTIVATION_POLICY_DOWN:
|
||||||
if (link->activated)
|
if (link->activated)
|
||||||
@ -1800,16 +1807,27 @@ static int link_joined(Link *link) {
|
|||||||
_fallthrough_;
|
_fallthrough_;
|
||||||
case ACTIVATION_POLICY_ALWAYS_DOWN:
|
case ACTIVATION_POLICY_ALWAYS_DOWN:
|
||||||
r = link_down(link, NULL);
|
r = link_down(link, NULL);
|
||||||
if (r < 0) {
|
if (r < 0)
|
||||||
link_enter_failed(link);
|
|
||||||
return r;
|
return r;
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
link->activated = true;
|
link->activated = true;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int link_joined(Link *link) {
|
||||||
|
int r;
|
||||||
|
|
||||||
|
assert(link);
|
||||||
|
assert(link->network);
|
||||||
|
|
||||||
|
r = link_activate(link);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
|
||||||
if (link->network->bridge) {
|
if (link->network->bridge) {
|
||||||
r = link_set_bridge(link);
|
r = link_set_bridge(link);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
@ -2076,6 +2094,7 @@ int link_configure(Link *link) {
|
|||||||
return r;
|
return r;
|
||||||
|
|
||||||
if (link->iftype == ARPHRD_CAN)
|
if (link->iftype == ARPHRD_CAN)
|
||||||
|
/* let's shortcut things for CAN which doesn't need most of what's done below. */
|
||||||
return link_configure_can(link);
|
return link_configure_can(link);
|
||||||
|
|
||||||
r = link_set_sysctl(link);
|
r = link_set_sysctl(link);
|
||||||
@ -2567,6 +2586,10 @@ static int link_carrier_gained(Link *link) {
|
|||||||
|
|
||||||
assert(link);
|
assert(link);
|
||||||
|
|
||||||
|
if (link->iftype == ARPHRD_CAN)
|
||||||
|
/* let's shortcut things for CAN which doesn't need most of what's done below. */
|
||||||
|
return link_handle_bound_by_list(link);
|
||||||
|
|
||||||
r = wifi_get_info(link);
|
r = wifi_get_info(link);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
@ -2625,6 +2648,10 @@ static int link_carrier_lost(Link *link) {
|
|||||||
if (link->network && link->network->ignore_carrier_loss)
|
if (link->network && link->network->ignore_carrier_loss)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
if (link->iftype == ARPHRD_CAN)
|
||||||
|
/* let's shortcut things for CAN which doesn't need most of what's done below. */
|
||||||
|
return link_handle_bound_by_list(link);
|
||||||
|
|
||||||
/* Some devices reset itself while setting the MTU. This causes the DHCP client fall into a loop.
|
/* Some devices reset itself while setting the MTU. This causes the DHCP client fall into a loop.
|
||||||
* setting_mtu keep track whether the device got reset because of setting MTU and does not drop the
|
* setting_mtu keep track whether the device got reset because of setting MTU and does not drop the
|
||||||
* configuration and stop the clients as well. */
|
* configuration and stop the clients as well. */
|
||||||
@ -2712,6 +2739,10 @@ static int link_admin_state_down(Link *link) {
|
|||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
if (link->network->activation_policy == ACTIVATION_POLICY_ALWAYS_UP) {
|
if (link->network->activation_policy == ACTIVATION_POLICY_ALWAYS_UP) {
|
||||||
|
if (streq_ptr(link->kind, "can") && !link->can_configured)
|
||||||
|
/* CAN device needs to be down on configure. */
|
||||||
|
return 0;
|
||||||
|
|
||||||
log_link_info(link, "ActivationPolicy is \"always-on\", forcing link up");
|
log_link_info(link, "ActivationPolicy is \"always-on\", forcing link up");
|
||||||
return link_up(link);
|
return link_up(link);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -131,6 +131,7 @@ typedef struct Link {
|
|||||||
bool setting_genmode:1;
|
bool setting_genmode:1;
|
||||||
bool ipv6_mtu_set:1;
|
bool ipv6_mtu_set:1;
|
||||||
bool bridge_mdb_configured:1;
|
bool bridge_mdb_configured:1;
|
||||||
|
bool can_configured:1;
|
||||||
bool activated:1;
|
bool activated:1;
|
||||||
|
|
||||||
sd_dhcp_server *dhcp_server;
|
sd_dhcp_server *dhcp_server;
|
||||||
@ -207,7 +208,9 @@ DEFINE_TRIVIAL_DESTRUCTOR(link_netlink_destroy_callback, Link, link_unref);
|
|||||||
|
|
||||||
int link_get(Manager *m, int ifindex, Link **ret);
|
int link_get(Manager *m, int ifindex, Link **ret);
|
||||||
|
|
||||||
|
int link_up(Link *link);
|
||||||
int link_down(Link *link, link_netlink_message_handler_t callback);
|
int link_down(Link *link, link_netlink_message_handler_t callback);
|
||||||
|
int link_activate(Link *link);
|
||||||
|
|
||||||
void link_enter_failed(Link *link);
|
void link_enter_failed(Link *link);
|
||||||
|
|
||||||
|
|||||||
@ -130,7 +130,7 @@ static int run(int argc, char *argv[]) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
udev_event_execute_rules(event, 3 * USEC_PER_SEC, SIGKILL, NULL, rules);
|
udev_event_execute_rules(event, -1, 3 * USEC_PER_SEC, SIGKILL, NULL, rules);
|
||||||
udev_event_execute_run(event, 3 * USEC_PER_SEC, SIGKILL);
|
udev_event_execute_run(event, 3 * USEC_PER_SEC, SIGKILL);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|||||||
@ -911,8 +911,9 @@ static int update_devnode(UdevEvent *event) {
|
|||||||
return udev_node_add(dev, apply_mac, event->mode, event->uid, event->gid, event->seclabel_list);
|
return udev_node_add(dev, apply_mac, event->mode, event->uid, event->gid, event->seclabel_list);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void event_execute_rules_on_remove(
|
static int event_execute_rules_on_remove(
|
||||||
UdevEvent *event,
|
UdevEvent *event,
|
||||||
|
int inotify_fd,
|
||||||
usec_t timeout_usec,
|
usec_t timeout_usec,
|
||||||
int timeout_signal,
|
int timeout_signal,
|
||||||
Hashmap *properties_list,
|
Hashmap *properties_list,
|
||||||
@ -933,13 +934,14 @@ static void event_execute_rules_on_remove(
|
|||||||
if (r < 0)
|
if (r < 0)
|
||||||
log_device_debug_errno(dev, r, "Failed to delete database under /run/udev/data/, ignoring: %m");
|
log_device_debug_errno(dev, r, "Failed to delete database under /run/udev/data/, ignoring: %m");
|
||||||
|
|
||||||
if (sd_device_get_devnum(dev, NULL) >= 0)
|
(void) udev_watch_end(inotify_fd, dev);
|
||||||
(void) udev_watch_end(dev);
|
|
||||||
|
|
||||||
(void) udev_rules_apply_to_event(rules, event, timeout_usec, timeout_signal, properties_list);
|
r = udev_rules_apply_to_event(rules, event, timeout_usec, timeout_signal, properties_list);
|
||||||
|
|
||||||
if (sd_device_get_devnum(dev, NULL) >= 0)
|
if (sd_device_get_devnum(dev, NULL) >= 0)
|
||||||
(void) udev_node_remove(dev);
|
(void) udev_node_remove(dev);
|
||||||
|
|
||||||
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int udev_event_on_move(sd_device *dev) {
|
static int udev_event_on_move(sd_device *dev) {
|
||||||
@ -971,12 +973,14 @@ static int copy_all_tags(sd_device *d, sd_device *s) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int udev_event_execute_rules(UdevEvent *event,
|
int udev_event_execute_rules(
|
||||||
usec_t timeout_usec,
|
UdevEvent *event,
|
||||||
int timeout_signal,
|
int inotify_fd, /* This may be negative */
|
||||||
Hashmap *properties_list,
|
usec_t timeout_usec,
|
||||||
UdevRules *rules) {
|
int timeout_signal,
|
||||||
const char *subsystem;
|
Hashmap *properties_list,
|
||||||
|
UdevRules *rules) {
|
||||||
|
|
||||||
sd_device_action_t action;
|
sd_device_action_t action;
|
||||||
sd_device *dev;
|
sd_device *dev;
|
||||||
int r;
|
int r;
|
||||||
@ -986,18 +990,15 @@ int udev_event_execute_rules(UdevEvent *event,
|
|||||||
|
|
||||||
dev = event->dev;
|
dev = event->dev;
|
||||||
|
|
||||||
r = sd_device_get_subsystem(dev, &subsystem);
|
|
||||||
if (r < 0)
|
|
||||||
return log_device_error_errno(dev, r, "Failed to get subsystem: %m");
|
|
||||||
|
|
||||||
r = sd_device_get_action(dev, &action);
|
r = sd_device_get_action(dev, &action);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return log_device_error_errno(dev, r, "Failed to get ACTION: %m");
|
return log_device_error_errno(dev, r, "Failed to get ACTION: %m");
|
||||||
|
|
||||||
if (action == SD_DEVICE_REMOVE) {
|
if (action == SD_DEVICE_REMOVE)
|
||||||
event_execute_rules_on_remove(event, timeout_usec, timeout_signal, properties_list, rules);
|
return event_execute_rules_on_remove(event, inotify_fd, timeout_usec, timeout_signal, properties_list, rules);
|
||||||
return 0;
|
|
||||||
}
|
/* Disable watch during event processing. */
|
||||||
|
(void) udev_watch_end(inotify_fd, event->dev);
|
||||||
|
|
||||||
r = device_clone_with_db(dev, &event->dev_db_clone);
|
r = device_clone_with_db(dev, &event->dev_db_clone);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
@ -1007,10 +1008,6 @@ int udev_event_execute_rules(UdevEvent *event,
|
|||||||
if (r < 0)
|
if (r < 0)
|
||||||
log_device_warning_errno(dev, r, "Failed to copy all tags from old database entry, ignoring: %m");
|
log_device_warning_errno(dev, r, "Failed to copy all tags from old database entry, ignoring: %m");
|
||||||
|
|
||||||
if (sd_device_get_devnum(dev, NULL) >= 0)
|
|
||||||
/* Disable watch during event processing. */
|
|
||||||
(void) udev_watch_end(event->dev_db_clone);
|
|
||||||
|
|
||||||
if (action == SD_DEVICE_MOVE) {
|
if (action == SD_DEVICE_MOVE) {
|
||||||
r = udev_event_on_move(event->dev);
|
r = udev_event_on_move(event->dev);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
@ -1048,11 +1045,7 @@ int udev_event_execute_rules(UdevEvent *event,
|
|||||||
/* Yes, we run update_devnode() twice, because in the first invocation, that is before update of udev database,
|
/* Yes, we run update_devnode() twice, because in the first invocation, that is before update of udev database,
|
||||||
* it could happen that two contenders are replacing each other's symlink. Hence we run it again to make sure
|
* it could happen that two contenders are replacing each other's symlink. Hence we run it again to make sure
|
||||||
* symlinks point to devices that claim them with the highest priority. */
|
* symlinks point to devices that claim them with the highest priority. */
|
||||||
r = update_devnode(event);
|
return update_devnode(event);
|
||||||
if (r < 0)
|
|
||||||
return r;
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void udev_event_execute_run(UdevEvent *event, usec_t timeout_usec, int timeout_signal) {
|
void udev_event_execute_run(UdevEvent *event, usec_t timeout_usec, int timeout_signal) {
|
||||||
@ -1087,3 +1080,24 @@ void udev_event_execute_run(UdevEvent *event, usec_t timeout_usec, int timeout_s
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int udev_event_process_inotify_watch(UdevEvent *event, int inotify_fd) {
|
||||||
|
sd_device *dev;
|
||||||
|
|
||||||
|
assert(event);
|
||||||
|
assert(inotify_fd >= 0);
|
||||||
|
|
||||||
|
dev = event->dev;
|
||||||
|
|
||||||
|
assert(dev);
|
||||||
|
|
||||||
|
if (device_for_action(dev, SD_DEVICE_REMOVE))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (event->inotify_watch)
|
||||||
|
(void) udev_watch_begin(inotify_fd, dev);
|
||||||
|
else
|
||||||
|
(void) udev_watch_end(inotify_fd, dev);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|||||||
@ -51,21 +51,30 @@ UdevEvent *udev_event_new(sd_device *dev, usec_t exec_delay_usec, sd_netlink *rt
|
|||||||
UdevEvent *udev_event_free(UdevEvent *event);
|
UdevEvent *udev_event_free(UdevEvent *event);
|
||||||
DEFINE_TRIVIAL_CLEANUP_FUNC(UdevEvent*, udev_event_free);
|
DEFINE_TRIVIAL_CLEANUP_FUNC(UdevEvent*, udev_event_free);
|
||||||
|
|
||||||
size_t udev_event_apply_format(UdevEvent *event,
|
size_t udev_event_apply_format(
|
||||||
const char *src, char *dest, size_t size,
|
UdevEvent *event,
|
||||||
bool replace_whitespace);
|
const char *src,
|
||||||
|
char *dest,
|
||||||
|
size_t size,
|
||||||
|
bool replace_whitespace);
|
||||||
int udev_check_format(const char *value, size_t *offset, const char **hint);
|
int udev_check_format(const char *value, size_t *offset, const char **hint);
|
||||||
int udev_event_spawn(UdevEvent *event,
|
int udev_event_spawn(
|
||||||
usec_t timeout_usec,
|
UdevEvent *event,
|
||||||
int timeout_signal,
|
usec_t timeout_usec,
|
||||||
bool accept_failure,
|
int timeout_signal,
|
||||||
const char *cmd, char *result, size_t ressize);
|
bool accept_failure,
|
||||||
int udev_event_execute_rules(UdevEvent *event,
|
const char *cmd,
|
||||||
usec_t timeout_usec,
|
char *result,
|
||||||
int timeout_signal,
|
size_t ressize);
|
||||||
Hashmap *properties_list,
|
int udev_event_execute_rules(
|
||||||
UdevRules *rules);
|
UdevEvent *event,
|
||||||
|
int inotify_fd,
|
||||||
|
usec_t timeout_usec,
|
||||||
|
int timeout_signal,
|
||||||
|
Hashmap *properties_list,
|
||||||
|
UdevRules *rules);
|
||||||
void udev_event_execute_run(UdevEvent *event, usec_t timeout_usec, int timeout_signal);
|
void udev_event_execute_run(UdevEvent *event, usec_t timeout_usec, int timeout_signal);
|
||||||
|
int udev_event_process_inotify_watch(UdevEvent *event, int inotify_fd);
|
||||||
|
|
||||||
static inline usec_t udev_warn_timeout(usec_t timeout_usec) {
|
static inline usec_t udev_warn_timeout(usec_t timeout_usec) {
|
||||||
return DIV_ROUND_UP(timeout_usec, 3);
|
return DIV_ROUND_UP(timeout_usec, 3);
|
||||||
|
|||||||
@ -30,7 +30,7 @@
|
|||||||
|
|
||||||
static int node_symlink(sd_device *dev, const char *node, const char *slink) {
|
static int node_symlink(sd_device *dev, const char *node, const char *slink) {
|
||||||
_cleanup_free_ char *slink_dirname = NULL, *target = NULL;
|
_cleanup_free_ char *slink_dirname = NULL, *target = NULL;
|
||||||
const char *id_filename, *slink_tmp;
|
const char *id, *slink_tmp;
|
||||||
struct stat stats;
|
struct stat stats;
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
@ -81,10 +81,10 @@ static int node_symlink(sd_device *dev, const char *node, const char *slink) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
log_device_debug(dev, "Atomically replace '%s'", slink);
|
log_device_debug(dev, "Atomically replace '%s'", slink);
|
||||||
r = device_get_id_filename(dev, &id_filename);
|
r = device_get_device_id(dev, &id);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return log_device_error_errno(dev, r, "Failed to get id_filename: %m");
|
return log_device_error_errno(dev, r, "Failed to get device id: %m");
|
||||||
slink_tmp = strjoina(slink, ".tmp-", id_filename);
|
slink_tmp = strjoina(slink, ".tmp-", id);
|
||||||
(void) unlink(slink_tmp);
|
(void) unlink(slink_tmp);
|
||||||
do {
|
do {
|
||||||
r = mkdir_parents_label(slink_tmp, 0755);
|
r = mkdir_parents_label(slink_tmp, 0755);
|
||||||
@ -147,7 +147,7 @@ static int link_find_prioritized(sd_device *dev, bool add, const char *stackdir,
|
|||||||
|
|
||||||
FOREACH_DIRENT_ALL(dent, dir, break) {
|
FOREACH_DIRENT_ALL(dent, dir, break) {
|
||||||
_cleanup_(sd_device_unrefp) sd_device *dev_db = NULL;
|
_cleanup_(sd_device_unrefp) sd_device *dev_db = NULL;
|
||||||
const char *devnode, *id_filename;
|
const char *devnode, *id;
|
||||||
int db_prio = 0;
|
int db_prio = 0;
|
||||||
|
|
||||||
if (dent->d_name[0] == '\0')
|
if (dent->d_name[0] == '\0')
|
||||||
@ -157,11 +157,11 @@ static int link_find_prioritized(sd_device *dev, bool add, const char *stackdir,
|
|||||||
|
|
||||||
log_device_debug(dev, "Found '%s' claiming '%s'", dent->d_name, stackdir);
|
log_device_debug(dev, "Found '%s' claiming '%s'", dent->d_name, stackdir);
|
||||||
|
|
||||||
if (device_get_id_filename(dev, &id_filename) < 0)
|
if (device_get_device_id(dev, &id) < 0)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
/* did we find ourself? */
|
/* did we find ourself? */
|
||||||
if (streq(dent->d_name, id_filename))
|
if (streq(dent->d_name, id))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (sd_device_new_from_device_id(&dev_db, dent->d_name) < 0)
|
if (sd_device_new_from_device_id(&dev_db, dent->d_name) < 0)
|
||||||
@ -229,21 +229,21 @@ static size_t escape_path(const char *src, char *dest, size_t size) {
|
|||||||
static int link_update(sd_device *dev, const char *slink, bool add) {
|
static int link_update(sd_device *dev, const char *slink, bool add) {
|
||||||
_cleanup_free_ char *filename = NULL, *dirname = NULL;
|
_cleanup_free_ char *filename = NULL, *dirname = NULL;
|
||||||
char name_enc[PATH_MAX];
|
char name_enc[PATH_MAX];
|
||||||
const char *id_filename;
|
const char *id;
|
||||||
int i, r, retries;
|
int i, r, retries;
|
||||||
|
|
||||||
assert(dev);
|
assert(dev);
|
||||||
assert(slink);
|
assert(slink);
|
||||||
|
|
||||||
r = device_get_id_filename(dev, &id_filename);
|
r = device_get_device_id(dev, &id);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return log_device_debug_errno(dev, r, "Failed to get id_filename: %m");
|
return log_device_debug_errno(dev, r, "Failed to get device id: %m");
|
||||||
|
|
||||||
escape_path(slink + STRLEN("/dev"), name_enc, sizeof(name_enc));
|
escape_path(slink + STRLEN("/dev"), name_enc, sizeof(name_enc));
|
||||||
dirname = path_join("/run/udev/links/", name_enc);
|
dirname = path_join("/run/udev/links/", name_enc);
|
||||||
if (!dirname)
|
if (!dirname)
|
||||||
return log_oom();
|
return log_oom();
|
||||||
filename = path_join(dirname, id_filename);
|
filename = path_join(dirname, id);
|
||||||
if (!filename)
|
if (!filename)
|
||||||
return log_oom();
|
return log_oom();
|
||||||
|
|
||||||
@ -348,7 +348,7 @@ int udev_node_update_old_links(sd_device *dev, sd_device *dev_old) {
|
|||||||
static int node_permissions_apply(sd_device *dev, bool apply_mac,
|
static int node_permissions_apply(sd_device *dev, bool apply_mac,
|
||||||
mode_t mode, uid_t uid, gid_t gid,
|
mode_t mode, uid_t uid, gid_t gid,
|
||||||
OrderedHashmap *seclabel_list) {
|
OrderedHashmap *seclabel_list) {
|
||||||
const char *devnode, *subsystem, *id_filename = NULL;
|
const char *devnode, *subsystem, *id = NULL;
|
||||||
bool apply_mode, apply_uid, apply_gid;
|
bool apply_mode, apply_uid, apply_gid;
|
||||||
_cleanup_close_ int node_fd = -1;
|
_cleanup_close_ int node_fd = -1;
|
||||||
struct stat stats;
|
struct stat stats;
|
||||||
@ -366,7 +366,7 @@ static int node_permissions_apply(sd_device *dev, bool apply_mac,
|
|||||||
r = sd_device_get_devnum(dev, &devnum);
|
r = sd_device_get_devnum(dev, &devnum);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return log_device_debug_errno(dev, r, "Failed to get devnum: %m");
|
return log_device_debug_errno(dev, r, "Failed to get devnum: %m");
|
||||||
(void) device_get_id_filename(dev, &id_filename);
|
(void) device_get_device_id(dev, &id);
|
||||||
|
|
||||||
if (streq(subsystem, "block"))
|
if (streq(subsystem, "block"))
|
||||||
mode |= S_IFBLK;
|
mode |= S_IFBLK;
|
||||||
@ -388,7 +388,7 @@ static int node_permissions_apply(sd_device *dev, bool apply_mac,
|
|||||||
|
|
||||||
if ((mode != MODE_INVALID && (stats.st_mode & S_IFMT) != (mode & S_IFMT)) || stats.st_rdev != devnum) {
|
if ((mode != MODE_INVALID && (stats.st_mode & S_IFMT) != (mode & S_IFMT)) || stats.st_rdev != devnum) {
|
||||||
log_device_debug(dev, "Found node '%s' with non-matching devnum %s, skipping handling.",
|
log_device_debug(dev, "Found node '%s' with non-matching devnum %s, skipping handling.",
|
||||||
devnode, id_filename);
|
devnode, strna(id));
|
||||||
return 0; /* We might process a device that already got replaced by the time we have a look
|
return 0; /* We might process a device that already got replaced by the time we have a look
|
||||||
* at it, handle this gracefully and step away. */
|
* at it, handle this gracefully and step away. */
|
||||||
}
|
}
|
||||||
@ -509,10 +509,10 @@ int udev_node_add(sd_device *dev, bool apply,
|
|||||||
return log_device_debug_errno(dev, r, "Failed to get devnode: %m");
|
return log_device_debug_errno(dev, r, "Failed to get devnode: %m");
|
||||||
|
|
||||||
if (DEBUG_LOGGING) {
|
if (DEBUG_LOGGING) {
|
||||||
const char *id_filename = NULL;
|
const char *id = NULL;
|
||||||
|
|
||||||
(void) device_get_id_filename(dev, &id_filename);
|
(void) device_get_device_id(dev, &id);
|
||||||
log_device_debug(dev, "Handling device node '%s', devnum=%s", devnode, strnull(id_filename));
|
log_device_debug(dev, "Handling device node '%s', devnum=%s", devnode, strna(id));
|
||||||
}
|
}
|
||||||
|
|
||||||
r = node_permissions_apply(dev, apply, mode, uid, gid, seclabel_list);
|
r = node_permissions_apply(dev, apply, mode, uid, gid, seclabel_list);
|
||||||
|
|||||||
@ -5,72 +5,60 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include <sys/inotify.h>
|
#include <sys/inotify.h>
|
||||||
#include <unistd.h>
|
|
||||||
|
|
||||||
#include "alloc-util.h"
|
#include "alloc-util.h"
|
||||||
#include "device-private.h"
|
#include "device-private.h"
|
||||||
#include "device-util.h"
|
#include "device-util.h"
|
||||||
#include "dirent-util.h"
|
#include "dirent-util.h"
|
||||||
#include "fs-util.h"
|
#include "fs-util.h"
|
||||||
#include "mkdir.h"
|
#include "parse-util.h"
|
||||||
#include "stdio-util.h"
|
|
||||||
#include "udev-watch.h"
|
#include "udev-watch.h"
|
||||||
|
|
||||||
static int inotify_fd = -1;
|
int udev_watch_restore(int inotify_fd) {
|
||||||
|
|
||||||
/* inotify descriptor, will be shared with rules directory;
|
|
||||||
* set to cloexec since we need our children to be able to add
|
|
||||||
* watches for us. */
|
|
||||||
int udev_watch_init(void) {
|
|
||||||
inotify_fd = inotify_init1(IN_CLOEXEC);
|
|
||||||
if (inotify_fd < 0)
|
|
||||||
return -errno;
|
|
||||||
|
|
||||||
return inotify_fd;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Move any old watches directory out of the way, and then restore the watches. */
|
|
||||||
int udev_watch_restore(void) {
|
|
||||||
struct dirent *ent;
|
struct dirent *ent;
|
||||||
DIR *dir;
|
DIR *dir;
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
if (inotify_fd < 0)
|
/* Move any old watches directory out of the way, and then restore the watches. */
|
||||||
return log_debug_errno(SYNTHETIC_ERRNO(EINVAL),
|
|
||||||
"Invalid inotify descriptor.");
|
assert(inotify_fd >= 0);
|
||||||
|
|
||||||
if (rename("/run/udev/watch", "/run/udev/watch.old") < 0) {
|
if (rename("/run/udev/watch", "/run/udev/watch.old") < 0) {
|
||||||
if (errno != ENOENT)
|
if (errno != ENOENT)
|
||||||
return log_warning_errno(errno, "Failed to move watches directory /run/udev/watch. Old watches will not be restored: %m");
|
return log_warning_errno(errno, "Failed to move watches directory /run/udev/watch. "
|
||||||
|
"Old watches will not be restored: %m");
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
dir = opendir("/run/udev/watch.old");
|
dir = opendir("/run/udev/watch.old");
|
||||||
if (!dir)
|
if (!dir)
|
||||||
return log_warning_errno(errno, "Failed to open old watches directory /run/udev/watch.old. Old watches will not be restored: %m");
|
return log_warning_errno(errno, "Failed to open old watches directory /run/udev/watch.old. "
|
||||||
|
"Old watches will not be restored: %m");
|
||||||
|
|
||||||
FOREACH_DIRENT_ALL(ent, dir, break) {
|
FOREACH_DIRENT_ALL(ent, dir, break) {
|
||||||
_cleanup_(sd_device_unrefp) sd_device *dev = NULL;
|
_cleanup_(sd_device_unrefp) sd_device *dev = NULL;
|
||||||
_cleanup_free_ char *device = NULL;
|
int wd;
|
||||||
|
|
||||||
if (ent->d_name[0] == '.')
|
if (ent->d_name[0] == '.')
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
r = readlinkat_malloc(dirfd(dir), ent->d_name, &device);
|
/* For backward compatibility, read symlink from watch handle to device id, and ignore
|
||||||
if (r < 0) {
|
* the opposite direction symlink. */
|
||||||
log_debug_errno(r, "Failed to read link '/run/udev/watch.old/%s', ignoring: %m", ent->d_name);
|
|
||||||
goto unlink;
|
|
||||||
}
|
|
||||||
|
|
||||||
r = sd_device_new_from_device_id(&dev, device);
|
if (safe_atoi(ent->d_name, &wd) < 0)
|
||||||
|
goto unlink;
|
||||||
|
|
||||||
|
r = device_new_from_watch_handle_at(&dev, dirfd(dir), wd);
|
||||||
if (r < 0) {
|
if (r < 0) {
|
||||||
log_debug_errno(r, "Failed to create sd_device object for '%s', ignoring: %m", device);
|
log_full_errno(r == -ENODEV ? LOG_DEBUG : LOG_WARNING, r,
|
||||||
|
"Failed to create sd_device object from saved watch handle '%s', ignoring: %m",
|
||||||
|
ent->d_name);
|
||||||
goto unlink;
|
goto unlink;
|
||||||
}
|
}
|
||||||
|
|
||||||
log_device_debug(dev, "Restoring old watch");
|
log_device_debug(dev, "Restoring old watch");
|
||||||
(void) udev_watch_begin(dev);
|
(void) udev_watch_begin(inotify_fd, dev);
|
||||||
unlink:
|
unlink:
|
||||||
(void) unlinkat(dirfd(dir), ent->d_name, 0);
|
(void) unlinkat(dirfd(dir), ent->d_name, 0);
|
||||||
}
|
}
|
||||||
@ -81,94 +69,54 @@ unlink:
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int udev_watch_begin(sd_device *dev) {
|
int udev_watch_begin(int inotify_fd, sd_device *dev) {
|
||||||
char filename[STRLEN("/run/udev/watch/") + DECIMAL_STR_MAX(int)];
|
const char *devnode;
|
||||||
const char *devnode, *id_filename;
|
|
||||||
int wd, r;
|
int wd, r;
|
||||||
|
|
||||||
if (inotify_fd < 0)
|
assert(inotify_fd >= 0);
|
||||||
return log_debug_errno(SYNTHETIC_ERRNO(EINVAL),
|
assert(dev);
|
||||||
"Invalid inotify descriptor.");
|
|
||||||
|
|
||||||
r = sd_device_get_devname(dev, &devnode);
|
r = sd_device_get_devname(dev, &devnode);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return log_device_error_errno(dev, r, "Failed to get device name: %m");
|
return log_device_debug_errno(dev, r, "Failed to get device name: %m");
|
||||||
|
|
||||||
log_device_debug(dev, "Adding watch on '%s'", devnode);
|
log_device_debug(dev, "Adding watch on '%s'", devnode);
|
||||||
wd = inotify_add_watch(inotify_fd, devnode, IN_CLOSE_WRITE);
|
wd = inotify_add_watch(inotify_fd, devnode, IN_CLOSE_WRITE);
|
||||||
if (wd < 0)
|
if (wd < 0) {
|
||||||
return log_device_full_errno(dev, errno == ENOENT ? LOG_DEBUG : LOG_ERR, errno,
|
r = log_device_full_errno(dev, errno == ENOENT ? LOG_DEBUG : LOG_WARNING,
|
||||||
"Failed to add device '%s' to watch: %m", devnode);
|
errno, "Failed to add device '%s' to watch: %m", devnode);
|
||||||
|
|
||||||
device_set_watch_handle(dev, wd);
|
(void) device_set_watch_handle(dev, -1);
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
xsprintf(filename, "/run/udev/watch/%d", wd);
|
r = device_set_watch_handle(dev, wd);
|
||||||
r = mkdir_parents(filename, 0755);
|
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return log_device_error_errno(dev, r, "Failed to create parent directory of '%s': %m", filename);
|
return log_device_warning_errno(dev, r, "Failed to save watch handle in /run/udev/watch: %m");
|
||||||
(void) unlink(filename);
|
|
||||||
|
|
||||||
r = device_get_id_filename(dev, &id_filename);
|
|
||||||
if (r < 0)
|
|
||||||
return log_device_error_errno(dev, r, "Failed to get device id-filename: %m");
|
|
||||||
|
|
||||||
if (symlink(id_filename, filename) < 0)
|
|
||||||
return log_device_error_errno(dev, errno, "Failed to create symlink %s: %m", filename);
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int udev_watch_end(sd_device *dev) {
|
int udev_watch_end(int inotify_fd, sd_device *dev) {
|
||||||
char filename[STRLEN("/run/udev/watch/") + DECIMAL_STR_MAX(int)];
|
int wd;
|
||||||
int wd, r;
|
|
||||||
|
|
||||||
|
assert(dev);
|
||||||
|
|
||||||
|
/* This may be called by 'udevadm test'. In that case, inotify_fd is not initialized. */
|
||||||
if (inotify_fd < 0)
|
if (inotify_fd < 0)
|
||||||
return 0; /* Nothing to do. */
|
|
||||||
|
|
||||||
r = device_get_watch_handle(dev, &wd);
|
|
||||||
if (r == -ENOENT)
|
|
||||||
return 0;
|
return 0;
|
||||||
if (r < 0)
|
|
||||||
return log_device_debug_errno(dev, r, "Failed to get watch handle, ignoring: %m");
|
|
||||||
|
|
||||||
log_device_debug(dev, "Removing watch");
|
if (sd_device_get_devname(dev, NULL) < 0)
|
||||||
(void) inotify_rm_watch(inotify_fd, wd);
|
return 0;
|
||||||
|
|
||||||
xsprintf(filename, "/run/udev/watch/%d", wd);
|
wd = device_get_watch_handle(dev);
|
||||||
(void) unlink(filename);
|
if (wd < 0)
|
||||||
|
log_device_debug_errno(dev, wd, "Failed to get watch handle, ignoring: %m");
|
||||||
device_set_watch_handle(dev, -1);
|
else {
|
||||||
|
log_device_debug(dev, "Removing watch");
|
||||||
|
(void) inotify_rm_watch(inotify_fd, wd);
|
||||||
|
}
|
||||||
|
(void) device_set_watch_handle(dev, -1);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int udev_watch_lookup(int wd, sd_device **ret) {
|
|
||||||
char filename[STRLEN("/run/udev/watch/") + DECIMAL_STR_MAX(int)];
|
|
||||||
_cleanup_free_ char *device = NULL;
|
|
||||||
int r;
|
|
||||||
|
|
||||||
assert(ret);
|
|
||||||
|
|
||||||
if (inotify_fd < 0)
|
|
||||||
return log_debug_errno(SYNTHETIC_ERRNO(EINVAL),
|
|
||||||
"Invalid inotify descriptor.");
|
|
||||||
|
|
||||||
if (wd < 0)
|
|
||||||
return log_debug_errno(SYNTHETIC_ERRNO(EINVAL),
|
|
||||||
"Invalid watch handle.");
|
|
||||||
|
|
||||||
xsprintf(filename, "/run/udev/watch/%d", wd);
|
|
||||||
r = readlink_malloc(filename, &device);
|
|
||||||
if (r == -ENOENT)
|
|
||||||
return 0;
|
|
||||||
if (r < 0)
|
|
||||||
return log_debug_errno(r, "Failed to read link '%s': %m", filename);
|
|
||||||
|
|
||||||
r = sd_device_new_from_device_id(ret, device);
|
|
||||||
if (r == -ENODEV)
|
|
||||||
return 0;
|
|
||||||
if (r < 0)
|
|
||||||
return log_debug_errno(r, "Failed to create sd_device object for '%s': %m", device);
|
|
||||||
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|||||||
@ -3,8 +3,6 @@
|
|||||||
|
|
||||||
#include "sd-device.h"
|
#include "sd-device.h"
|
||||||
|
|
||||||
int udev_watch_init(void);
|
int udev_watch_restore(int inotify_fd);
|
||||||
int udev_watch_restore(void);
|
int udev_watch_begin(int inotify_fd, sd_device *dev);
|
||||||
int udev_watch_begin(sd_device *dev);
|
int udev_watch_end(int inotify_fd, sd_device *dev);
|
||||||
int udev_watch_end(sd_device *dev);
|
|
||||||
int udev_watch_lookup(int wd, sd_device **ret);
|
|
||||||
|
|||||||
@ -141,7 +141,7 @@ int test_main(int argc, char *argv[], void *userdata) {
|
|||||||
assert_se(sigfillset(&mask) >= 0);
|
assert_se(sigfillset(&mask) >= 0);
|
||||||
assert_se(sigprocmask(SIG_SETMASK, &mask, &sigmask_orig) >= 0);
|
assert_se(sigprocmask(SIG_SETMASK, &mask, &sigmask_orig) >= 0);
|
||||||
|
|
||||||
udev_event_execute_rules(event, 60 * USEC_PER_SEC, SIGKILL, NULL, rules);
|
udev_event_execute_rules(event, -1, 60 * USEC_PER_SEC, SIGKILL, NULL, rules);
|
||||||
|
|
||||||
FOREACH_DEVICE_PROPERTY(dev, key, value)
|
FOREACH_DEVICE_PROPERTY(dev, key, value)
|
||||||
printf("%s=%s\n", key, value);
|
printf("%s=%s\n", key, value);
|
||||||
|
|||||||
@ -92,10 +92,12 @@ typedef struct Manager {
|
|||||||
|
|
||||||
sd_device_monitor *monitor;
|
sd_device_monitor *monitor;
|
||||||
struct udev_ctrl *ctrl;
|
struct udev_ctrl *ctrl;
|
||||||
int fd_inotify;
|
|
||||||
int worker_watch[2];
|
int worker_watch[2];
|
||||||
|
|
||||||
|
/* used by udev-watch */
|
||||||
|
int inotify_fd;
|
||||||
sd_event_source *inotify_event;
|
sd_event_source *inotify_event;
|
||||||
|
|
||||||
sd_event_source *kill_workers_event;
|
sd_event_source *kill_workers_event;
|
||||||
|
|
||||||
usec_t last_usec;
|
usec_t last_usec;
|
||||||
@ -304,7 +306,7 @@ static Manager* manager_free(Manager *manager) {
|
|||||||
hashmap_free_free_free(manager->properties);
|
hashmap_free_free_free(manager->properties);
|
||||||
udev_rules_free(manager->rules);
|
udev_rules_free(manager->rules);
|
||||||
|
|
||||||
safe_close(manager->fd_inotify);
|
safe_close(manager->inotify_fd);
|
||||||
safe_close_pair(manager->worker_watch);
|
safe_close_pair(manager->worker_watch);
|
||||||
|
|
||||||
return mfree(manager);
|
return mfree(manager);
|
||||||
@ -473,7 +475,7 @@ static int worker_process_device(Manager *manager, sd_device *dev) {
|
|||||||
* degree — they go hand-in-hand after all. */
|
* degree — they go hand-in-hand after all. */
|
||||||
|
|
||||||
log_device_debug(dev, "Block device is currently locked, installing watch to wait until the lock is released.");
|
log_device_debug(dev, "Block device is currently locked, installing watch to wait until the lock is released.");
|
||||||
(void) udev_watch_begin(dev);
|
(void) udev_watch_begin(manager->inotify_fd, dev);
|
||||||
|
|
||||||
/* Now the watch is installed, let's lock the device again, maybe in the meantime things changed */
|
/* Now the watch is installed, let's lock the device again, maybe in the meantime things changed */
|
||||||
r = worker_lock_block_device(dev, &fd_lock);
|
r = worker_lock_block_device(dev, &fd_lock);
|
||||||
@ -484,7 +486,13 @@ static int worker_process_device(Manager *manager, sd_device *dev) {
|
|||||||
(void) worker_mark_block_device_read_only(dev);
|
(void) worker_mark_block_device_read_only(dev);
|
||||||
|
|
||||||
/* apply rules, create node, symlinks */
|
/* apply rules, create node, symlinks */
|
||||||
r = udev_event_execute_rules(udev_event, arg_event_timeout_usec, arg_timeout_signal, manager->properties, manager->rules);
|
r = udev_event_execute_rules(
|
||||||
|
udev_event,
|
||||||
|
manager->inotify_fd,
|
||||||
|
arg_event_timeout_usec,
|
||||||
|
arg_timeout_signal,
|
||||||
|
manager->properties,
|
||||||
|
manager->rules);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
@ -494,14 +502,9 @@ static int worker_process_device(Manager *manager, sd_device *dev) {
|
|||||||
/* in case rtnl was initialized */
|
/* in case rtnl was initialized */
|
||||||
manager->rtnl = sd_netlink_ref(udev_event->rtnl);
|
manager->rtnl = sd_netlink_ref(udev_event->rtnl);
|
||||||
|
|
||||||
/* apply/restore/end inotify watch */
|
r = udev_event_process_inotify_watch(udev_event, manager->inotify_fd);
|
||||||
if (udev_event->inotify_watch) {
|
if (r < 0)
|
||||||
(void) udev_watch_begin(dev);
|
return r;
|
||||||
r = device_update_db(dev);
|
|
||||||
if (r < 0)
|
|
||||||
return log_device_debug_errno(dev, r, "Failed to update database under /run/udev/data/: %m");
|
|
||||||
} else
|
|
||||||
(void) udev_watch_end(dev);
|
|
||||||
|
|
||||||
log_device_uevent(dev, "Device processed");
|
log_device_uevent(dev, "Device processed");
|
||||||
return 0;
|
return 0;
|
||||||
@ -872,7 +875,7 @@ static void manager_exit(Manager *manager) {
|
|||||||
manager->ctrl = udev_ctrl_unref(manager->ctrl);
|
manager->ctrl = udev_ctrl_unref(manager->ctrl);
|
||||||
|
|
||||||
manager->inotify_event = sd_event_source_unref(manager->inotify_event);
|
manager->inotify_event = sd_event_source_unref(manager->inotify_event);
|
||||||
manager->fd_inotify = safe_close(manager->fd_inotify);
|
manager->inotify_fd = safe_close(manager->inotify_fd);
|
||||||
|
|
||||||
manager->monitor = sd_device_monitor_unref(manager->monitor);
|
manager->monitor = sd_device_monitor_unref(manager->monitor);
|
||||||
|
|
||||||
@ -1299,17 +1302,21 @@ static int on_inotify(sd_event_source *s, int fd, uint32_t revents, void *userda
|
|||||||
_cleanup_(sd_device_unrefp) sd_device *dev = NULL;
|
_cleanup_(sd_device_unrefp) sd_device *dev = NULL;
|
||||||
const char *devnode;
|
const char *devnode;
|
||||||
|
|
||||||
if (udev_watch_lookup(e->wd, &dev) <= 0)
|
r = device_new_from_watch_handle(&dev, e->wd);
|
||||||
|
if (r < 0) {
|
||||||
|
log_debug_errno(r, "Failed to create sd_device object from watch handle, ignoring: %m");
|
||||||
continue;
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
if (sd_device_get_devname(dev, &devnode) < 0)
|
if (sd_device_get_devname(dev, &devnode) < 0)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
log_device_debug(dev, "Inotify event: %x for %s", e->mask, devnode);
|
log_device_debug(dev, "Inotify event: %x for %s", e->mask, devnode);
|
||||||
if (e->mask & IN_CLOSE_WRITE)
|
if (e->mask & IN_CLOSE_WRITE)
|
||||||
synthesize_change(dev);
|
(void) synthesize_change(dev);
|
||||||
else if (e->mask & IN_IGNORED)
|
|
||||||
udev_watch_end(dev);
|
/* Do not handle IN_IGNORED here. It should be handled by worker in 'remove' uevent;
|
||||||
|
* udev_event_execute_rules() -> event_execute_rules_on_remove() -> udev_watch_end(). */
|
||||||
}
|
}
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
@ -1669,7 +1676,7 @@ static int manager_new(Manager **ret, int fd_ctrl, int fd_uevent, const char *cg
|
|||||||
return log_oom();
|
return log_oom();
|
||||||
|
|
||||||
*manager = (Manager) {
|
*manager = (Manager) {
|
||||||
.fd_inotify = -1,
|
.inotify_fd = -1,
|
||||||
.worker_watch = { -1, -1 },
|
.worker_watch = { -1, -1 },
|
||||||
.cgroup = cgroup,
|
.cgroup = cgroup,
|
||||||
};
|
};
|
||||||
@ -1722,12 +1729,11 @@ static int main_loop(Manager *manager) {
|
|||||||
if (r < 0)
|
if (r < 0)
|
||||||
return log_error_errno(r, "Failed to enable SO_PASSCRED: %m");
|
return log_error_errno(r, "Failed to enable SO_PASSCRED: %m");
|
||||||
|
|
||||||
r = udev_watch_init();
|
manager->inotify_fd = inotify_init1(IN_CLOEXEC);
|
||||||
if (r < 0)
|
if (manager->inotify_fd < 0)
|
||||||
return log_error_errno(r, "Failed to create inotify descriptor: %m");
|
return log_error_errno(errno, "Failed to create inotify descriptor: %m");
|
||||||
manager->fd_inotify = r;
|
|
||||||
|
|
||||||
udev_watch_restore();
|
udev_watch_restore(manager->inotify_fd);
|
||||||
|
|
||||||
/* block and listen to all signals on signalfd */
|
/* block and listen to all signals on signalfd */
|
||||||
assert_se(sigprocmask_many(SIG_BLOCK, NULL, SIGTERM, SIGINT, SIGHUP, SIGCHLD, -1) >= 0);
|
assert_se(sigprocmask_many(SIG_BLOCK, NULL, SIGTERM, SIGINT, SIGHUP, SIGCHLD, -1) >= 0);
|
||||||
@ -1772,7 +1778,7 @@ static int main_loop(Manager *manager) {
|
|||||||
if (r < 0)
|
if (r < 0)
|
||||||
return log_error_errno(r, "Failed to set IDLE event priority for udev control event source: %m");
|
return log_error_errno(r, "Failed to set IDLE event priority for udev control event source: %m");
|
||||||
|
|
||||||
r = sd_event_add_io(manager->event, &manager->inotify_event, manager->fd_inotify, EPOLLIN, on_inotify, manager);
|
r = sd_event_add_io(manager->event, &manager->inotify_event, manager->inotify_fd, EPOLLIN, on_inotify, manager);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return log_error_errno(r, "Failed to create inotify event source: %m");
|
return log_error_errno(r, "Failed to create inotify event source: %m");
|
||||||
|
|
||||||
|
|||||||
@ -8,7 +8,7 @@ TEST_NO_NSPAWN=1
|
|||||||
# shellcheck source=test/test-functions
|
# shellcheck source=test/test-functions
|
||||||
. "${TEST_BASE_DIR:?}/test-functions"
|
. "${TEST_BASE_DIR:?}/test-functions"
|
||||||
|
|
||||||
QEMU_TIMEOUT=500
|
QEMU_TIMEOUT=800
|
||||||
|
|
||||||
test_append_files() {
|
test_append_files() {
|
||||||
(
|
(
|
||||||
|
|||||||
@ -227,10 +227,10 @@ if [[ "$IS_BUILT_WITH_ASAN" = "yes" ]]; then
|
|||||||
QEMU_SMP="${QEMU_SMP:-4}"
|
QEMU_SMP="${QEMU_SMP:-4}"
|
||||||
|
|
||||||
# We need to correctly distinguish between gcc's and clang's ASan DSOs.
|
# We need to correctly distinguish between gcc's and clang's ASan DSOs.
|
||||||
if ASAN_RT_NAME="$(ldd "$SYSTEMD" | awk '/libasan.so/ {x=$1; exit} END {print x; exit x==""}')"; then
|
if ASAN_RT_NAME="$(awk '/libasan.so/ {x=$1; exit} END {print x; exit x==""}' < <(ldd "$SYSTEMD"))"; then
|
||||||
ASAN_COMPILER=gcc
|
ASAN_COMPILER=gcc
|
||||||
ASAN_RT_PATH="$(readlink -f "$(${CC:-gcc} --print-file-name "$ASAN_RT_NAME")")"
|
ASAN_RT_PATH="$(readlink -f "$(${CC:-gcc} --print-file-name "$ASAN_RT_NAME")")"
|
||||||
elif ASAN_RT_NAME="$(ldd "$SYSTEMD" | awk '/libclang_rt.asan/ {x=$1; exit} END {print x; exit x==""}')"; then
|
elif ASAN_RT_NAME="$(awk '/libclang_rt.asan/ {x=$1; exit} END {print x; exit x==""}' < <(ldd "$SYSTEMD"))"; then
|
||||||
ASAN_COMPILER=clang
|
ASAN_COMPILER=clang
|
||||||
ASAN_RT_PATH="$(readlink -f "$(${CC:-clang} --print-file-name "$ASAN_RT_NAME")")"
|
ASAN_RT_PATH="$(readlink -f "$(${CC:-clang} --print-file-name "$ASAN_RT_NAME")")"
|
||||||
|
|
||||||
|
|||||||
@ -20,6 +20,7 @@ while : ; do
|
|||||||
done
|
done
|
||||||
|
|
||||||
cat >/run/udev/rules.d/50-testsuite.rules <<EOF
|
cat >/run/udev/rules.d/50-testsuite.rules <<EOF
|
||||||
|
SUBSYSTEM=="block", KERNEL=="sda", OPTIONS="log_level=debug"
|
||||||
ACTION!="remove", SUBSYSTEM=="block", KERNEL=="sda", ENV{SYSTEMD_WANTS}="foobar.service"
|
ACTION!="remove", SUBSYSTEM=="block", KERNEL=="sda", ENV{SYSTEMD_WANTS}="foobar.service"
|
||||||
EOF
|
EOF
|
||||||
udevadm control --reload
|
udevadm control --reload
|
||||||
@ -37,6 +38,7 @@ while : ; do
|
|||||||
done
|
done
|
||||||
|
|
||||||
cat >/run/udev/rules.d/50-testsuite.rules <<EOF
|
cat >/run/udev/rules.d/50-testsuite.rules <<EOF
|
||||||
|
SUBSYSTEM=="block", KERNEL=="sda", OPTIONS="log_level=debug"
|
||||||
ACTION!="remove", SUBSYSTEM=="block", KERNEL=="sda", ENV{SYSTEMD_WANTS}="waldo.service"
|
ACTION!="remove", SUBSYSTEM=="block", KERNEL=="sda", ENV{SYSTEMD_WANTS}="waldo.service"
|
||||||
EOF
|
EOF
|
||||||
udevadm control --reload
|
udevadm control --reload
|
||||||
|
|||||||
@ -7,6 +7,7 @@ mkdir -p /run/udev/rules.d/
|
|||||||
cat >/run/udev/rules.d/50-testsuite.rules <<EOF
|
cat >/run/udev/rules.d/50-testsuite.rules <<EOF
|
||||||
ACTION=="remove", GOTO="lo_end"
|
ACTION=="remove", GOTO="lo_end"
|
||||||
|
|
||||||
|
SUBSYSTEM=="net", KERNEL=="lo", OPTIONS="log_level=debug"
|
||||||
SUBSYSTEM=="net", KERNEL=="lo", TAG+="systemd", ENV{SYSTEMD_ALIAS}+="/sys/subsystem/net/devices/lo"
|
SUBSYSTEM=="net", KERNEL=="lo", TAG+="systemd", ENV{SYSTEMD_ALIAS}+="/sys/subsystem/net/devices/lo"
|
||||||
|
|
||||||
ACTION!="change", GOTO="lo_end"
|
ACTION!="change", GOTO="lo_end"
|
||||||
|
|||||||
@ -7,7 +7,10 @@ test_rule="/run/udev/rules.d/49-test.rules"
|
|||||||
setup() {
|
setup() {
|
||||||
mkdir -p "${test_rule%/*}"
|
mkdir -p "${test_rule%/*}"
|
||||||
cp -f /etc/udev/udev.conf /etc/udev/udev.conf.bckp
|
cp -f /etc/udev/udev.conf /etc/udev/udev.conf.bckp
|
||||||
echo 'KERNEL=="lo", SUBSYSTEM=="net", PROGRAM=="/bin/sleep 60"' >"${test_rule}"
|
cat >"${test_rule}" <<EOF
|
||||||
|
SUBSYSTEM=="net", KERNEL=="lo", OPTIONS="log_level=debug"
|
||||||
|
SUBSYSTEM=="net", KERNEL=="lo", PROGRAM=="/bin/sleep 60"
|
||||||
|
EOF
|
||||||
echo "event_timeout=30" >>/etc/udev/udev.conf
|
echo "event_timeout=30" >>/etc/udev/udev.conf
|
||||||
echo "timeout_signal=SIGABRT" >>/etc/udev/udev.conf
|
echo "timeout_signal=SIGABRT" >>/etc/udev/udev.conf
|
||||||
|
|
||||||
|
|||||||
@ -9,6 +9,7 @@ test ! -f /run/udev/tags/changed/c1:3
|
|||||||
udevadm info /dev/null | grep -E 'E: (TAGS|CURRENT_TAGS)=.*:(added|changed):' && exit 1
|
udevadm info /dev/null | grep -E 'E: (TAGS|CURRENT_TAGS)=.*:(added|changed):' && exit 1
|
||||||
|
|
||||||
cat >/run/udev/rules.d/50-testsuite.rules <<EOF
|
cat >/run/udev/rules.d/50-testsuite.rules <<EOF
|
||||||
|
SUBSYSTEM=="mem", KERNEL=="null", OPTIONS="log_level=debug"
|
||||||
ACTION=="add", SUBSYSTEM=="mem", KERNEL=="null", TAG+="added"
|
ACTION=="add", SUBSYSTEM=="mem", KERNEL=="null", TAG+="added"
|
||||||
ACTION=="change", SUBSYSTEM=="mem", KERNEL=="null", TAG+="changed"
|
ACTION=="change", SUBSYSTEM=="mem", KERNEL=="null", TAG+="changed"
|
||||||
EOF
|
EOF
|
||||||
|
|||||||
75
test/units/testsuite-17.06.sh
Executable file
75
test/units/testsuite-17.06.sh
Executable file
@ -0,0 +1,75 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
set -ex
|
||||||
|
set -o pipefail
|
||||||
|
|
||||||
|
# tests for udev watch
|
||||||
|
|
||||||
|
function check_validity() {
|
||||||
|
local f ID_OR_HANDLE
|
||||||
|
|
||||||
|
for f in /run/udev/watch/*; do
|
||||||
|
ID_OR_HANDLE=$(readlink $f)
|
||||||
|
test -L /run/udev/watch/${ID_OR_HANDLE}
|
||||||
|
test $(readlink /run/udev/watch/${ID_OR_HANDLE}) = $(basename $f)
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
function check() {
|
||||||
|
local i j
|
||||||
|
|
||||||
|
for ((i=0;i<2;i++)); do
|
||||||
|
systemctl restart systemd-udevd.service
|
||||||
|
udevadm control --ping
|
||||||
|
udevadm settle
|
||||||
|
sleep 1
|
||||||
|
check_validity
|
||||||
|
|
||||||
|
for ((j=0;j<2;j++)); do
|
||||||
|
udevadm trigger -w --action add --subsystem-match=block
|
||||||
|
udevadm settle
|
||||||
|
sleep 1
|
||||||
|
check_validity
|
||||||
|
done
|
||||||
|
|
||||||
|
for ((j=0;j<2;j++)); do
|
||||||
|
udevadm trigger -w --action change --subsystem-match=block
|
||||||
|
udevadm settle
|
||||||
|
sleep 1
|
||||||
|
check_validity
|
||||||
|
done
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
mkdir -p /run/udev/rules.d/
|
||||||
|
|
||||||
|
cat >/run/udev/rules.d/00-debug.rules <<EOF
|
||||||
|
SUBSYSTEM=="block", KERNEL=="sda*", OPTIONS="log_level=debug"
|
||||||
|
EOF
|
||||||
|
|
||||||
|
cat >/run/udev/rules.d/50-testsuite.rules <<EOF
|
||||||
|
ACTION=="add", SUBSYSTEM=="block", KERNEL=="sda", OPTIONS:="watch"
|
||||||
|
EOF
|
||||||
|
|
||||||
|
check
|
||||||
|
|
||||||
|
MAJOR=$(udevadm info /dev/sda | grep -e '^E: MAJOR=' | sed -e 's/^E: MAJOR=//')
|
||||||
|
MINOR=$(udevadm info /dev/sda | grep -e '^E: MINOR=' | sed -e 's/^E: MINOR=//')
|
||||||
|
test -L /run/udev/watch/b${MAJOR}:${MINOR}
|
||||||
|
|
||||||
|
cat >/run/udev/rules.d/50-testsuite.rules <<EOF
|
||||||
|
ACTION=="change", SUBSYSTEM=="block", KERNEL=="sda", OPTIONS:="nowatch"
|
||||||
|
EOF
|
||||||
|
|
||||||
|
check
|
||||||
|
|
||||||
|
MAJOR=$(udevadm info /dev/sda | grep -e '^E: MAJOR=' | sed -e 's/^E: MAJOR=//')
|
||||||
|
MINOR=$(udevadm info /dev/sda | grep -e '^E: MINOR=' | sed -e 's/^E: MINOR=//')
|
||||||
|
test ! -e /run/udev/watch/b${MAJOR}:${MINOR}
|
||||||
|
|
||||||
|
rm /run/udev/rules.d/00-debug.rules
|
||||||
|
rm /run/udev/rules.d/50-testsuite.rules
|
||||||
|
|
||||||
|
udevadm control --reload
|
||||||
|
udevadm trigger -w --action add --subsystem-match=block
|
||||||
|
|
||||||
|
exit 0
|
||||||
@ -5,6 +5,8 @@ set -o pipefail
|
|||||||
|
|
||||||
: >/failed
|
: >/failed
|
||||||
|
|
||||||
|
udevadm settle
|
||||||
|
|
||||||
for t in "${0%.sh}".*.sh; do
|
for t in "${0%.sh}".*.sh; do
|
||||||
echo "Running $t"; ./"$t"
|
echo "Running $t"; ./"$t"
|
||||||
done
|
done
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user