summaryrefslogtreecommitdiff
path: root/src/udev/udevd.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/udev/udevd.c')
-rw-r--r--src/udev/udevd.c169
1 files changed, 80 insertions, 89 deletions
diff --git a/src/udev/udevd.c b/src/udev/udevd.c
index fb8724ea87..0303f36b4f 100644
--- a/src/udev/udevd.c
+++ b/src/udev/udevd.c
@@ -31,6 +31,7 @@
#include "sd-event.h"
#include "alloc-util.h"
+#include "build.h"
#include "cgroup-util.h"
#include "cpu-set-util.h"
#include "dev-setup.h"
@@ -185,20 +186,11 @@ static void worker_free(struct worker *worker) {
free(worker);
}
-static void manager_workers_free(Manager *manager) {
- struct worker *worker;
- Iterator i;
-
- assert(manager);
-
- HASHMAP_FOREACH(worker, manager->workers, i)
- worker_free(worker);
-
- manager->workers = hashmap_free(manager->workers);
-}
+DEFINE_TRIVIAL_CLEANUP_FUNC(struct worker *, worker_free);
+DEFINE_PRIVATE_HASH_OPS_WITH_VALUE_DESTRUCTOR(worker_hash_op, void, trivial_hash_func, trivial_compare_func, struct worker, worker_free);
static int worker_new(struct worker **ret, Manager *manager, sd_device_monitor *worker_monitor, pid_t pid) {
- _cleanup_free_ struct worker *worker = NULL;
+ _cleanup_(worker_freep) struct worker *worker = NULL;
int r;
assert(ret);
@@ -206,17 +198,20 @@ static int worker_new(struct worker **ret, Manager *manager, sd_device_monitor *
assert(worker_monitor);
assert(pid > 1);
- worker = new0(struct worker, 1);
+ /* close monitor, but keep address around */
+ device_monitor_disconnect(worker_monitor);
+
+ worker = new(struct worker, 1);
if (!worker)
return -ENOMEM;
- worker->manager = manager;
- /* close monitor, but keep address around */
- device_monitor_disconnect(worker_monitor);
- worker->monitor = sd_device_monitor_ref(worker_monitor);
- worker->pid = pid;
+ *worker = (struct worker) {
+ .manager = manager,
+ .monitor = sd_device_monitor_ref(worker_monitor),
+ .pid = pid,
+ };
- r = hashmap_ensure_allocated(&manager->workers, NULL);
+ r = hashmap_ensure_allocated(&manager->workers, &worker_hash_op);
if (r < 0)
return r;
@@ -290,7 +285,7 @@ static void manager_clear_for_worker(Manager *manager) {
manager->event = sd_event_unref(manager->event);
- manager_workers_free(manager);
+ manager->workers = hashmap_free(manager->workers);
event_queue_cleanup(manager, EVENT_UNDEF);
manager->monitor = sd_device_monitor_unref(manager->monitor);
@@ -396,7 +391,7 @@ static int worker_lock_block_device(sd_device *dev, int *ret_fd) {
static int worker_process_device(Manager *manager, sd_device *dev) {
_cleanup_(udev_event_freep) UdevEvent *udev_event = NULL;
_cleanup_close_ int fd_lock = -1;
- const char *seqnum;
+ const char *seqnum, *action;
int r;
assert(manager);
@@ -404,9 +399,13 @@ static int worker_process_device(Manager *manager, sd_device *dev) {
r = sd_device_get_property_value(dev, "SEQNUM", &seqnum);
if (r < 0)
- log_device_debug_errno(dev, r, "Failed to get SEQNUM: %m");
+ return log_device_debug_errno(dev, r, "Failed to get SEQNUM: %m");
- log_device_debug(dev, "Processing device (SEQNUM=%s)", seqnum);
+ r = sd_device_get_property_value(dev, "ACTION", &action);
+ if (r < 0)
+ return log_device_debug_errno(dev, r, "Failed to get ACTION: %m");
+
+ log_device_debug(dev, "Processing device (SEQNUM=%s, ACTION=%s)", seqnum, action);
udev_event = udev_event_new(dev, arg_exec_delay_usec, manager->rtnl);
if (!udev_event)
@@ -432,7 +431,7 @@ static int worker_process_device(Manager *manager, sd_device *dev) {
return log_device_debug_errno(dev, r, "Failed to update database under /run/udev/data/: %m");
}
- log_device_debug(dev, "Device (SEQNUM=%s) processed", seqnum);
+ log_device_debug(dev, "Device (SEQNUM=%s, ACTION=%s) processed", seqnum, action);
return 0;
}
@@ -464,7 +463,7 @@ static int worker_device_monitor_handler(sd_device_monitor *monitor, sd_device *
static int worker_main(Manager *_manager, sd_device_monitor *monitor, sd_device *first_device) {
_cleanup_(sd_device_unrefp) sd_device *dev = first_device;
_cleanup_(manager_freep) Manager *manager = _manager;
- int r, ret;
+ int r;
assert(manager);
assert(monitor);
@@ -507,11 +506,7 @@ static int worker_main(Manager *_manager, sd_device_monitor *monitor, sd_device
if (r < 0)
return log_error_errno(r, "Event loop failed: %m");
- r = sd_event_get_exit_code(manager->event, &ret);
- if (r < 0)
- return log_error_errno(r, "Failed to get exit code: %m");
-
- return ret;
+ return 0;
}
static int worker_spawn(Manager *manager, struct event *event) {
@@ -534,7 +529,7 @@ static int worker_spawn(Manager *manager, struct event *event) {
if (r < 0)
return log_error_errno(r, "Worker: Failed to enable receiving of device: %m");
- r = safe_fork("(worker)", FORK_DEATHSIG, &pid);
+ r = safe_fork(NULL, FORK_DEATHSIG, &pid);
if (r < 0) {
event->state = EVENT_QUEUED;
return log_error_errno(r, "Failed to fork() worker: %m");
@@ -592,8 +587,8 @@ static void event_run(Manager *manager, struct event *event) {
static int event_queue_insert(Manager *manager, sd_device *dev) {
_cleanup_(sd_device_unrefp) sd_device *clone = NULL;
+ const char *val, *action;
struct event *event;
- const char *val;
uint64_t seqnum;
int r;
@@ -618,6 +613,11 @@ static int event_queue_insert(Manager *manager, sd_device *dev) {
if (seqnum == 0)
return -EINVAL;
+ /* Refuse devices do not have ACTION property. */
+ r = sd_device_get_property_value(dev, "ACTION", &action);
+ if (r < 0)
+ return r;
+
/* Save original device to restore the state on failures. */
r = device_shallow_clone(dev, &clone);
if (r < 0)
@@ -647,12 +647,7 @@ static int event_queue_insert(Manager *manager, sd_device *dev) {
LIST_APPEND(event, manager->events, event);
- if (DEBUG_LOGGING) {
- if (sd_device_get_property_value(dev, "ACTION", &val) < 0)
- val = NULL;
-
- log_device_debug(dev, "Device (SEQNUM=%"PRIu64", ACTION=%s) is queued", seqnum, strnull(val));
- }
+ log_device_debug(dev, "Device (SEQNUM=%"PRIu64", ACTION=%s) is queued", seqnum, action);
return 0;
}
@@ -875,7 +870,7 @@ static void event_queue_start(Manager *manager) {
assert_se(sd_event_now(manager->event, CLOCK_MONOTONIC, &usec) >= 0);
/* check for changed config, every 3 seconds at most */
if (manager->last_usec == 0 ||
- (usec - manager->last_usec) > 3 * USEC_PER_SEC) {
+ usec - manager->last_usec > 3 * USEC_PER_SEC) {
if (udev_rules_check_timestamp(manager->rules) ||
udev_builtin_validate())
manager_reload(manager);
@@ -960,12 +955,11 @@ static int on_worker(sd_event_source *s, int fd, uint32_t revents, void *userdat
continue;
}
- CMSG_FOREACH(cmsg, &msghdr) {
+ CMSG_FOREACH(cmsg, &msghdr)
if (cmsg->cmsg_level == SOL_SOCKET &&
cmsg->cmsg_type == SCM_CREDENTIALS &&
cmsg->cmsg_len == CMSG_LEN(sizeof(struct ucred)))
ucred = (struct ucred*) CMSG_DATA(cmsg);
- }
if (!ucred || ucred->pid <= 0) {
log_warning("Ignoring worker message without valid PID");
@@ -1033,7 +1027,8 @@ static int on_ctrl_msg(sd_event_source *s, int fd, uint32_t revents, void *userd
i = udev_ctrl_get_set_log_level(ctrl_msg);
if (i >= 0) {
log_debug("Received udev control message (SET_LOG_LEVEL), setting log_priority=%i", i);
- log_set_max_level(i);
+ log_set_max_level_realm(LOG_REALM_UDEV, i);
+ log_set_max_level_realm(LOG_REALM_SYSTEMD, i);
manager_kill_workers(manager);
}
@@ -1118,7 +1113,7 @@ static int on_ctrl_msg(sd_event_source *s, int fd, uint32_t revents, void *userd
}
if (udev_ctrl_get_ping(ctrl_msg) > 0)
- log_debug("Received udev control message (SYNC)");
+ log_debug("Received udev control message (PING)");
if (udev_ctrl_get_exit(ctrl_msg) > 0) {
log_debug("Received udev control message (EXIT)");
@@ -1338,9 +1333,9 @@ static int on_sigchld(sd_event_source *s, const struct signalfd_siginfo *si, voi
log_debug("Worker ["PID_FMT"] exited", pid);
else
log_warning("Worker ["PID_FMT"] exited with return code %i", pid, WEXITSTATUS(status));
- } else if (WIFSIGNALED(status)) {
+ } else if (WIFSIGNALED(status))
log_warning("Worker ["PID_FMT"] terminated by signal %i (%s)", pid, WTERMSIG(status), signal_to_string(WTERMSIG(status)));
- } else if (WIFSTOPPED(status)) {
+ else if (WIFSTOPPED(status)) {
log_info("Worker ["PID_FMT"] stopped", pid);
continue;
} else if (WIFCONTINUED(status)) {
@@ -1579,7 +1574,7 @@ static int parse_argv(int argc, char *argv[]) {
case 'h':
return help();
case 'V':
- printf("%s\n", PACKAGE_VERSION);
+ printf("%s\n", GIT_VERSION);
return 0;
case '?':
return -EINVAL;
@@ -1594,7 +1589,7 @@ static int parse_argv(int argc, char *argv[]) {
static int manager_new(Manager **ret, int fd_ctrl, int fd_uevent, const char *cgroup) {
_cleanup_(manager_freep) Manager *manager = NULL;
- int r, fd_worker;
+ int r;
assert(ret);
@@ -1608,25 +1603,13 @@ static int manager_new(Manager **ret, int fd_ctrl, int fd_uevent, const char *cg
.cgroup = cgroup,
};
- udev_builtin_init();
-
- r = udev_rules_new(&manager->rules, arg_resolve_name_timing);
- if (!manager->rules)
- return log_error_errno(r, "Failed to read udev rules: %m");
-
manager->ctrl = udev_ctrl_new_from_fd(fd_ctrl);
if (!manager->ctrl)
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Failed to initialize udev control socket");
- if (fd_ctrl < 0) {
- r = udev_ctrl_enable_receiving(manager->ctrl);
- if (r < 0)
- return log_error_errno(r, "Failed to bind udev control socket: %m");
- }
-
- fd_ctrl = udev_ctrl_get_fd(manager->ctrl);
- if (fd_ctrl < 0)
- return log_error_errno(fd_ctrl, "Failed to get udev control socket fd: %m");
+ r = udev_ctrl_enable_receiving(manager->ctrl);
+ if (r < 0)
+ return log_error_errno(r, "Failed to bind udev control socket: %m");
r = device_monitor_new_full(&manager->monitor, MONITOR_GROUP_KERNEL, fd_uevent);
if (r < 0)
@@ -1634,6 +1617,18 @@ static int manager_new(Manager **ret, int fd_ctrl, int fd_uevent, const char *cg
(void) sd_device_monitor_set_receive_buffer_size(manager->monitor, 128 * 1024 * 1024);
+ r = device_monitor_enable_receiving(manager->monitor);
+ if (r < 0)
+ return log_error_errno(r, "Failed to bind netlink socket: %m");
+
+ *ret = TAKE_PTR(manager);
+
+ return 0;
+}
+
+static int main_loop(Manager *manager) {
+ int fd_worker, fd_ctrl, r;
+
/* unnamed socket from workers to the main daemon */
r = socketpair(AF_LOCAL, SOCK_DGRAM|SOCK_CLOEXEC, 0, manager->worker_watch);
if (r < 0)
@@ -1679,6 +1674,10 @@ static int manager_new(Manager **ret, int fd_ctrl, int fd_uevent, const char *cg
if (r < 0)
return log_error_errno(r, "Failed to create watchdog event source: %m");
+ fd_ctrl = udev_ctrl_get_fd(manager->ctrl);
+ if (fd_ctrl < 0)
+ return log_error_errno(fd_ctrl, "Failed to get udev control socket fd: %m");
+
r = sd_event_add_io(manager->event, &manager->ctrl_event, fd_ctrl, EPOLLIN, on_ctrl_msg, manager);
if (r < 0)
return log_error_errno(r, "Failed to create udev control event source: %m");
@@ -1713,20 +1712,11 @@ static int manager_new(Manager **ret, int fd_ctrl, int fd_uevent, const char *cg
if (r < 0)
return log_error_errno(r, "Failed to create post event source: %m");
- *ret = TAKE_PTR(manager);
-
- return 0;
-}
-
-static int main_loop(int fd_ctrl, int fd_uevent, const char *cgroup) {
- _cleanup_(manager_freep) Manager *manager = NULL;
- int r;
+ udev_builtin_init();
- r = manager_new(&manager, fd_ctrl, fd_uevent, cgroup);
- if (r < 0) {
- r = log_error_errno(r, "Failed to allocate manager object: %m");
- goto exit;
- }
+ r = udev_rules_new(&manager->rules, arg_resolve_name_timing);
+ if (!manager->rules)
+ return log_error_errno(r, "Failed to read udev rules: %m");
r = udev_rules_apply_static_dev_perms(manager->rules);
if (r < 0)
@@ -1737,24 +1727,18 @@ static int main_loop(int fd_ctrl, int fd_uevent, const char *cgroup) {
"STATUS=Processing with %u children at max", arg_children_max);
r = sd_event_loop(manager->event);
- if (r < 0) {
+ if (r < 0)
log_error_errno(r, "Event loop failed: %m");
- goto exit;
- }
- sd_event_get_exit_code(manager->event, &r);
-
-exit:
sd_notify(false,
"STOPPING=1\n"
"STATUS=Shutting down...");
- if (manager)
- udev_ctrl_cleanup(manager->ctrl);
return r;
}
static int run(int argc, char *argv[]) {
_cleanup_free_ char *cgroup = NULL;
+ _cleanup_(manager_freep) Manager *manager = NULL;
int fd_ctrl = -1, fd_uevent = -1;
int r;
@@ -1814,10 +1798,10 @@ static int run(int argc, char *argv[]) {
dev_setup(NULL, UID_INVALID, GID_INVALID);
- if (getppid() == 1) {
- /* get our own cgroup, we regularly kill everything udev has left behind
- we only do this on systemd systems, and only if we are directly spawned
- by PID1. otherwise we are not guaranteed to have a dedicated cgroup */
+ if (getppid() == 1 && sd_booted() > 0) {
+ /* Get our own cgroup, we regularly kill everything udev has left behind.
+ * We only do this on systemd systems, and only if we are directly spawned
+ * by PID1. Otherwise we are not guaranteed to have a dedicated cgroup. */
r = cg_pid_get_path(SYSTEMD_CGROUP_CONTROLLER, 0, &cgroup);
if (r < 0) {
if (IN_SET(r, -ENOENT, -ENOMEDIUM))
@@ -1831,10 +1815,14 @@ static int run(int argc, char *argv[]) {
if (r < 0)
return log_error_errno(r, "Failed to listen on fds: %m");
+ r = manager_new(&manager, fd_ctrl, fd_uevent, cgroup);
+ if (r < 0)
+ return log_error_errno(r, "Failed to create manager: %m");
+
if (arg_daemonize) {
pid_t pid;
- log_info("starting version " PACKAGE_VERSION);
+ log_info("Starting version " GIT_VERSION);
/* connect /dev/null to stdin, stdout, stderr */
if (log_get_max_level() < LOG_DEBUG) {
@@ -1858,7 +1846,10 @@ static int run(int argc, char *argv[]) {
log_debug_errno(r, "Failed to adjust OOM score, ignoring: %m");
}
- return main_loop(fd_ctrl, fd_uevent, cgroup);
+ r = main_loop(manager);
+ /* FIXME: move this into manager_free() */
+ udev_ctrl_cleanup(manager->ctrl);
+ return r;
}
DEFINE_MAIN_FUNCTION(run);