mirror of
https://github.com/systemd/systemd-stable.git
synced 2025-02-22 17:57:49 +03:00
monitor udev for device changes
This commit is contained in:
parent
ef734fd6c2
commit
f94ea366d3
113
device.c
113
device.c
@ -1,6 +1,7 @@
|
||||
/*-*- Mode: C; c-basic-offset: 8 -*-*/
|
||||
|
||||
#include <errno.h>
|
||||
#include <sys/epoll.h>
|
||||
#include <libudev.h>
|
||||
|
||||
#include "unit.h"
|
||||
@ -91,7 +92,7 @@ static int device_add_escaped_name(Unit *u, const char *prefix, const char *dn,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int device_process_device(Manager *m, struct udev_device *dev) {
|
||||
static int device_process_new_device(Manager *m, struct udev_device *dev, bool update_state) {
|
||||
const char *dn, *names, *wants, *sysfs;
|
||||
Unit *u = NULL;
|
||||
int r;
|
||||
@ -146,6 +147,7 @@ static int device_process_device(Manager *m, struct udev_device *dev) {
|
||||
if ((r = unit_set_description(u, model)) < 0)
|
||||
goto fail;
|
||||
|
||||
unit_add_to_load_queue(u);
|
||||
} else {
|
||||
delete = false;
|
||||
free(e);
|
||||
@ -173,12 +175,6 @@ static int device_process_device(Manager *m, struct udev_device *dev) {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (set_isempty(u->meta.names)) {
|
||||
r = -EEXIST;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (wants) {
|
||||
FOREACH_WORD(w, l, wants, state) {
|
||||
if (!(e = strndup(w, l)))
|
||||
@ -192,7 +188,11 @@ static int device_process_device(Manager *m, struct udev_device *dev) {
|
||||
}
|
||||
}
|
||||
|
||||
unit_add_to_load_queue(u);
|
||||
if (update_state) {
|
||||
manager_dispatch_load_queue(u->meta.manager);
|
||||
device_set_state(DEVICE(u), DEVICE_AVAILABLE);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
fail:
|
||||
@ -201,7 +201,7 @@ fail:
|
||||
return r;
|
||||
}
|
||||
|
||||
static int device_process_path(Manager *m, const char *path) {
|
||||
static int device_process_path(Manager *m, const char *path, bool update_state) {
|
||||
int r;
|
||||
struct udev_device *dev;
|
||||
|
||||
@ -213,19 +213,53 @@ static int device_process_path(Manager *m, const char *path) {
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
r = device_process_device(m, dev);
|
||||
r = device_process_new_device(m, dev, update_state);
|
||||
udev_device_unref(dev);
|
||||
return r;
|
||||
}
|
||||
|
||||
static int device_process_removed_device(Manager *m, struct udev_device *dev) {
|
||||
const char *sysfs;
|
||||
char *e;
|
||||
Unit *u;
|
||||
Device *d;
|
||||
|
||||
assert(m);
|
||||
assert(dev);
|
||||
|
||||
if (!(sysfs = udev_device_get_syspath(dev)))
|
||||
return -ENOMEM;
|
||||
|
||||
assert(sysfs[0] == '/');
|
||||
if (!(e = unit_name_escape_path("sysfs-", sysfs+1, ".device")))
|
||||
return -ENOMEM;
|
||||
|
||||
u = manager_get_unit(m, e);
|
||||
free(e);
|
||||
|
||||
if (!u)
|
||||
return 0;
|
||||
|
||||
d = DEVICE(u);
|
||||
free(d->sysfs);
|
||||
d->sysfs = NULL;
|
||||
|
||||
device_set_state(d, DEVICE_DEAD);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void device_shutdown(Manager *m) {
|
||||
assert(m);
|
||||
|
||||
if (m->udev_monitor)
|
||||
udev_monitor_unref(m->udev_monitor);
|
||||
|
||||
if (m->udev)
|
||||
udev_unref(m->udev);
|
||||
}
|
||||
|
||||
static int device_enumerate(Manager *m) {
|
||||
struct epoll_event ev;
|
||||
int r;
|
||||
struct udev_enumerate *e = NULL;
|
||||
struct udev_list_entry *item = NULL, *first = NULL;
|
||||
@ -235,6 +269,26 @@ static int device_enumerate(Manager *m) {
|
||||
if (!(m->udev = udev_new()))
|
||||
return -ENOMEM;
|
||||
|
||||
if (!(m->udev_monitor = udev_monitor_new_from_netlink(m->udev, "udev"))) {
|
||||
r = -ENOMEM;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (udev_monitor_enable_receiving(m->udev_monitor) < 0) {
|
||||
r = -EIO;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
m->udev_watch.type = WATCH_UDEV;
|
||||
m->udev_watch.fd = udev_monitor_get_fd(m->udev_monitor);
|
||||
|
||||
zero(ev);
|
||||
ev.events = EPOLLIN;
|
||||
ev.data.ptr = &m->udev_watch;
|
||||
|
||||
if (epoll_ctl(m->epoll_fd, EPOLL_CTL_ADD, m->udev_watch.fd, &ev) < 0)
|
||||
return -errno;
|
||||
|
||||
if (!(e = udev_enumerate_new(m->udev))) {
|
||||
r = -ENOMEM;
|
||||
goto fail;
|
||||
@ -247,10 +301,9 @@ static int device_enumerate(Manager *m) {
|
||||
|
||||
first = udev_enumerate_get_list_entry(e);
|
||||
udev_list_entry_foreach(item, first)
|
||||
device_process_path(m, udev_list_entry_get_name(item));
|
||||
device_process_path(m, udev_list_entry_get_name(item), false);
|
||||
|
||||
udev_enumerate_unref(e);
|
||||
|
||||
return 0;
|
||||
|
||||
fail:
|
||||
@ -261,6 +314,42 @@ fail:
|
||||
return r;
|
||||
}
|
||||
|
||||
void device_fd_event(Manager *m, int events) {
|
||||
struct udev_device *dev;
|
||||
int r;
|
||||
const char *action;
|
||||
|
||||
assert(m);
|
||||
assert(events == EPOLLIN);
|
||||
|
||||
log_debug("got udev event");
|
||||
|
||||
if (!(dev = udev_monitor_receive_device(m->udev_monitor))) {
|
||||
log_error("Failed to receive device.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!(action = udev_device_get_action(dev))) {
|
||||
log_error("Failed to get udev action string.");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (streq(action, "remove")) {
|
||||
if ((r = device_process_removed_device(m, dev)) < 0) {
|
||||
log_error("Failed to process udev device event: %s", strerror(-r));
|
||||
goto fail;
|
||||
}
|
||||
} else {
|
||||
if ((r = device_process_new_device(m, dev, true)) < 0) {
|
||||
log_error("Failed to process udev device event: %s", strerror(-r));
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
|
||||
fail:
|
||||
udev_device_unref(dev);
|
||||
}
|
||||
|
||||
const UnitVTable device_vtable = {
|
||||
.suffix = ".device",
|
||||
|
||||
|
2
device.h
2
device.h
@ -26,4 +26,6 @@ struct Device {
|
||||
|
||||
extern const UnitVTable device_vtable;
|
||||
|
||||
void device_fd_event(Manager *m, int events);
|
||||
|
||||
#endif
|
||||
|
5
fixme
5
fixme
@ -40,3 +40,8 @@
|
||||
- automatically delete stale unix sockets
|
||||
|
||||
- .socket needs to be notified not only by .service state changes, but also unsuccessful start jobs
|
||||
|
||||
- we probably cannot use glibc's syslog() for logging, since it
|
||||
presumably uses the logging socket in blocking mode which might
|
||||
trigger a deadlock if syslog does not process the socket anymore
|
||||
(maybe because it is restarted) and the socket buffer is full.
|
||||
|
8
logger.c
8
logger.c
@ -319,7 +319,7 @@ static int stream_new(Server *s, int server_fd) {
|
||||
|
||||
zero(ev);
|
||||
ev.data.ptr = stream;
|
||||
ev.events = POLLIN;
|
||||
ev.events = EPOLLIN;
|
||||
if (epoll_ctl(s->epoll_fd, EPOLL_CTL_ADD, fd, &ev) < 0) {
|
||||
r = -errno;
|
||||
goto fail;
|
||||
@ -429,7 +429,7 @@ static int server_init(Server *s, unsigned n_sockets) {
|
||||
struct epoll_event ev;
|
||||
|
||||
zero(ev);
|
||||
ev.events = POLLIN;
|
||||
ev.events = EPOLLIN;
|
||||
ev.data.ptr = UINT_TO_PTR(SERVER_FD_START+i);
|
||||
if (epoll_ctl(s->epoll_fd, EPOLL_CTL_ADD, SERVER_FD_START+i, &ev) < 0) {
|
||||
r = -errno;
|
||||
@ -479,7 +479,7 @@ static int process_event(Server *s, struct epoll_event *ev) {
|
||||
if (PTR_TO_UINT(ev->data.ptr) >= SERVER_FD_START &&
|
||||
PTR_TO_UINT(ev->data.ptr) < SERVER_FD_START+s->n_server_fd) {
|
||||
|
||||
if (ev->events != POLLIN) {
|
||||
if (ev->events != EPOLLIN) {
|
||||
log_info("Got invalid event from epoll. (1)");
|
||||
return -EIO;
|
||||
}
|
||||
@ -495,7 +495,7 @@ static int process_event(Server *s, struct epoll_event *ev) {
|
||||
|
||||
timestamp = now(CLOCK_REALTIME);
|
||||
|
||||
if (!(ev->events & POLLIN)) {
|
||||
if (!(ev->events & EPOLLIN)) {
|
||||
log_info("Got invalid event from epoll. (3)");
|
||||
stream_free(stream);
|
||||
return 0;
|
||||
|
@ -56,7 +56,7 @@ Manager* manager_new(void) {
|
||||
if (!(m = new0(Manager, 1)))
|
||||
return NULL;
|
||||
|
||||
m->signal_watch.fd = m->mount_watch.fd = m->epoll_fd = -1;
|
||||
m->signal_watch.fd = m->mount_watch.fd = m->udev_watch.fd = m->epoll_fd = -1;
|
||||
|
||||
if (!(m->units = hashmap_new(string_hash_func, string_compare_func)))
|
||||
goto fail;
|
||||
@ -1126,7 +1126,7 @@ static int process_event(Manager *m, struct epoll_event *ev, bool *quit) {
|
||||
case WATCH_SIGNAL:
|
||||
|
||||
/* An incoming signal? */
|
||||
if (ev->events != POLLIN)
|
||||
if (ev->events != EPOLLIN)
|
||||
return -EINVAL;
|
||||
|
||||
if ((r = manager_process_signal_fd(m, quit)) < 0)
|
||||
@ -1162,6 +1162,11 @@ static int process_event(Manager *m, struct epoll_event *ev, bool *quit) {
|
||||
mount_fd_event(m, ev->events);
|
||||
break;
|
||||
|
||||
case WATCH_UDEV:
|
||||
/* Some notification from udev, intended for the device subsystem */
|
||||
device_fd_event(m, ev->events);
|
||||
break;
|
||||
|
||||
default:
|
||||
assert_not_reached("Unknown epoll event type.");
|
||||
}
|
||||
|
@ -16,7 +16,8 @@ enum WatchType {
|
||||
WATCH_SIGNAL,
|
||||
WATCH_FD,
|
||||
WATCH_TIMER,
|
||||
WATCH_MOUNT
|
||||
WATCH_MOUNT,
|
||||
WATCH_UDEV
|
||||
};
|
||||
|
||||
struct Watch {
|
||||
@ -74,6 +75,8 @@ struct Manager {
|
||||
|
||||
/* Data specific to the device subsystem */
|
||||
struct udev* udev;
|
||||
struct udev_monitor* udev_monitor;
|
||||
Watch udev_watch;
|
||||
|
||||
/* Data specific to the mount subsystem */
|
||||
FILE *proc_self_mountinfo;
|
||||
|
5
mount.c
5
mount.c
@ -208,6 +208,7 @@ static int mount_add_one(Manager *m, const char *what, const char *where, bool l
|
||||
if ((r = unit_set_description(u, where)) < 0)
|
||||
goto fail;
|
||||
|
||||
unit_add_to_load_queue(u);
|
||||
} else {
|
||||
delete = false;
|
||||
free(e);
|
||||
@ -232,8 +233,6 @@ static int mount_add_one(Manager *m, const char *what, const char *where, bool l
|
||||
if ((r = mount_add_path_links(MOUNT(u))) < 0)
|
||||
goto fail;
|
||||
|
||||
unit_add_to_load_queue(u);
|
||||
|
||||
return 0;
|
||||
|
||||
fail:
|
||||
@ -420,7 +419,7 @@ void mount_fd_event(Manager *m, int events) {
|
||||
int r;
|
||||
|
||||
assert(m);
|
||||
assert(events == POLLERR);
|
||||
assert(events == EPOLLERR);
|
||||
|
||||
/* The manager calls this for every fd event happening on the
|
||||
* /proc/self/mountinfo file, which informs us about mounting
|
||||
|
6
socket.c
6
socket.c
@ -5,7 +5,7 @@
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/poll.h>
|
||||
#include <sys/epoll.h>
|
||||
#include <signal.h>
|
||||
|
||||
#include "unit.h"
|
||||
@ -285,7 +285,7 @@ static int socket_watch_fds(Socket *s) {
|
||||
if (p->fd < 0)
|
||||
continue;
|
||||
|
||||
if ((r = unit_watch_fd(UNIT(s), p->fd, POLLIN, &p->fd_watch)) < 0)
|
||||
if ((r = unit_watch_fd(UNIT(s), p->fd, EPOLLIN, &p->fd_watch)) < 0)
|
||||
goto fail;
|
||||
}
|
||||
|
||||
@ -634,7 +634,7 @@ static void socket_fd_event(Unit *u, int fd, uint32_t events, Watch *w) {
|
||||
|
||||
log_debug("Incoming traffic on %s", unit_id(u));
|
||||
|
||||
if (events != POLLIN)
|
||||
if (events != EPOLLIN)
|
||||
socket_enter_stop_pre(s, false);
|
||||
|
||||
socket_enter_running(s);
|
||||
|
Loading…
x
Reference in New Issue
Block a user