mirror of
https://github.com/systemd/systemd-stable.git
synced 2024-10-27 10:25:06 +03:00
udevd: pass a Manager objcet to event handlers
Stop relying on global variables in event handlers, and move them all to a Manager object instead.
This commit is contained in:
parent
b40c3dfa32
commit
c0c6806bf9
327
src/udev/udevd.c
327
src/udev/udevd.c
@ -52,15 +52,10 @@
|
||||
#include "hashmap.h"
|
||||
|
||||
static struct udev_rules *rules;
|
||||
static struct udev_ctrl *udev_ctrl;
|
||||
static struct udev_ctrl_connection *udev_ctrl_conn;
|
||||
static struct udev_monitor *monitor;
|
||||
static int worker_watch[2] = { -1, -1 };
|
||||
static int fd_signal = -1;
|
||||
static int fd_ep = -1;
|
||||
static int fd_inotify = -1;
|
||||
static bool stop_exec_queue;
|
||||
static bool reload;
|
||||
static bool arg_debug = false;
|
||||
static int arg_daemonize = false;
|
||||
static int arg_resolve_names = 1;
|
||||
@ -70,10 +65,22 @@ static usec_t arg_event_timeout_usec = 180 * USEC_PER_SEC;
|
||||
static usec_t arg_event_timeout_warn_usec = 180 * USEC_PER_SEC / 3;
|
||||
static sigset_t sigmask_orig;
|
||||
static UDEV_LIST(event_list);
|
||||
Hashmap *workers;
|
||||
static char *udev_cgroup;
|
||||
static struct udev_list properties_list;
|
||||
static bool udev_exit;
|
||||
|
||||
typedef struct Manager {
|
||||
struct udev *udev;
|
||||
Hashmap *workers;
|
||||
|
||||
struct udev_list properties;
|
||||
|
||||
struct udev_monitor *monitor;
|
||||
struct udev_ctrl *ctrl;
|
||||
struct udev_ctrl_connection *ctrl_conn_blocking;
|
||||
|
||||
bool stop_exec_queue:1;
|
||||
bool reload:1;
|
||||
bool exit:1;
|
||||
} Manager;
|
||||
|
||||
enum event_state {
|
||||
EVENT_UNDEF,
|
||||
@ -114,8 +121,8 @@ enum worker_state {
|
||||
};
|
||||
|
||||
struct worker {
|
||||
Manager *manager;
|
||||
struct udev_list_node node;
|
||||
struct udev *udev;
|
||||
int refcount;
|
||||
pid_t pid;
|
||||
struct udev_monitor *monitor;
|
||||
@ -145,31 +152,33 @@ static void worker_free(struct worker *worker) {
|
||||
if (!worker)
|
||||
return;
|
||||
|
||||
hashmap_remove(workers, UINT_TO_PTR(worker->pid));
|
||||
assert(worker->manager);
|
||||
|
||||
hashmap_remove(worker->manager->workers, UINT_TO_PTR(worker->pid));
|
||||
udev_monitor_unref(worker->monitor);
|
||||
udev_unref(worker->udev);
|
||||
event_free(worker->event);
|
||||
|
||||
free(worker);
|
||||
}
|
||||
|
||||
static void workers_free(void) {
|
||||
static void manager_workers_free(Manager *manager) {
|
||||
struct worker *worker;
|
||||
Iterator i;
|
||||
|
||||
HASHMAP_FOREACH(worker, workers, i)
|
||||
assert(manager);
|
||||
|
||||
HASHMAP_FOREACH(worker, manager->workers, i)
|
||||
worker_free(worker);
|
||||
|
||||
hashmap_free(workers);
|
||||
workers = NULL;
|
||||
manager->workers = hashmap_free(manager->workers);
|
||||
}
|
||||
|
||||
static int worker_new(struct worker **ret, struct udev *udev, struct udev_monitor *worker_monitor, pid_t pid) {
|
||||
static int worker_new(struct worker **ret, Manager *manager, struct udev_monitor *worker_monitor, pid_t pid) {
|
||||
_cleanup_free_ struct worker *worker = NULL;
|
||||
int r;
|
||||
|
||||
assert(ret);
|
||||
assert(udev);
|
||||
assert(manager);
|
||||
assert(worker_monitor);
|
||||
assert(pid > 1);
|
||||
|
||||
@ -178,17 +187,17 @@ static int worker_new(struct worker **ret, struct udev *udev, struct udev_monito
|
||||
return -ENOMEM;
|
||||
|
||||
worker->refcount = 1;
|
||||
worker->udev = udev_ref(udev);
|
||||
worker->manager = manager;
|
||||
/* close monitor, but keep address around */
|
||||
udev_monitor_disconnect(worker_monitor);
|
||||
worker->monitor = udev_monitor_ref(worker_monitor);
|
||||
worker->pid = pid;
|
||||
|
||||
r = hashmap_ensure_allocated(&workers, NULL);
|
||||
r = hashmap_ensure_allocated(&manager->workers, NULL);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = hashmap_put(workers, UINT_TO_PTR(pid), worker);
|
||||
r = hashmap_put(manager->workers, UINT_TO_PTR(pid), worker);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
@ -212,7 +221,7 @@ static void worker_attach_event(struct worker *worker, struct event *event) {
|
||||
event->worker = worker;
|
||||
}
|
||||
|
||||
static void worker_spawn(struct event *event) {
|
||||
static void worker_spawn(Manager *manager, struct event *event) {
|
||||
struct udev *udev = event->udev;
|
||||
_cleanup_udev_monitor_unref_ struct udev_monitor *worker_monitor = NULL;
|
||||
pid_t pid;
|
||||
@ -222,7 +231,7 @@ static void worker_spawn(struct event *event) {
|
||||
if (worker_monitor == NULL)
|
||||
return;
|
||||
/* allow the main daemon netlink address to send devices to the worker */
|
||||
udev_monitor_allow_unicast_sender(worker_monitor, monitor);
|
||||
udev_monitor_allow_unicast_sender(worker_monitor, manager->monitor);
|
||||
udev_monitor_enable_receiving(worker_monitor);
|
||||
|
||||
pid = fork();
|
||||
@ -239,10 +248,10 @@ static void worker_spawn(struct event *event) {
|
||||
dev = event->dev;
|
||||
event->dev = NULL;
|
||||
|
||||
workers_free();
|
||||
manager_workers_free(manager);
|
||||
event_queue_cleanup(udev, EVENT_UNDEF);
|
||||
udev_monitor_unref(monitor);
|
||||
udev_ctrl_unref(udev_ctrl);
|
||||
udev_monitor_unref(manager->monitor);
|
||||
udev_ctrl_unref(manager->ctrl);
|
||||
close(fd_signal);
|
||||
close(fd_ep);
|
||||
close(worker_watch[READ_END]);
|
||||
@ -333,7 +342,7 @@ static void worker_spawn(struct event *event) {
|
||||
/* apply rules, create node, symlinks */
|
||||
udev_event_execute_rules(udev_event,
|
||||
arg_event_timeout_usec, arg_event_timeout_warn_usec,
|
||||
&properties_list,
|
||||
&manager->properties,
|
||||
rules,
|
||||
&sigmask_orig);
|
||||
|
||||
@ -430,7 +439,7 @@ out:
|
||||
struct worker *worker;
|
||||
int r;
|
||||
|
||||
r = worker_new(&worker, udev, worker_monitor, pid);
|
||||
r = worker_new(&worker, manager, worker_monitor, pid);
|
||||
if (r < 0)
|
||||
return;
|
||||
|
||||
@ -442,17 +451,20 @@ out:
|
||||
}
|
||||
}
|
||||
|
||||
static void event_run(struct event *event) {
|
||||
static void event_run(Manager *manager, struct event *event) {
|
||||
struct worker *worker;
|
||||
Iterator i;
|
||||
|
||||
HASHMAP_FOREACH(worker, workers, i) {
|
||||
assert(manager);
|
||||
assert(event);
|
||||
|
||||
HASHMAP_FOREACH(worker, manager->workers, i) {
|
||||
ssize_t count;
|
||||
|
||||
if (worker->state != WORKER_IDLE)
|
||||
continue;
|
||||
|
||||
count = udev_monitor_send_device(monitor, worker->monitor, event->dev);
|
||||
count = udev_monitor_send_device(manager->monitor, worker->monitor, event->dev);
|
||||
if (count < 0) {
|
||||
log_error_errno(errno, "worker ["PID_FMT"] did not accept message %zi (%m), kill it",
|
||||
worker->pid, count);
|
||||
@ -464,14 +476,14 @@ static void event_run(struct event *event) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (hashmap_size(workers) >= arg_children_max) {
|
||||
if (hashmap_size(manager->workers) >= arg_children_max) {
|
||||
if (arg_children_max > 1)
|
||||
log_debug("maximum number (%i) of children reached", hashmap_size(workers));
|
||||
log_debug("maximum number (%i) of children reached", hashmap_size(manager->workers));
|
||||
return;
|
||||
}
|
||||
|
||||
/* start new worker and pass initial device */
|
||||
worker_spawn(event);
|
||||
worker_spawn(manager, event);
|
||||
}
|
||||
|
||||
static int event_queue_insert(struct udev_device *dev) {
|
||||
@ -501,11 +513,13 @@ static int event_queue_insert(struct udev_device *dev) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void worker_kill(void) {
|
||||
static void manager_kill_workers(Manager *manager) {
|
||||
struct worker *worker;
|
||||
Iterator i;
|
||||
|
||||
HASHMAP_FOREACH(worker, workers, i) {
|
||||
assert(manager);
|
||||
|
||||
HASHMAP_FOREACH(worker, manager->workers, i) {
|
||||
if (worker->state == WORKER_KILLED)
|
||||
continue;
|
||||
|
||||
@ -586,9 +600,11 @@ static bool is_devpath_busy(struct event *event) {
|
||||
return false;
|
||||
}
|
||||
|
||||
static void event_queue_start(struct udev *udev) {
|
||||
static void event_queue_start(Manager *manager) {
|
||||
struct udev_list_node *loop;
|
||||
|
||||
assert(manager);
|
||||
|
||||
udev_list_node_foreach(loop, &event_list) {
|
||||
struct event *event = node_to_event(loop);
|
||||
|
||||
@ -599,7 +615,7 @@ static void event_queue_start(struct udev *udev) {
|
||||
if (is_devpath_busy(event))
|
||||
continue;
|
||||
|
||||
event_run(event);
|
||||
event_run(manager, event);
|
||||
}
|
||||
}
|
||||
|
||||
@ -617,6 +633,10 @@ static void event_queue_cleanup(struct udev *udev, enum event_state match_type)
|
||||
}
|
||||
|
||||
static int on_worker(sd_event_source *s, int fd, uint32_t revents, void *userdata) {
|
||||
Manager *manager = userdata;
|
||||
|
||||
assert(manager);
|
||||
|
||||
for (;;) {
|
||||
struct worker_message msg;
|
||||
struct iovec iovec = {
|
||||
@ -662,7 +682,7 @@ static int on_worker(sd_event_source *s, int fd, uint32_t revents, void *userdat
|
||||
}
|
||||
|
||||
/* lookup worker who sent the signal */
|
||||
worker = hashmap_get(workers, UINT_TO_PTR(ucred->pid));
|
||||
worker = hashmap_get(manager->workers, UINT_TO_PTR(ucred->pid));
|
||||
if (!worker) {
|
||||
log_debug("worker ["PID_FMT"] returned, but is no longer tracked", ucred->pid);
|
||||
continue;
|
||||
@ -679,13 +699,13 @@ static int on_worker(sd_event_source *s, int fd, uint32_t revents, void *userdat
|
||||
}
|
||||
|
||||
static int on_uevent(sd_event_source *s, int fd, uint32_t revents, void *userdata) {
|
||||
struct udev_monitor *m = userdata;
|
||||
Manager *manager = userdata;
|
||||
struct udev_device *dev;
|
||||
int r;
|
||||
|
||||
assert(m);
|
||||
assert(manager);
|
||||
|
||||
dev = udev_monitor_receive_device(m);
|
||||
dev = udev_monitor_receive_device(manager->monitor);
|
||||
if (dev) {
|
||||
udev_device_ensure_usec_initialized(dev, NULL);
|
||||
r = event_queue_insert(dev);
|
||||
@ -712,15 +732,15 @@ static void event_queue_update(void) {
|
||||
|
||||
/* receive the udevd message from userspace */
|
||||
static int on_ctrl_msg(sd_event_source *s, int fd, uint32_t revents, void *userdata) {
|
||||
struct udev_ctrl *uctrl = userdata;
|
||||
Manager *manager = userdata;
|
||||
_cleanup_udev_ctrl_connection_unref_ struct udev_ctrl_connection *ctrl_conn = NULL;
|
||||
_cleanup_udev_ctrl_msg_unref_ struct udev_ctrl_msg *ctrl_msg = NULL;
|
||||
const char *str;
|
||||
int i;
|
||||
|
||||
assert(uctrl);
|
||||
assert(manager);
|
||||
|
||||
ctrl_conn = udev_ctrl_get_connection(uctrl);
|
||||
ctrl_conn = udev_ctrl_get_connection(manager->ctrl);
|
||||
if (!ctrl_conn)
|
||||
return 1;
|
||||
|
||||
@ -732,30 +752,30 @@ static int on_ctrl_msg(sd_event_source *s, int fd, uint32_t revents, void *userd
|
||||
if (i >= 0) {
|
||||
log_debug("udevd message (SET_LOG_LEVEL) received, log_priority=%i", i);
|
||||
log_set_max_level(i);
|
||||
worker_kill();
|
||||
manager_kill_workers(manager);
|
||||
}
|
||||
|
||||
if (udev_ctrl_get_stop_exec_queue(ctrl_msg) > 0) {
|
||||
log_debug("udevd message (STOP_EXEC_QUEUE) received");
|
||||
stop_exec_queue = true;
|
||||
manager->stop_exec_queue = true;
|
||||
}
|
||||
|
||||
if (udev_ctrl_get_start_exec_queue(ctrl_msg) > 0) {
|
||||
log_debug("udevd message (START_EXEC_QUEUE) received");
|
||||
stop_exec_queue = false;
|
||||
manager->stop_exec_queue = false;
|
||||
}
|
||||
|
||||
if (udev_ctrl_get_reload(ctrl_msg) > 0) {
|
||||
log_debug("udevd message (RELOAD) received");
|
||||
reload = true;
|
||||
manager->reload = true;
|
||||
}
|
||||
|
||||
str = udev_ctrl_get_set_env(ctrl_msg);
|
||||
if (str != NULL) {
|
||||
char *key;
|
||||
_cleanup_free_ char *key = NULL;
|
||||
|
||||
key = strdup(str);
|
||||
if (key != NULL) {
|
||||
if (key) {
|
||||
char *val;
|
||||
|
||||
val = strchr(key, '=');
|
||||
@ -764,17 +784,15 @@ static int on_ctrl_msg(sd_event_source *s, int fd, uint32_t revents, void *userd
|
||||
val = &val[1];
|
||||
if (val[0] == '\0') {
|
||||
log_debug("udevd message (ENV) received, unset '%s'", key);
|
||||
udev_list_entry_add(&properties_list, key, NULL);
|
||||
udev_list_entry_add(&manager->properties, key, NULL);
|
||||
} else {
|
||||
log_debug("udevd message (ENV) received, set '%s=%s'", key, val);
|
||||
udev_list_entry_add(&properties_list, key, val);
|
||||
udev_list_entry_add(&manager->properties, key, val);
|
||||
}
|
||||
} else {
|
||||
} else
|
||||
log_error("wrong key format '%s'", key);
|
||||
}
|
||||
free(key);
|
||||
}
|
||||
worker_kill();
|
||||
manager_kill_workers(manager);
|
||||
}
|
||||
|
||||
i = udev_ctrl_get_set_children_max(ctrl_msg);
|
||||
@ -793,9 +811,10 @@ static int on_ctrl_msg(sd_event_source *s, int fd, uint32_t revents, void *userd
|
||||
|
||||
if (udev_ctrl_get_exit(ctrl_msg) > 0) {
|
||||
log_debug("udevd message (EXIT) received");
|
||||
udev_exit = true;
|
||||
/* keep reference to block the client until we exit */
|
||||
udev_ctrl_conn = udev_ctrl_connection_ref(ctrl_conn);
|
||||
manager->exit = true;
|
||||
/* keep reference to block the client until we exit
|
||||
TODO: deal with several blocking exit requests */
|
||||
manager->ctrl_conn_blocking = udev_ctrl_connection_ref(ctrl_conn);
|
||||
}
|
||||
|
||||
return 1;
|
||||
@ -906,12 +925,12 @@ static int synthesize_change(struct udev_device *dev) {
|
||||
}
|
||||
|
||||
static int on_inotify(sd_event_source *s, int fd, uint32_t revents, void *userdata) {
|
||||
struct udev *udev = userdata;
|
||||
Manager *manager = userdata;
|
||||
union inotify_event_buffer buffer;
|
||||
struct inotify_event *e;
|
||||
ssize_t l;
|
||||
|
||||
assert(udev);
|
||||
assert(manager);
|
||||
|
||||
l = read(fd, &buffer, sizeof(buffer));
|
||||
if (l < 0) {
|
||||
@ -924,7 +943,7 @@ static int on_inotify(sd_event_source *s, int fd, uint32_t revents, void *userda
|
||||
FOREACH_INOTIFY_EVENT(e, buffer, l) {
|
||||
_cleanup_udev_device_unref_ struct udev_device *dev = NULL;
|
||||
|
||||
dev = udev_watch_lookup(udev, e->wd);
|
||||
dev = udev_watch_lookup(manager->udev, e->wd);
|
||||
if (!dev)
|
||||
continue;
|
||||
|
||||
@ -937,27 +956,39 @@ static int on_inotify(sd_event_source *s, int fd, uint32_t revents, void *userda
|
||||
* generated a "change" event, but we won't have queued up
|
||||
* the resultant uevent yet. Do that.
|
||||
*/
|
||||
on_uevent(NULL, -1, 0, monitor);
|
||||
on_uevent(NULL, -1, 0, manager);
|
||||
} else if (e->mask & IN_IGNORED)
|
||||
udev_watch_end(udev, dev);
|
||||
udev_watch_end(manager->udev, dev);
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int on_request_exit(sd_event_source *s, const struct signalfd_siginfo *si, void *userdata) {
|
||||
udev_exit = true;
|
||||
Manager *manager = userdata;
|
||||
|
||||
assert(manager);
|
||||
|
||||
manager->exit = true;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int on_request_reload(sd_event_source *s, const struct signalfd_siginfo *si, void *userdata) {
|
||||
reload = true;
|
||||
Manager *manager = userdata;
|
||||
|
||||
assert(manager);
|
||||
|
||||
manager->reload = true;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int on_sigchld(sd_event_source *s, const struct signalfd_siginfo *si, void *userdata) {
|
||||
Manager *manager = userdata;
|
||||
|
||||
assert(manager);
|
||||
|
||||
for (;;) {
|
||||
pid_t pid;
|
||||
int status;
|
||||
@ -967,7 +998,7 @@ static int on_sigchld(sd_event_source *s, const struct signalfd_siginfo *si, voi
|
||||
if (pid <= 0)
|
||||
return 1;
|
||||
|
||||
worker = hashmap_get(workers, UINT_TO_PTR(pid));
|
||||
worker = hashmap_get(manager->workers, UINT_TO_PTR(pid));
|
||||
if (!worker) {
|
||||
log_warning("worker ["PID_FMT"] is unknown, ignoring", pid);
|
||||
return 1;
|
||||
@ -996,7 +1027,7 @@ static int on_sigchld(sd_event_source *s, const struct signalfd_siginfo *si, voi
|
||||
udev_device_delete_db(worker->event->dev);
|
||||
udev_device_tag_index(worker->event->dev, NULL, false);
|
||||
/* forward kernel event without amending it */
|
||||
udev_monitor_send_device(monitor, NULL, worker->event->dev_kernel);
|
||||
udev_monitor_send_device(manager->monitor, NULL, worker->event->dev_kernel);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1006,7 +1037,7 @@ static int on_sigchld(sd_event_source *s, const struct signalfd_siginfo *si, voi
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int systemd_fds(struct udev *udev, int *rctrl, int *rnetlink) {
|
||||
static int systemd_fds(int *rctrl, int *rnetlink) {
|
||||
int ctrl = -1, netlink = -1;
|
||||
int fd, n;
|
||||
|
||||
@ -1182,8 +1213,45 @@ static int parse_argv(int argc, char *argv[]) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void manager_free(Manager *manager) {
|
||||
if (!manager)
|
||||
return;
|
||||
|
||||
udev_unref(manager->udev);
|
||||
manager_workers_free(manager);
|
||||
|
||||
udev_monitor_unref(manager->monitor);
|
||||
udev_ctrl_unref(manager->ctrl);
|
||||
udev_ctrl_connection_unref(manager->ctrl_conn_blocking);
|
||||
|
||||
udev_list_cleanup(&manager->properties);
|
||||
|
||||
free(manager);
|
||||
}
|
||||
|
||||
DEFINE_TRIVIAL_CLEANUP_FUNC(Manager*, manager_free);
|
||||
|
||||
static int manager_new(Manager **ret) {
|
||||
_cleanup_(manager_freep) Manager *manager = NULL;
|
||||
|
||||
assert(ret);
|
||||
|
||||
manager = new0(Manager, 1);
|
||||
if (!manager)
|
||||
return log_oom();
|
||||
|
||||
manager->udev = udev_new();
|
||||
if (!manager->udev)
|
||||
return log_error_errno(errno, "could not allocate udev context: %m");
|
||||
|
||||
*ret = manager;
|
||||
manager = NULL;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
struct udev *udev;
|
||||
_cleanup_(manager_freep) Manager *manager = NULL;
|
||||
sigset_t mask;
|
||||
int fd_ctrl = -1;
|
||||
int fd_netlink = -1;
|
||||
@ -1195,16 +1263,14 @@ int main(int argc, char *argv[]) {
|
||||
struct epoll_event ep_worker = { .events = EPOLLIN };
|
||||
int r = 0, one = 1;
|
||||
|
||||
udev = udev_new();
|
||||
if (!udev) {
|
||||
r = log_error_errno(errno, "could not allocate udev context: %m");
|
||||
goto exit;
|
||||
}
|
||||
|
||||
log_set_target(LOG_TARGET_AUTO);
|
||||
log_parse_environment();
|
||||
log_open();
|
||||
|
||||
r = manager_new(&manager);
|
||||
if (r < 0)
|
||||
goto exit;
|
||||
|
||||
r = parse_argv(argc, argv);
|
||||
if (r <= 0)
|
||||
goto exit;
|
||||
@ -1236,7 +1302,7 @@ int main(int argc, char *argv[]) {
|
||||
|
||||
umask(022);
|
||||
|
||||
udev_list_init(udev, &properties_list, true);
|
||||
udev_list_init(manager->udev, &manager->properties, true);
|
||||
|
||||
r = mkdir("/run/udev", 0755);
|
||||
if (r < 0 && errno != EEXIST) {
|
||||
@ -1263,16 +1329,16 @@ int main(int argc, char *argv[]) {
|
||||
}
|
||||
}
|
||||
|
||||
if (systemd_fds(udev, &fd_ctrl, &fd_netlink) >= 0) {
|
||||
if (systemd_fds(&fd_ctrl, &fd_netlink) >= 0) {
|
||||
/* get control and netlink socket from systemd */
|
||||
udev_ctrl = udev_ctrl_new_from_fd(udev, fd_ctrl);
|
||||
if (!udev_ctrl) {
|
||||
manager->ctrl = udev_ctrl_new_from_fd(manager->udev, fd_ctrl);
|
||||
if (!manager->ctrl) {
|
||||
r = log_error_errno(EINVAL, "error taking over udev control socket");
|
||||
goto exit;
|
||||
}
|
||||
|
||||
monitor = udev_monitor_new_from_netlink_fd(udev, "kernel", fd_netlink);
|
||||
if (!monitor) {
|
||||
manager->monitor = udev_monitor_new_from_netlink_fd(manager->udev, "kernel", fd_netlink);
|
||||
if (!manager->monitor) {
|
||||
r = log_error_errno(EINVAL, "error taking over netlink socket");
|
||||
goto exit;
|
||||
}
|
||||
@ -1282,38 +1348,38 @@ int main(int argc, char *argv[]) {
|
||||
udev_cgroup = NULL;
|
||||
} else {
|
||||
/* open control and netlink socket */
|
||||
udev_ctrl = udev_ctrl_new(udev);
|
||||
if (!udev_ctrl) {
|
||||
manager->ctrl = udev_ctrl_new(manager->udev);
|
||||
if (!manager->ctrl) {
|
||||
r = log_error_errno(EINVAL, "error initializing udev control socket");
|
||||
goto exit;
|
||||
}
|
||||
fd_ctrl = udev_ctrl_get_fd(udev_ctrl);
|
||||
fd_ctrl = udev_ctrl_get_fd(manager->ctrl);
|
||||
|
||||
monitor = udev_monitor_new_from_netlink(udev, "kernel");
|
||||
if (!monitor) {
|
||||
manager->monitor = udev_monitor_new_from_netlink(manager->udev, "kernel");
|
||||
if (!manager->monitor) {
|
||||
r = log_error_errno(EINVAL, "error initializing netlink socket");
|
||||
goto exit;
|
||||
}
|
||||
fd_netlink = udev_monitor_get_fd(monitor);
|
||||
fd_netlink = udev_monitor_get_fd(manager->monitor);
|
||||
|
||||
udev_monitor_set_receive_buffer_size(monitor, 128 * 1024 * 1024);
|
||||
udev_monitor_set_receive_buffer_size(manager->monitor, 128 * 1024 * 1024);
|
||||
}
|
||||
|
||||
if (udev_monitor_enable_receiving(monitor) < 0) {
|
||||
if (udev_monitor_enable_receiving(manager->monitor) < 0) {
|
||||
r = log_error_errno(EINVAL, "error binding netlink socket");
|
||||
goto exit;
|
||||
}
|
||||
|
||||
if (udev_ctrl_enable_receiving(udev_ctrl) < 0) {
|
||||
if (udev_ctrl_enable_receiving(manager->ctrl) < 0) {
|
||||
r = log_error_errno(EINVAL, "error binding udev control socket");
|
||||
goto exit;
|
||||
}
|
||||
|
||||
log_info("starting version " VERSION);
|
||||
|
||||
udev_builtin_init(udev);
|
||||
udev_builtin_init(manager->udev);
|
||||
|
||||
rules = udev_rules_new(udev, arg_resolve_names);
|
||||
rules = udev_rules_new(manager->udev, arg_resolve_names);
|
||||
if (!rules) {
|
||||
r = log_error_errno(ENOMEM, "error reading rules");
|
||||
goto exit;
|
||||
@ -1357,12 +1423,12 @@ int main(int argc, char *argv[]) {
|
||||
|
||||
udev_list_node_init(&event_list);
|
||||
|
||||
fd_inotify = udev_watch_init(udev);
|
||||
fd_inotify = udev_watch_init(manager->udev);
|
||||
if (fd_inotify < 0) {
|
||||
r = log_error_errno(ENOMEM, "error initializing inotify");
|
||||
goto exit;
|
||||
}
|
||||
udev_watch_restore(udev);
|
||||
udev_watch_restore(manager->udev);
|
||||
|
||||
/* block and listen to all signals on signalfd */
|
||||
sigfillset(&mask);
|
||||
@ -1412,16 +1478,15 @@ int main(int argc, char *argv[]) {
|
||||
bool is_worker, is_signal, is_inotify, is_netlink, is_ctrl;
|
||||
int i;
|
||||
|
||||
if (udev_exit) {
|
||||
if (manager->exit) {
|
||||
/* close sources of new events and discard buffered events */
|
||||
if (fd_ctrl >= 0) {
|
||||
epoll_ctl(fd_ep, EPOLL_CTL_DEL, fd_ctrl, NULL);
|
||||
fd_ctrl = -1;
|
||||
}
|
||||
if (monitor != NULL) {
|
||||
if (manager->monitor) {
|
||||
epoll_ctl(fd_ep, EPOLL_CTL_DEL, fd_netlink, NULL);
|
||||
udev_monitor_unref(monitor);
|
||||
monitor = NULL;
|
||||
manager->monitor = udev_monitor_unref(manager->monitor);
|
||||
}
|
||||
if (fd_inotify >= 0) {
|
||||
epoll_ctl(fd_ep, EPOLL_CTL_DEL, fd_inotify, NULL);
|
||||
@ -1430,16 +1495,16 @@ int main(int argc, char *argv[]) {
|
||||
}
|
||||
|
||||
/* discard queued events and kill workers */
|
||||
event_queue_cleanup(udev, EVENT_QUEUED);
|
||||
worker_kill();
|
||||
event_queue_cleanup(manager->udev, EVENT_QUEUED);
|
||||
manager_kill_workers(manager);
|
||||
|
||||
/* exit after all has cleaned up */
|
||||
if (udev_list_node_is_empty(&event_list) && hashmap_isempty(workers))
|
||||
if (udev_list_node_is_empty(&event_list) && hashmap_isempty(manager->workers))
|
||||
break;
|
||||
|
||||
/* timeout at exit for workers to finish */
|
||||
timeout = 30 * MSEC_PER_SEC;
|
||||
} else if (udev_list_node_is_empty(&event_list) && hashmap_isempty(workers)) {
|
||||
} else if (udev_list_node_is_empty(&event_list) && hashmap_isempty(manager->workers)) {
|
||||
/* we are idle */
|
||||
timeout = -1;
|
||||
|
||||
@ -1463,7 +1528,7 @@ int main(int argc, char *argv[]) {
|
||||
Iterator j;
|
||||
|
||||
/* timeout */
|
||||
if (udev_exit) {
|
||||
if (manager->exit) {
|
||||
log_error("timeout, giving up waiting for workers to finish");
|
||||
break;
|
||||
}
|
||||
@ -1471,11 +1536,11 @@ int main(int argc, char *argv[]) {
|
||||
/* kill idle workers */
|
||||
if (udev_list_node_is_empty(&event_list)) {
|
||||
log_debug("cleanup idle workers");
|
||||
worker_kill();
|
||||
manager_kill_workers(manager);
|
||||
}
|
||||
|
||||
/* check for hanging events */
|
||||
HASHMAP_FOREACH(worker, workers, j) {
|
||||
HASHMAP_FOREACH(worker, manager->workers, j) {
|
||||
struct event *event = worker->event;
|
||||
usec_t ts;
|
||||
|
||||
@ -1519,36 +1584,36 @@ int main(int argc, char *argv[]) {
|
||||
/* check for changed config, every 3 seconds at most */
|
||||
if ((now(CLOCK_MONOTONIC) - last_usec) > 3 * USEC_PER_SEC) {
|
||||
if (udev_rules_check_timestamp(rules))
|
||||
reload = true;
|
||||
if (udev_builtin_validate(udev))
|
||||
reload = true;
|
||||
manager->reload = true;
|
||||
if (udev_builtin_validate(manager->udev))
|
||||
manager->reload = true;
|
||||
|
||||
last_usec = now(CLOCK_MONOTONIC);
|
||||
}
|
||||
|
||||
/* reload requested, HUP signal received, rules changed, builtin changed */
|
||||
if (reload) {
|
||||
worker_kill();
|
||||
if (manager->reload) {
|
||||
manager_kill_workers(manager);
|
||||
rules = udev_rules_unref(rules);
|
||||
udev_builtin_exit(udev);
|
||||
reload = false;
|
||||
udev_builtin_exit(manager->udev);
|
||||
manager->reload = false;
|
||||
}
|
||||
|
||||
/* event has finished */
|
||||
if (is_worker)
|
||||
on_worker(NULL, fd_worker, 0, NULL);
|
||||
on_worker(NULL, fd_worker, 0, manager);
|
||||
|
||||
/* uevent from kernel */
|
||||
if (is_netlink)
|
||||
on_uevent(NULL, fd_netlink, 0, monitor);
|
||||
on_uevent(NULL, fd_netlink, 0, manager);
|
||||
|
||||
/* start new events */
|
||||
if (!udev_list_node_is_empty(&event_list) && !udev_exit && !stop_exec_queue) {
|
||||
udev_builtin_init(udev);
|
||||
if (!udev_list_node_is_empty(&event_list) && !manager->exit && !manager->stop_exec_queue) {
|
||||
udev_builtin_init(manager->udev);
|
||||
if (rules == NULL)
|
||||
rules = udev_rules_new(udev, arg_resolve_names);
|
||||
rules = udev_rules_new(manager->udev, arg_resolve_names);
|
||||
if (rules != NULL)
|
||||
event_queue_start(udev);
|
||||
event_queue_start(manager);
|
||||
}
|
||||
|
||||
if (is_signal) {
|
||||
@ -1560,25 +1625,25 @@ int main(int argc, char *argv[]) {
|
||||
switch (fdsi.ssi_signo) {
|
||||
case SIGINT:
|
||||
case SIGTERM:
|
||||
on_request_exit(NULL, &fdsi, NULL);
|
||||
on_request_exit(NULL, &fdsi, manager);
|
||||
break;
|
||||
case SIGHUP:
|
||||
on_request_reload(NULL, &fdsi, NULL);
|
||||
on_request_reload(NULL, &fdsi, manager);
|
||||
break;
|
||||
case SIGCHLD:
|
||||
on_sigchld(NULL, &fdsi, NULL);
|
||||
on_sigchld(NULL, &fdsi, manager);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* we are shutting down, the events below are not handled anymore */
|
||||
if (udev_exit)
|
||||
if (manager->exit)
|
||||
continue;
|
||||
|
||||
/* device node watch */
|
||||
if (is_inotify)
|
||||
on_inotify(NULL, fd_inotify, 0, udev);
|
||||
on_inotify(NULL, fd_inotify, 0, manager);
|
||||
|
||||
/*
|
||||
* This needs to be after the inotify handling, to make sure,
|
||||
@ -1586,31 +1651,25 @@ int main(int argc, char *argv[]) {
|
||||
* "change" events by the inotify device node watch.
|
||||
*/
|
||||
if (is_ctrl)
|
||||
on_ctrl_msg(NULL, fd_ctrl, 0, udev_ctrl);
|
||||
on_ctrl_msg(NULL, fd_ctrl, 0, manager);
|
||||
}
|
||||
|
||||
exit:
|
||||
udev_ctrl_cleanup(udev_ctrl);
|
||||
udev_ctrl_cleanup(manager->ctrl);
|
||||
unlink("/run/udev/queue");
|
||||
exit_daemonize:
|
||||
if (fd_ep >= 0)
|
||||
close(fd_ep);
|
||||
workers_free();
|
||||
event_queue_cleanup(udev, EVENT_UNDEF);
|
||||
event_queue_cleanup(manager->udev, EVENT_UNDEF);
|
||||
udev_rules_unref(rules);
|
||||
udev_builtin_exit(udev);
|
||||
udev_builtin_exit(manager->udev);
|
||||
if (fd_signal >= 0)
|
||||
close(fd_signal);
|
||||
if (worker_watch[READ_END] >= 0)
|
||||
close(worker_watch[READ_END]);
|
||||
if (worker_watch[WRITE_END] >= 0)
|
||||
close(worker_watch[WRITE_END]);
|
||||
udev_monitor_unref(monitor);
|
||||
udev_ctrl_connection_unref(udev_ctrl_conn);
|
||||
udev_ctrl_unref(udev_ctrl);
|
||||
udev_list_cleanup(&properties_list);
|
||||
mac_selinux_finish();
|
||||
udev_unref(udev);
|
||||
log_close();
|
||||
return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user