1
0
mirror of https://github.com/systemd/systemd synced 2026-03-14 17:14:49 +01:00

Compare commits

..

No commits in common. "d49b881eafe25c2efd2816d1ad6164c43e5896fa" and "c068a17f6a18d3ebfabe88fc49e24a923d0bdd0a" have entirely different histories.

23 changed files with 365 additions and 531 deletions

View File

@ -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 *device_id; char *id_filename;
usec_t usec_initialized; usec_t usec_initialized;
@ -84,7 +84,9 @@ 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 */

View File

@ -20,7 +20,6 @@
#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"
@ -569,142 +568,28 @@ int device_get_devlink_priority(sd_device *device, int *priority) {
return 0; return 0;
} }
int device_get_watch_handle(sd_device *device) { int device_get_watch_handle(sd_device *device, int *handle) {
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);
if (wd >= 0 && wd == device->watch_handle) r = device_read_db(device);
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;
path_id = strjoina("/run/udev/watch/", id); if (device->watch_handle < 0)
xsprintf(path_wd, "/run/udev/watch/%d", wd); return -ENOENT;
r = mkdir_parents(path_wd, 0755); if (handle)
if (r < 0) *handle = device->watch_handle;
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;
} }
int device_new_from_watch_handle_at(sd_device **ret, int dirfd, int wd) { void device_set_watch_handle(sd_device *device, int handle) {
char path_wd[STRLEN("/run/udev/watch/") + DECIMAL_STR_MAX(int)]; assert(device);
_cleanup_free_ char *id = NULL;
int r;
assert(ret); device->watch_handle = handle;
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) {
@ -876,7 +761,7 @@ static int device_tag(sd_device *device, const char *tag, bool add) {
assert(device); assert(device);
assert(tag); assert(tag);
r = device_get_device_id(device, &id); r = device_get_id_filename(device, &id);
if (r < 0) if (r < 0)
return r; return r;
@ -937,6 +822,9 @@ 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;
} }
@ -958,7 +846,7 @@ int device_update_db(sd_device *device) {
has_info = device_has_info(device); has_info = device_has_info(device);
r = device_get_device_id(device, &id); r = device_get_id_filename(device, &id);
if (r < 0) if (r < 0)
return r; return r;
@ -1011,6 +899,9 @@ 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)
@ -1059,7 +950,7 @@ int device_delete_db(sd_device *device) {
assert(device); assert(device);
r = device_get_device_id(device, &id); r = device_get_id_filename(device, &id);
if (r < 0) if (r < 0)
return r; return r;

View File

@ -12,22 +12,18 @@
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_device_id(sd_device *device, const char **ret); int device_get_id_filename(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 device_get_watch_handle(sd_device *device, int *handle);
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);
int device_set_watch_handle(sd_device *device, int wd); void device_set_watch_handle(sd_device *device, int fd);
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);

View File

@ -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->device_id); free(device->id_filename);
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,14 +652,15 @@ _public_ int sd_device_new_from_device_id(sd_device **ret, const char *id) {
} }
case '+': { case '+': {
char subsys[NAME_MAX+1]; /* NAME_MAX does not include the trailing NUL. */ char subsys[PATH_MAX];
const char *sysname; char *sysname;
sysname = strchr(id + 1, ':'); (void) strscpy(subsys, sizeof(subsys), id + 1);
sysname = strchr(subsys, ':');
if (!sysname) if (!sysname)
return -EINVAL; return -EINVAL;
(void) strnscpy(subsys, sizeof(subsys), id + 1, sysname - id - 1); sysname[0] = '\0';
sysname++; sysname++;
return sd_device_new_from_subsystem_sysname(ret, subsys, sysname); return sd_device_new_from_subsystem_sysname(ret, subsys, sysname);
@ -751,34 +752,15 @@ 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) { static int device_set_drivers_subsystem(sd_device *device, const char *_subsystem) {
_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);
r = sd_device_get_syspath(device, &syspath); subsystem = strdup(_subsystem);
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;
@ -790,46 +772,60 @@ static int device_set_drivers_subsystem(sd_device *device) {
} }
_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);
if (!device->subsystem_set) {
_cleanup_free_ char *subsystem = NULL;
const char *syspath;
char *path;
r = sd_device_get_syspath(device, &syspath); r = sd_device_get_syspath(device, &syspath);
if (r < 0) if (r < 0)
return r; return r;
if (!device->subsystem_set) {
_cleanup_free_ char *subsystem = NULL;
char *path;
/* 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 && r != -ENOENT) if (r >= 0)
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 (strstr(syspath, "/drivers/")) else if (!(drivers = strstr(syspath, "/drivers/")) &&
r = device_set_drivers_subsystem(device); PATH_STARTSWITH_SET(device->devpath, "/subsystem/",
else if (PATH_STARTSWITH_SET(device->devpath, "/subsystem/",
"/class/", "/class/",
"/bus/")) "/bus/"))
r = device_set_subsystem(device, "subsystem"); r = device_set_subsystem(device, "subsystem");
else { if (r < 0 && r != -ENOENT)
return log_device_debug_errno(device, r, "sd-device: Failed to set subsystem for %s: %m", device->devpath);
device->subsystem_set = true; device->subsystem_set = true;
r = 0; } 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) if (r < 0 && r != -ENOENT)
return log_device_debug_errno(device, r, return log_device_debug_errno(device, r, "sd-device: Failed to set subsystem for driver %s: %m", device->devpath);
"sd-device: Failed to set subsystem for %s: %m", }
device->devpath);
device->driver_subsystem_set = true;
} }
if (!device->subsystem) if (!device->subsystem)
@ -991,7 +987,7 @@ _public_ int sd_device_get_devname(sd_device *device, const char **devname) {
return 0; return 0;
} }
static int device_set_sysname_and_sysnum(sd_device *device) { static int device_set_sysname(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;
@ -1028,6 +1024,7 @@ static int device_set_sysname_and_sysnum(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);
} }
@ -1037,12 +1034,14 @@ _public_ int sd_device_get_sysname(sd_device *device, const char **ret) {
assert_return(device, -EINVAL); assert_return(device, -EINVAL);
if (!device->sysname) { if (!device->sysname_set) {
r = device_set_sysname_and_sysnum(device); r = device_set_sysname(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;
@ -1053,8 +1052,8 @@ _public_ int sd_device_get_sysnum(sd_device *device, const char **ret) {
assert_return(device, -EINVAL); assert_return(device, -EINVAL);
if (!device->sysname) { if (!device->sysname_set) {
r = device_set_sysname_and_sysnum(device); r = device_set_sysname(device);
if (r < 0) if (r < 0)
return r; return r;
} }
@ -1238,10 +1237,10 @@ static int handle_db_line(sd_device *device, char key, const char *value) {
break; break;
case 'W': case 'W':
/* Deprecated. Previously, watch handle is both saved in database and /run/udev/watch. r = safe_atoi(value, &device->watch_handle);
* However, the handle saved in database may not be updated when the handle is updated if (r < 0)
* or removed. Moreover, it is not necessary to store the handle within the database, return r;
* 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);
@ -1256,11 +1255,11 @@ static int handle_db_line(sd_device *device, char key, const char *value) {
return 0; return 0;
} }
int device_get_device_id(sd_device *device, const char **ret) { int device_get_id_filename(sd_device *device, const char **ret) {
assert(device); assert(device);
assert(ret); assert(ret);
if (!device->device_id) { if (!device->id_filename) {
_cleanup_free_ char *id = NULL; _cleanup_free_ char *id = NULL;
const char *subsystem; const char *subsystem;
dev_t devnum; dev_t devnum;
@ -1297,6 +1296,7 @@ int device_get_device_id(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,13 +1307,10 @@ int device_get_device_id(sd_device *device, const char **ret) {
return -ENOMEM; return -ENOMEM;
} }
if (!filename_is_valid(id)) device->id_filename = TAKE_PTR(id);
return -EINVAL;
device->device_id = TAKE_PTR(id);
} }
*ret = device->device_id; *ret = device->id_filename;
return 0; return 0;
} }
@ -1410,7 +1407,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_device_id(device, &id); r = device_get_id_filename(device, &id);
if (r < 0) if (r < 0)
return r; return r;

View File

@ -52,7 +52,7 @@ int config_parse_can_bitrate(
return 0; return 0;
} }
static int link_set_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) { static int link_up_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
int r; int r;
assert(link); assert(link);
@ -60,24 +60,53 @@ static int link_set_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;
} }
@ -226,6 +255,9 @@ 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;
} }
@ -258,21 +290,30 @@ 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);
else if (r < 0) {
r = link_set_can(link);
if (r < 0)
link_enter_failed(link); link_enter_failed(link);
return r; return r;
} }
} else {
r = link_activate(link); r = link_set_can(link);
if (r < 0) if (r < 0) {
link_enter_failed(link);
return r; return r;
}
link->can_configured = true; }
link_check_ready(link);
return 0;
}
if (!(link->flags & IFF_UP)) {
r = link_up_can(link);
if (r < 0) {
link_enter_failed(link);
return r;
}
}
return 0; return 0;
} }

View File

@ -764,15 +764,6 @@ 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__);
@ -1385,7 +1376,7 @@ static int link_up_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link)
return 1; return 1;
} }
int link_up(Link *link) { static 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;
@ -1780,7 +1771,7 @@ static void link_drop(Link *link) {
link_detach_from_manager(link); link_detach_from_manager(link);
} }
int link_activate(Link *link) { static int link_joined(Link *link) {
int r; int r;
assert(link); assert(link);
@ -1798,8 +1789,10 @@ int link_activate(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)
@ -1807,27 +1800,16 @@ int link_activate(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)
@ -2094,7 +2076,6 @@ 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);
@ -2586,10 +2567,6 @@ 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;
@ -2648,10 +2625,6 @@ 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. */
@ -2739,10 +2712,6 @@ 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);
} }

View File

@ -131,7 +131,6 @@ 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;
@ -208,9 +207,7 @@ 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);

View File

@ -130,7 +130,7 @@ static int run(int argc, char *argv[]) {
} }
} }
udev_event_execute_rules(event, -1, 3 * USEC_PER_SEC, SIGKILL, NULL, rules); udev_event_execute_rules(event, 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;

View File

@ -911,9 +911,8 @@ 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 int event_execute_rules_on_remove( static void 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,
@ -934,14 +933,13 @@ static int 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");
(void) udev_watch_end(inotify_fd, dev); if (sd_device_get_devnum(dev, NULL) >= 0)
(void) udev_watch_end(dev);
r = udev_rules_apply_to_event(rules, event, timeout_usec, timeout_signal, properties_list); (void) 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) {
@ -973,14 +971,12 @@ static int copy_all_tags(sd_device *d, sd_device *s) {
return 0; return 0;
} }
int udev_event_execute_rules( int udev_event_execute_rules(UdevEvent *event,
UdevEvent *event,
int inotify_fd, /* This may be negative */
usec_t timeout_usec, usec_t timeout_usec,
int timeout_signal, int timeout_signal,
Hashmap *properties_list, Hashmap *properties_list,
UdevRules *rules) { UdevRules *rules) {
const char *subsystem;
sd_device_action_t action; sd_device_action_t action;
sd_device *dev; sd_device *dev;
int r; int r;
@ -990,15 +986,18 @@ int udev_event_execute_rules(
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) {
return event_execute_rules_on_remove(event, inotify_fd, timeout_usec, timeout_signal, properties_list, rules); event_execute_rules_on_remove(event, 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)
@ -1008,6 +1007,10 @@ int udev_event_execute_rules(
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)
@ -1045,7 +1048,11 @@ int udev_event_execute_rules(
/* 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. */
return update_devnode(event); r = 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) {
@ -1080,24 +1087,3 @@ 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;
}

View File

@ -51,30 +51,21 @@ 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( size_t udev_event_apply_format(UdevEvent *event,
UdevEvent *event, const char *src, char *dest, size_t size,
const char *src,
char *dest,
size_t size,
bool replace_whitespace); 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( int udev_event_spawn(UdevEvent *event,
UdevEvent *event,
usec_t timeout_usec, usec_t timeout_usec,
int timeout_signal, int timeout_signal,
bool accept_failure, bool accept_failure,
const char *cmd, const char *cmd, char *result, size_t ressize);
char *result, int udev_event_execute_rules(UdevEvent *event,
size_t ressize);
int udev_event_execute_rules(
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,
UdevRules *rules); 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);

View File

@ -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, *slink_tmp; const char *id_filename, *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_device_id(dev, &id); r = device_get_id_filename(dev, &id_filename);
if (r < 0) if (r < 0)
return log_device_error_errno(dev, r, "Failed to get device id: %m"); return log_device_error_errno(dev, r, "Failed to get id_filename: %m");
slink_tmp = strjoina(slink, ".tmp-", id); slink_tmp = strjoina(slink, ".tmp-", id_filename);
(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; const char *devnode, *id_filename;
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_device_id(dev, &id) < 0) if (device_get_id_filename(dev, &id_filename) < 0)
continue; continue;
/* did we find ourself? */ /* did we find ourself? */
if (streq(dent->d_name, id)) if (streq(dent->d_name, id_filename))
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; const char *id_filename;
int i, r, retries; int i, r, retries;
assert(dev); assert(dev);
assert(slink); assert(slink);
r = device_get_device_id(dev, &id); r = device_get_id_filename(dev, &id_filename);
if (r < 0) if (r < 0)
return log_device_debug_errno(dev, r, "Failed to get device id: %m"); return log_device_debug_errno(dev, r, "Failed to get id_filename: %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 = path_join(dirname, id_filename);
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 = NULL; const char *devnode, *subsystem, *id_filename = 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_device_id(dev, &id); (void) device_get_id_filename(dev, &id_filename);
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, strna(id)); devnode, id_filename);
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 = NULL; const char *id_filename = NULL;
(void) device_get_device_id(dev, &id); (void) device_get_id_filename(dev, &id_filename);
log_device_debug(dev, "Handling device node '%s', devnum=%s", devnode, strna(id)); log_device_debug(dev, "Handling device node '%s', devnum=%s", devnode, strnull(id_filename));
} }
r = node_permissions_apply(dev, apply, mode, uid, gid, seclabel_list); r = node_permissions_apply(dev, apply, mode, uid, gid, seclabel_list);

View File

@ -5,60 +5,72 @@
*/ */
#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 "parse-util.h" #include "mkdir.h"
#include "stdio-util.h"
#include "udev-watch.h" #include "udev-watch.h"
int udev_watch_restore(int inotify_fd) { static int inotify_fd = -1;
/* 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;
/* Move any old watches directory out of the way, and then restore the watches. */ if (inotify_fd < 0)
return log_debug_errno(SYNTHETIC_ERRNO(EINVAL),
assert(inotify_fd >= 0); "Invalid inotify descriptor.");
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. " return log_warning_errno(errno, "Failed to move watches directory /run/udev/watch. Old watches will not be restored: %m");
"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. " return log_warning_errno(errno, "Failed to open old watches directory /run/udev/watch.old. Old watches will not be restored: %m");
"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;
int wd; _cleanup_free_ char *device = NULL;
if (ent->d_name[0] == '.') if (ent->d_name[0] == '.')
continue; continue;
/* For backward compatibility, read symlink from watch handle to device id, and ignore r = readlinkat_malloc(dirfd(dir), ent->d_name, &device);
* the opposite direction symlink. */
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_full_errno(r == -ENODEV ? LOG_DEBUG : LOG_WARNING, r, log_debug_errno(r, "Failed to read link '/run/udev/watch.old/%s', ignoring: %m", ent->d_name);
"Failed to create sd_device object from saved watch handle '%s', ignoring: %m", goto unlink;
ent->d_name); }
r = sd_device_new_from_device_id(&dev, device);
if (r < 0) {
log_debug_errno(r, "Failed to create sd_device object for '%s', ignoring: %m", device);
goto unlink; goto unlink;
} }
log_device_debug(dev, "Restoring old watch"); log_device_debug(dev, "Restoring old watch");
(void) udev_watch_begin(inotify_fd, dev); (void) udev_watch_begin(dev);
unlink: unlink:
(void) unlinkat(dirfd(dir), ent->d_name, 0); (void) unlinkat(dirfd(dir), ent->d_name, 0);
} }
@ -69,54 +81,94 @@ unlink:
return 0; return 0;
} }
int udev_watch_begin(int inotify_fd, sd_device *dev) { int udev_watch_begin(sd_device *dev) {
const char *devnode; char filename[STRLEN("/run/udev/watch/") + DECIMAL_STR_MAX(int)];
const char *devnode, *id_filename;
int wd, r; int wd, r;
assert(inotify_fd >= 0); if (inotify_fd < 0)
assert(dev); return log_debug_errno(SYNTHETIC_ERRNO(EINVAL),
"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_debug_errno(dev, r, "Failed to get device name: %m"); return log_device_error_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) {
r = log_device_full_errno(dev, errno == ENOENT ? LOG_DEBUG : LOG_WARNING,
errno, "Failed to add device '%s' to watch: %m", devnode);
(void) device_set_watch_handle(dev, -1);
return r;
}
r = device_set_watch_handle(dev, wd);
if (r < 0)
return log_device_warning_errno(dev, r, "Failed to save watch handle in /run/udev/watch: %m");
return 0;
}
int udev_watch_end(int inotify_fd, sd_device *dev) {
int wd;
assert(dev);
/* This may be called by 'udevadm test'. In that case, inotify_fd is not initialized. */
if (inotify_fd < 0)
return 0;
if (sd_device_get_devname(dev, NULL) < 0)
return 0;
wd = device_get_watch_handle(dev);
if (wd < 0) if (wd < 0)
log_device_debug_errno(dev, wd, "Failed to get watch handle, ignoring: %m"); return log_device_full_errno(dev, errno == ENOENT ? LOG_DEBUG : LOG_ERR, errno,
else { "Failed to add device '%s' to watch: %m", devnode);
device_set_watch_handle(dev, wd);
xsprintf(filename, "/run/udev/watch/%d", wd);
r = mkdir_parents(filename, 0755);
if (r < 0)
return log_device_error_errno(dev, r, "Failed to create parent directory of '%s': %m", filename);
(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;
}
int udev_watch_end(sd_device *dev) {
char filename[STRLEN("/run/udev/watch/") + DECIMAL_STR_MAX(int)];
int wd, r;
if (inotify_fd < 0)
return 0; /* Nothing to do. */
r = device_get_watch_handle(dev, &wd);
if (r == -ENOENT)
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"); log_device_debug(dev, "Removing watch");
(void) inotify_rm_watch(inotify_fd, wd); (void) inotify_rm_watch(inotify_fd, wd);
}
(void) device_set_watch_handle(dev, -1); xsprintf(filename, "/run/udev/watch/%d", wd);
(void) unlink(filename);
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;
}

View File

@ -3,6 +3,8 @@
#include "sd-device.h" #include "sd-device.h"
int udev_watch_restore(int inotify_fd); int udev_watch_init(void);
int udev_watch_begin(int inotify_fd, sd_device *dev); int udev_watch_restore(void);
int udev_watch_end(int inotify_fd, sd_device *dev); int udev_watch_begin(sd_device *dev);
int udev_watch_end(sd_device *dev);
int udev_watch_lookup(int wd, sd_device **ret);

View File

@ -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, -1, 60 * USEC_PER_SEC, SIGKILL, NULL, rules); udev_event_execute_rules(event, 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);

View File

@ -92,12 +92,10 @@ 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;
@ -306,7 +304,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->inotify_fd); safe_close(manager->fd_inotify);
safe_close_pair(manager->worker_watch); safe_close_pair(manager->worker_watch);
return mfree(manager); return mfree(manager);
@ -475,7 +473,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(manager->inotify_fd, dev); (void) udev_watch_begin(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);
@ -486,13 +484,7 @@ 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( r = udev_event_execute_rules(udev_event, arg_event_timeout_usec, arg_timeout_signal, manager->properties, manager->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;
@ -502,9 +494,14 @@ 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);
r = udev_event_process_inotify_watch(udev_event, manager->inotify_fd); /* apply/restore/end inotify watch */
if (udev_event->inotify_watch) {
(void) udev_watch_begin(dev);
r = device_update_db(dev);
if (r < 0) if (r < 0)
return r; 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;
@ -875,7 +872,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->inotify_fd = safe_close(manager->inotify_fd); manager->fd_inotify = safe_close(manager->fd_inotify);
manager->monitor = sd_device_monitor_unref(manager->monitor); manager->monitor = sd_device_monitor_unref(manager->monitor);
@ -1302,21 +1299,17 @@ 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;
r = device_new_from_watch_handle(&dev, e->wd); if (udev_watch_lookup(e->wd, &dev) <= 0)
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)
(void) synthesize_change(dev); synthesize_change(dev);
else if (e->mask & IN_IGNORED)
/* Do not handle IN_IGNORED here. It should be handled by worker in 'remove' uevent; udev_watch_end(dev);
* udev_event_execute_rules() -> event_execute_rules_on_remove() -> udev_watch_end(). */
} }
return 1; return 1;
@ -1676,7 +1669,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) {
.inotify_fd = -1, .fd_inotify = -1,
.worker_watch = { -1, -1 }, .worker_watch = { -1, -1 },
.cgroup = cgroup, .cgroup = cgroup,
}; };
@ -1729,11 +1722,12 @@ 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");
manager->inotify_fd = inotify_init1(IN_CLOEXEC); r = udev_watch_init();
if (manager->inotify_fd < 0) if (r < 0)
return log_error_errno(errno, "Failed to create inotify descriptor: %m"); return log_error_errno(r, "Failed to create inotify descriptor: %m");
manager->fd_inotify = r;
udev_watch_restore(manager->inotify_fd); udev_watch_restore();
/* 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);
@ -1778,7 +1772,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->inotify_fd, EPOLLIN, on_inotify, manager); r = sd_event_add_io(manager->event, &manager->inotify_event, manager->fd_inotify, 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");

View File

@ -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=800 QEMU_TIMEOUT=500
test_append_files() { test_append_files() {
( (

View File

@ -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="$(awk '/libasan.so/ {x=$1; exit} END {print x; exit x==""}' < <(ldd "$SYSTEMD"))"; then if ASAN_RT_NAME="$(ldd "$SYSTEMD" | awk '/libasan.so/ {x=$1; exit} END {print x; exit x==""}')"; 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="$(awk '/libclang_rt.asan/ {x=$1; exit} END {print x; exit x==""}' < <(ldd "$SYSTEMD"))"; then elif ASAN_RT_NAME="$(ldd "$SYSTEMD" | awk '/libclang_rt.asan/ {x=$1; exit} END {print x; exit x==""}')"; 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")")"

View File

@ -20,7 +20,6 @@ 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
@ -38,7 +37,6 @@ 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

View File

@ -7,7 +7,6 @@ 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"

View File

@ -7,10 +7,7 @@ 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
cat >"${test_rule}" <<EOF echo 'KERNEL=="lo", SUBSYSTEM=="net", PROGRAM=="/bin/sleep 60"' >"${test_rule}"
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

View File

@ -9,7 +9,6 @@ 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

View File

@ -1,75 +0,0 @@
#!/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

View File

@ -5,8 +5,6 @@ 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