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

Compare commits

...

26 Commits

Author SHA1 Message Date
Frantisek Sumsal
d49b881eaf test: fix a yet another pipefail + pipe race
Basically the same scenario as in
a33e2692e162671f0d97856ad2f49a2620a1ec10, where `awk` exits as soon
as it finds a match, thus sending SIGPIPE to `ldd` if it's not fast
enough. That, in combination with `set -o pipefail` causes random &
unexpected fails, like:

```
No journal files were found.
-rw-r----- 1 root root 16777216 Apr 30 10:31
/var/tmp/TEST-01-BASIC_sanitizers-nspawn/system.journal
TEST-01-BASIC RUN: Basic systemd setup [OK]
systemd is not linked against the ASan DSO
gcc does this by default, for clang compile with -shared-libasan
make: *** [Makefile:2: clean-again] Error 1
make: Leaving directory '/build/test/TEST-01-BASIC'
```
2021-05-01 15:05:16 +09:00
Yu Watanabe
0c9cdcb9d4
Merge pull request #19476 from yuwata/network-can
network: several CAN device related updates
2021-05-01 15:03:22 +09:00
Yu Watanabe
bff97a251d
Merge pull request #18904 from yuwata/udev-watch
udev: several inotify watch fixups
2021-05-01 15:02:43 +09:00
Yu Watanabe
b43669a4b1 test: add a simple test for udev watch 2021-04-30 19:42:09 +09:00
Yu Watanabe
e63916ab29 test: generate debugging logs for udev tests 2021-04-30 19:42:09 +09:00
Yu Watanabe
e1e56f3443 test: run udev tests after currently queued events are finished 2021-04-30 19:42:09 +09:00
Yu Watanabe
e7f781e473 udev,sd_device: also save map from device ID to watch handle in /run/udev/watch
Previously, watch handle is saved in the udev databse. But in most cases,
the handle saved in the database is not updated. Especially, when udevd
is restarted, the inotify watch is restarted, but the database is not
updated.

Moreover, it is not necessary to save watch handle in the database, as
the handle is only take a effect during udevd is running, and the value
is meaningless when udevd is restarted.

So, this makes the opposite map from device ID to watch handle is saved
in /run/udev/watch as a symbolic link, and the handle not saved in the
database anymore.

Fixes #18525.
2021-04-30 19:41:41 +09:00
Yu Watanabe
5e0d051067 udev: make udev_watch_end() noop when device does not have devname 2021-04-30 19:32:14 +09:00
Yu Watanabe
4956f220a1 sd-device: cleanup sd_device_get_subsystem() 2021-04-30 19:32:10 +09:00
Yu Watanabe
6e25642f8e sd-device: drop sysname_set flag
When device_set_sysname() succeeds, sysname is always set.
2021-04-30 19:21:18 +09:00
Yu Watanabe
ff7a8d2938 sd-device: minor optimization for sd_device_new_from_device_id() 2021-04-30 19:21:18 +09:00
Yu Watanabe
db2bad4368 sd-device: check the validity of device id
The device id is used as filename under /run/udev/data or
/run/udev/watch.
2021-04-30 19:21:18 +09:00
Yu Watanabe
fe7323815d sd-device: rename device_get_id_filename() -> device_get_device_id()
We have sd_device_new_from_device_id(), which takes device ID generated
from device_get_id_filename(). For consistency, let's rename the
function.
2021-04-30 19:21:18 +09:00
Yu Watanabe
0d77bc4a18 udev: refuse to enable inotify watch on remove event
Some udev rule may erroneously set inotify watch on remove event.
For safety, silently ignore such an inotify watch enablement.

This also moves inotify watch enablement code to udev-event.c.
2021-04-30 19:21:18 +09:00
Yu Watanabe
4cac2260c8 udev: also propagate error in udev_rules_apply_to_event() on remove event
When udev rules are not applied correctly, then run program lists is
not perfect. So, udev_event_execute_run() later in
worker_process_device() should not be called.
2021-04-30 19:21:18 +09:00
Yu Watanabe
75b4984638 udev: shorten code a bit 2021-04-30 19:21:18 +09:00
Yu Watanabe
fa5d8899aa udev: drop unused variable 2021-04-30 19:21:18 +09:00
Yu Watanabe
99e0c96f31 sd-device: drop doubled empty lines 2021-04-30 19:21:18 +09:00
Yu Watanabe
df7ee95913 udev: do not store inotify fd in a global variable
When manager_exit() or manager_free() is called, the global variable in
udev-watch.c is not set '-1'. Of course, that is safe, as the event source
for the inotify fd is unref()ed in manager_exit() and manager_free().
But let's not store fd globally.
2021-04-30 19:21:18 +09:00
Yu Watanabe
36161cba7c network: do not bring up CAN interface on configure 2021-04-30 19:16:15 +09:00
Yu Watanabe
d9fc3b0da9 network: make CAN device follow activation policy 2021-04-30 19:16:15 +09:00
Yu Watanabe
04952b25e8 network: introduce link_activate() 2021-04-30 19:16:15 +09:00
Yu Watanabe
600b7898e8 network: do not try to configure address or etc on can device 2021-04-30 19:16:02 +09:00
Yu Watanabe
e361398e48 network: can: shorten code a bit 2021-04-30 19:11:25 +09:00
Yu Watanabe
ed52cce33f network: can: do not warn if link does not exist anymore 2021-04-30 19:11:25 +09:00
Yu Watanabe
f282ce20aa network: drop duplicated link_up_can() 2021-04-30 19:11:25 +09:00
23 changed files with 519 additions and 353 deletions

View File

@ -67,7 +67,7 @@ struct sd_device {
char *driver_subsystem; /* only set for the 'drivers' subsystem */
char *driver;
char *id_filename;
char *device_id;
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_devlinks_outdated:1; /* need to update DEVLINKS= property */
bool properties_buf_outdated:1; /* need to reread hashmap */
bool sysname_set:1; /* don't reread sysname */
bool subsystem_set:1; /* don't reread subsystem */
bool driver_subsystem_set:1; /* don't reread subsystem */
bool driver_set:1; /* don't reread driver */
bool uevent_loaded:1; /* don't reread uevent */
bool db_loaded; /* don't reread db */

View File

@ -20,6 +20,7 @@
#include "parse-util.h"
#include "path-util.h"
#include "set.h"
#include "stdio-util.h"
#include "string-table.h"
#include "string-util.h"
#include "strv.h"
@ -568,28 +569,142 @@ int device_get_devlink_priority(sd_device *device, int *priority) {
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;
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)
return r;
if (device->watch_handle < 0)
return -ENOENT;
path_id = strjoina("/run/udev/watch/", id);
xsprintf(path_wd, "/run/udev/watch/%d", wd);
if (handle)
*handle = device->watch_handle;
r = mkdir_parents(path_wd, 0755);
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;
}
void device_set_watch_handle(sd_device *device, int handle) {
assert(device);
int device_new_from_watch_handle_at(sd_device **ret, int dirfd, int wd) {
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) {
@ -761,7 +876,7 @@ static int device_tag(sd_device *device, const char *tag, bool add) {
assert(device);
assert(tag);
r = device_get_id_filename(device, &id);
r = device_get_device_id(device, &id);
if (r < 0)
return r;
@ -822,9 +937,6 @@ static bool device_has_info(sd_device *device) {
if (!set_isempty(device->current_tags))
return true;
if (device->watch_handle >= 0)
return true;
return false;
}
@ -846,7 +958,7 @@ int device_update_db(sd_device *device) {
has_info = device_has_info(device);
r = device_get_id_filename(device, &id);
r = device_get_device_id(device, &id);
if (r < 0)
return r;
@ -899,9 +1011,6 @@ int device_update_db(sd_device *device) {
if (device->devlink_priority != 0)
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)
@ -950,7 +1059,7 @@ int device_delete_db(sd_device *device) {
assert(device);
r = device_get_id_filename(device, &id);
r = device_get_device_id(device, &id);
if (r < 0)
return r;

View File

@ -12,18 +12,22 @@
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_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_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_uid(sd_device *device, uid_t *uid);
int device_get_devnode_gid(sd_device *device, gid_t *gid);
void device_seal(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_devlink_priority(sd_device *device, int priority);
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->driver_subsystem);
free(device->driver);
free(device->id_filename);
free(device->device_id);
free(device->properties_strv);
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 = {};
int ifindex;
r = ifr.ifr_ifindex = parse_ifindex(&id[1]);
r = ifr.ifr_ifindex = parse_ifindex(id + 1);
if (r < 0)
return r;
@ -652,15 +652,14 @@ _public_ int sd_device_new_from_device_id(sd_device **ret, const char *id) {
}
case '+': {
char subsys[PATH_MAX];
char *sysname;
char subsys[NAME_MAX+1]; /* NAME_MAX does not include the trailing NUL. */
const char *sysname;
(void) strscpy(subsys, sizeof(subsys), id + 1);
sysname = strchr(subsys, ':');
sysname = strchr(id + 1, ':');
if (!sysname)
return -EINVAL;
sysname[0] = '\0';
(void) strnscpy(subsys, sizeof(subsys), id + 1, sysname - id - 1);
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);
}
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;
const char *syspath, *drivers, *p;
int r;
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)
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) {
const char *syspath, *drivers = NULL;
int r;
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);
if (r < 0)
return r;
if (!device->subsystem_set) {
_cleanup_free_ char *subsystem = NULL;
char *path;
/* read 'subsystem' link */
path = strjoina(syspath, "/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);
/* use implicit names */
else if (path_startswith(device->devpath, "/module/"))
r = device_set_subsystem(device, "module");
else if (!(drivers = strstr(syspath, "/drivers/")) &&
PATH_STARTSWITH_SET(device->devpath, "/subsystem/",
else if (strstr(syspath, "/drivers/"))
r = device_set_drivers_subsystem(device);
else if (PATH_STARTSWITH_SET(device->devpath, "/subsystem/",
"/class/",
"/bus/"))
r = device_set_subsystem(device, "subsystem");
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;
} 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);
device->subsystem_set = true;
r = 0;
}
if (r < 0 && r != -ENOENT)
return log_device_debug_errno(device, r, "sd-device: Failed to set subsystem for driver %s: %m", device->devpath);
}
device->driver_subsystem_set = true;
if (r < 0)
return log_device_debug_errno(device, r,
"sd-device: Failed to set subsystem for %s: %m",
device->devpath);
}
if (!device->subsystem)
@ -987,7 +991,7 @@ _public_ int sd_device_get_devname(sd_device *device, const char **devname) {
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;
const char *sysnum = NULL;
const char *pos;
@ -1024,7 +1028,6 @@ static int device_set_sysname(sd_device *device) {
if (len == 0)
sysnum = NULL;
device->sysname_set = true;
device->sysnum = sysnum;
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);
if (!device->sysname_set) {
r = device_set_sysname(device);
if (!device->sysname) {
r = device_set_sysname_and_sysnum(device);
if (r < 0)
return r;
}
assert_return(device->sysname, -ENOENT);
if (ret)
*ret = device->sysname;
return 0;
@ -1052,8 +1053,8 @@ _public_ int sd_device_get_sysnum(sd_device *device, const char **ret) {
assert_return(device, -EINVAL);
if (!device->sysname_set) {
r = device_set_sysname(device);
if (!device->sysname) {
r = device_set_sysname_and_sysnum(device);
if (r < 0)
return r;
}
@ -1237,10 +1238,10 @@ static int handle_db_line(sd_device *device, char key, const char *value) {
break;
case 'W':
r = safe_atoi(value, &device->watch_handle);
if (r < 0)
return r;
/* Deprecated. Previously, watch handle is both saved in database and /run/udev/watch.
* However, the handle saved in database may not be updated when the handle is updated
* or removed. Moreover, it is not necessary to store the handle within the database,
* as its value becomes meaningless when udevd is restarted. */
break;
case 'V':
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;
}
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(ret);
if (!device->id_filename) {
if (!device->device_id) {
_cleanup_free_ char *id = NULL;
const char *subsystem;
dev_t devnum;
@ -1296,7 +1297,6 @@ int device_get_id_filename(sd_device *device, const char **ret) {
if (!subsystem)
return -EINVAL;
if (streq(subsystem, "drivers"))
/* the 'drivers' pseudo-subsystem is special, and needs the real subsystem
* encoded as well */
@ -1307,10 +1307,13 @@ int device_get_id_filename(sd_device *device, const char **ret) {
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;
}
@ -1407,7 +1410,7 @@ int device_read_db_internal(sd_device *device, bool force) {
if (device->db_loaded || (!force && device->sealed))
return 0;
r = device_get_id_filename(device, &id);
r = device_get_device_id(device, &id);
if (r < 0)
return r;

View File

@ -52,7 +52,7 @@ int config_parse_can_bitrate(
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;
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))
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);
if (r < 0 && r != -EEXIST) {
log_link_message_warning_errno(link, m, r, "Failed to configure CAN 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;
}
@ -255,9 +226,6 @@ static int link_set_can(Link *link) {
link_ref(link);
if (!(link->flags & IFF_UP))
return link_up_can(link);
return 0;
}
@ -290,30 +258,21 @@ int link_configure_can(Link *link) {
if (streq_ptr(link->kind, "can")) {
/* 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);
if (r < 0) {
link_enter_failed(link);
return r;
}
} else {
else
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);
r = link_activate(link);
if (r < 0)
return r;
}
}
link->can_configured = true;
link_check_ready(link);
return 0;
}

View File

@ -764,6 +764,15 @@ void link_check_ready(Link *link) {
if (!link->network)
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)
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;
}
static int link_up(Link *link) {
int link_up(Link *link) {
_cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL;
int r;
@ -1771,7 +1780,7 @@ static void link_drop(Link *link) {
link_detach_from_manager(link);
}
static int link_joined(Link *link) {
int link_activate(Link *link) {
int r;
assert(link);
@ -1789,10 +1798,8 @@ static int link_joined(Link *link) {
_fallthrough_;
case ACTIVATION_POLICY_ALWAYS_UP:
r = link_up(link);
if (r < 0) {
link_enter_failed(link);
if (r < 0)
return r;
}
break;
case ACTIVATION_POLICY_DOWN:
if (link->activated)
@ -1800,16 +1807,27 @@ static int link_joined(Link *link) {
_fallthrough_;
case ACTIVATION_POLICY_ALWAYS_DOWN:
r = link_down(link, NULL);
if (r < 0) {
link_enter_failed(link);
if (r < 0)
return r;
}
break;
default:
break;
}
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) {
r = link_set_bridge(link);
if (r < 0)
@ -2076,6 +2094,7 @@ int link_configure(Link *link) {
return r;
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);
r = link_set_sysctl(link);
@ -2567,6 +2586,10 @@ static int link_carrier_gained(Link *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);
if (r < 0)
return r;
@ -2625,6 +2648,10 @@ static int link_carrier_lost(Link *link) {
if (link->network && link->network->ignore_carrier_loss)
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.
* 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. */
@ -2712,6 +2739,10 @@ static int link_admin_state_down(Link *link) {
return 0;
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");
return link_up(link);
}

View File

@ -131,6 +131,7 @@ typedef struct Link {
bool setting_genmode:1;
bool ipv6_mtu_set:1;
bool bridge_mdb_configured:1;
bool can_configured:1;
bool activated:1;
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_up(Link *link);
int link_down(Link *link, link_netlink_message_handler_t callback);
int link_activate(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, 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);
return 0;

View File

@ -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);
}
static void event_execute_rules_on_remove(
static int event_execute_rules_on_remove(
UdevEvent *event,
int inotify_fd,
usec_t timeout_usec,
int timeout_signal,
Hashmap *properties_list,
@ -933,13 +934,14 @@ static void event_execute_rules_on_remove(
if (r < 0)
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(dev);
(void) udev_watch_end(inotify_fd, 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)
(void) udev_node_remove(dev);
return r;
}
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;
}
int udev_event_execute_rules(UdevEvent *event,
int udev_event_execute_rules(
UdevEvent *event,
int inotify_fd, /* This may be negative */
usec_t timeout_usec,
int timeout_signal,
Hashmap *properties_list,
UdevRules *rules) {
const char *subsystem;
sd_device_action_t action;
sd_device *dev;
int r;
@ -986,18 +990,15 @@ int udev_event_execute_rules(UdevEvent *event,
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);
if (r < 0)
return log_device_error_errno(dev, r, "Failed to get ACTION: %m");
if (action == SD_DEVICE_REMOVE) {
event_execute_rules_on_remove(event, timeout_usec, timeout_signal, properties_list, rules);
return 0;
}
if (action == SD_DEVICE_REMOVE)
return event_execute_rules_on_remove(event, inotify_fd, timeout_usec, timeout_signal, properties_list, rules);
/* Disable watch during event processing. */
(void) udev_watch_end(inotify_fd, event->dev);
r = device_clone_with_db(dev, &event->dev_db_clone);
if (r < 0)
@ -1007,10 +1008,6 @@ int udev_event_execute_rules(UdevEvent *event,
if (r < 0)
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) {
r = udev_event_on_move(event->dev);
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,
* 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. */
r = update_devnode(event);
if (r < 0)
return r;
return 0;
return update_devnode(event);
}
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;
}

View File

@ -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);
DEFINE_TRIVIAL_CLEANUP_FUNC(UdevEvent*, udev_event_free);
size_t udev_event_apply_format(UdevEvent *event,
const char *src, char *dest, size_t size,
size_t udev_event_apply_format(
UdevEvent *event,
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_event_spawn(UdevEvent *event,
int udev_event_spawn(
UdevEvent *event,
usec_t timeout_usec,
int timeout_signal,
bool accept_failure,
const char *cmd, char *result, size_t ressize);
int udev_event_execute_rules(UdevEvent *event,
const char *cmd,
char *result,
size_t ressize);
int udev_event_execute_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);
int udev_event_process_inotify_watch(UdevEvent *event, int inotify_fd);
static inline usec_t udev_warn_timeout(usec_t timeout_usec) {
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) {
_cleanup_free_ char *slink_dirname = NULL, *target = NULL;
const char *id_filename, *slink_tmp;
const char *id, *slink_tmp;
struct stat stats;
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);
r = device_get_id_filename(dev, &id_filename);
r = device_get_device_id(dev, &id);
if (r < 0)
return log_device_error_errno(dev, r, "Failed to get id_filename: %m");
slink_tmp = strjoina(slink, ".tmp-", id_filename);
return log_device_error_errno(dev, r, "Failed to get device id: %m");
slink_tmp = strjoina(slink, ".tmp-", id);
(void) unlink(slink_tmp);
do {
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) {
_cleanup_(sd_device_unrefp) sd_device *dev_db = NULL;
const char *devnode, *id_filename;
const char *devnode, *id;
int db_prio = 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);
if (device_get_id_filename(dev, &id_filename) < 0)
if (device_get_device_id(dev, &id) < 0)
continue;
/* did we find ourself? */
if (streq(dent->d_name, id_filename))
if (streq(dent->d_name, id))
continue;
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) {
_cleanup_free_ char *filename = NULL, *dirname = NULL;
char name_enc[PATH_MAX];
const char *id_filename;
const char *id;
int i, r, retries;
assert(dev);
assert(slink);
r = device_get_id_filename(dev, &id_filename);
r = device_get_device_id(dev, &id);
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));
dirname = path_join("/run/udev/links/", name_enc);
if (!dirname)
return log_oom();
filename = path_join(dirname, id_filename);
filename = path_join(dirname, id);
if (!filename)
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,
mode_t mode, uid_t uid, gid_t gid,
OrderedHashmap *seclabel_list) {
const char *devnode, *subsystem, *id_filename = NULL;
const char *devnode, *subsystem, *id = NULL;
bool apply_mode, apply_uid, apply_gid;
_cleanup_close_ int node_fd = -1;
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);
if (r < 0)
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"))
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) {
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
* 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");
if (DEBUG_LOGGING) {
const char *id_filename = NULL;
const char *id = NULL;
(void) device_get_id_filename(dev, &id_filename);
log_device_debug(dev, "Handling device node '%s', devnum=%s", devnode, strnull(id_filename));
(void) device_get_device_id(dev, &id);
log_device_debug(dev, "Handling device node '%s', devnum=%s", devnode, strna(id));
}
r = node_permissions_apply(dev, apply, mode, uid, gid, seclabel_list);

View File

@ -5,72 +5,60 @@
*/
#include <sys/inotify.h>
#include <unistd.h>
#include "alloc-util.h"
#include "device-private.h"
#include "device-util.h"
#include "dirent-util.h"
#include "fs-util.h"
#include "mkdir.h"
#include "stdio-util.h"
#include "parse-util.h"
#include "udev-watch.h"
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) {
int udev_watch_restore(int inotify_fd) {
struct dirent *ent;
DIR *dir;
int r;
if (inotify_fd < 0)
return log_debug_errno(SYNTHETIC_ERRNO(EINVAL),
"Invalid inotify descriptor.");
/* Move any old watches directory out of the way, and then restore the watches. */
assert(inotify_fd >= 0);
if (rename("/run/udev/watch", "/run/udev/watch.old") < 0) {
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;
}
dir = opendir("/run/udev/watch.old");
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) {
_cleanup_(sd_device_unrefp) sd_device *dev = NULL;
_cleanup_free_ char *device = NULL;
int wd;
if (ent->d_name[0] == '.')
continue;
r = readlinkat_malloc(dirfd(dir), ent->d_name, &device);
if (r < 0) {
log_debug_errno(r, "Failed to read link '/run/udev/watch.old/%s', ignoring: %m", ent->d_name);
goto unlink;
}
/* For backward compatibility, read symlink from watch handle to device id, and ignore
* the opposite direction symlink. */
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) {
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;
}
log_device_debug(dev, "Restoring old watch");
(void) udev_watch_begin(dev);
(void) udev_watch_begin(inotify_fd, dev);
unlink:
(void) unlinkat(dirfd(dir), ent->d_name, 0);
}
@ -81,94 +69,54 @@ unlink:
return 0;
}
int udev_watch_begin(sd_device *dev) {
char filename[STRLEN("/run/udev/watch/") + DECIMAL_STR_MAX(int)];
const char *devnode, *id_filename;
int udev_watch_begin(int inotify_fd, sd_device *dev) {
const char *devnode;
int wd, r;
if (inotify_fd < 0)
return log_debug_errno(SYNTHETIC_ERRNO(EINVAL),
"Invalid inotify descriptor.");
assert(inotify_fd >= 0);
assert(dev);
r = sd_device_get_devname(dev, &devnode);
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);
wd = inotify_add_watch(inotify_fd, devnode, IN_CLOSE_WRITE);
if (wd < 0)
return log_device_full_errno(dev, errno == ENOENT ? LOG_DEBUG : LOG_ERR, errno,
"Failed to add device '%s' to watch: %m", devnode);
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);
device_set_watch_handle(dev, wd);
(void) device_set_watch_handle(dev, -1);
return r;
}
xsprintf(filename, "/run/udev/watch/%d", wd);
r = mkdir_parents(filename, 0755);
r = device_set_watch_handle(dev, wd);
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 log_device_warning_errno(dev, r, "Failed to save watch handle in /run/udev/watch: %m");
return 0;
}
int udev_watch_end(sd_device *dev) {
char filename[STRLEN("/run/udev/watch/") + DECIMAL_STR_MAX(int)];
int wd, r;
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; /* 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");
if (sd_device_get_devname(dev, NULL) < 0)
return 0;
wd = device_get_watch_handle(dev);
if (wd < 0)
log_device_debug_errno(dev, wd, "Failed to get watch handle, ignoring: %m");
else {
log_device_debug(dev, "Removing watch");
(void) inotify_rm_watch(inotify_fd, wd);
xsprintf(filename, "/run/udev/watch/%d", wd);
(void) unlink(filename);
device_set_watch_handle(dev, -1);
}
(void) device_set_watch_handle(dev, -1);
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,8 +3,6 @@
#include "sd-device.h"
int udev_watch_init(void);
int udev_watch_restore(void);
int udev_watch_begin(sd_device *dev);
int udev_watch_end(sd_device *dev);
int udev_watch_lookup(int wd, sd_device **ret);
int udev_watch_restore(int inotify_fd);
int udev_watch_begin(int inotify_fd, sd_device *dev);
int udev_watch_end(int inotify_fd, sd_device *dev);

View File

@ -141,7 +141,7 @@ int test_main(int argc, char *argv[], void *userdata) {
assert_se(sigfillset(&mask) >= 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)
printf("%s=%s\n", key, value);

View File

@ -92,10 +92,12 @@ typedef struct Manager {
sd_device_monitor *monitor;
struct udev_ctrl *ctrl;
int fd_inotify;
int worker_watch[2];
/* used by udev-watch */
int inotify_fd;
sd_event_source *inotify_event;
sd_event_source *kill_workers_event;
usec_t last_usec;
@ -304,7 +306,7 @@ static Manager* manager_free(Manager *manager) {
hashmap_free_free_free(manager->properties);
udev_rules_free(manager->rules);
safe_close(manager->fd_inotify);
safe_close(manager->inotify_fd);
safe_close_pair(manager->worker_watch);
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. */
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 */
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);
/* 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)
return r;
@ -494,14 +502,9 @@ static int worker_process_device(Manager *manager, sd_device *dev) {
/* in case rtnl was initialized */
manager->rtnl = sd_netlink_ref(udev_event->rtnl);
/* apply/restore/end inotify watch */
if (udev_event->inotify_watch) {
(void) udev_watch_begin(dev);
r = device_update_db(dev);
r = udev_event_process_inotify_watch(udev_event, manager->inotify_fd);
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);
return r;
log_device_uevent(dev, "Device processed");
return 0;
@ -872,7 +875,7 @@ static void manager_exit(Manager *manager) {
manager->ctrl = udev_ctrl_unref(manager->ctrl);
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);
@ -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;
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;
}
if (sd_device_get_devname(dev, &devnode) < 0)
continue;
log_device_debug(dev, "Inotify event: %x for %s", e->mask, devnode);
if (e->mask & IN_CLOSE_WRITE)
synthesize_change(dev);
else if (e->mask & IN_IGNORED)
udev_watch_end(dev);
(void) synthesize_change(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;
@ -1669,7 +1676,7 @@ static int manager_new(Manager **ret, int fd_ctrl, int fd_uevent, const char *cg
return log_oom();
*manager = (Manager) {
.fd_inotify = -1,
.inotify_fd = -1,
.worker_watch = { -1, -1 },
.cgroup = cgroup,
};
@ -1722,12 +1729,11 @@ static int main_loop(Manager *manager) {
if (r < 0)
return log_error_errno(r, "Failed to enable SO_PASSCRED: %m");
r = udev_watch_init();
if (r < 0)
return log_error_errno(r, "Failed to create inotify descriptor: %m");
manager->fd_inotify = r;
manager->inotify_fd = inotify_init1(IN_CLOEXEC);
if (manager->inotify_fd < 0)
return log_error_errno(errno, "Failed to create inotify descriptor: %m");
udev_watch_restore();
udev_watch_restore(manager->inotify_fd);
/* block and listen to all signals on signalfd */
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)
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)
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
. "${TEST_BASE_DIR:?}/test-functions"
QEMU_TIMEOUT=500
QEMU_TIMEOUT=800
test_append_files() {
(

View File

@ -227,10 +227,10 @@ if [[ "$IS_BUILT_WITH_ASAN" = "yes" ]]; then
QEMU_SMP="${QEMU_SMP:-4}"
# 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_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_RT_PATH="$(readlink -f "$(${CC:-clang} --print-file-name "$ASAN_RT_NAME")")"

View File

@ -20,6 +20,7 @@ while : ; do
done
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"
EOF
udevadm control --reload
@ -37,6 +38,7 @@ while : ; do
done
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"
EOF
udevadm control --reload

View File

@ -7,6 +7,7 @@ mkdir -p /run/udev/rules.d/
cat >/run/udev/rules.d/50-testsuite.rules <<EOF
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"
ACTION!="change", GOTO="lo_end"

View File

@ -7,7 +7,10 @@ test_rule="/run/udev/rules.d/49-test.rules"
setup() {
mkdir -p "${test_rule%/*}"
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 "timeout_signal=SIGABRT" >>/etc/udev/udev.conf

View File

@ -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
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=="change", SUBSYSTEM=="mem", KERNEL=="null", TAG+="changed"
EOF

75
test/units/testsuite-17.06.sh Executable file
View 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

View File

@ -5,6 +5,8 @@ set -o pipefail
: >/failed
udevadm settle
for t in "${0%.sh}".*.sh; do
echo "Running $t"; ./"$t"
done