From 932e3ee76ea0a9d28902f694ad1873e37532da35 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 29 Jun 2011 00:06:04 +0200 Subject: [PATCH] logind: use named pipes instead of fifos to keep track of sessions so that we can reconnect later --- src/logind-dbus.c | 40 +++++++++------------ src/logind-seat.c | 3 ++ src/logind-session.c | 86 +++++++++++++++++++++++++++++++++----------- src/logind-session.h | 8 +++-- src/logind-user.c | 3 ++ src/logind.c | 17 ++++----- src/logind.h | 9 +++-- 7 files changed, 105 insertions(+), 61 deletions(-) diff --git a/src/logind-dbus.c b/src/logind-dbus.c index 5997fb5d..ff500f3c 100644 --- a/src/logind-dbus.c +++ b/src/logind-dbus.c @@ -191,7 +191,7 @@ static int bus_manager_create_session(Manager *m, DBusMessage *message, DBusMess int r; char *id = NULL, *p; uint32_t vtnr = 0; - int pipe_fds[2] = { -1, -1 }; + int fifo_fd = -1; DBusMessage *reply = NULL; bool b; @@ -353,6 +353,12 @@ static int bus_manager_create_session(Manager *m, DBusMessage *message, DBusMess if (session) { + fifo_fd = session_create_fifo(session); + if (fifo_fd < 0) { + r = fifo_fd; + goto fail; + } + /* Session already exists, client is probably * something like "su" which changes uid but * is still the same audit session */ @@ -363,15 +369,6 @@ static int bus_manager_create_session(Manager *m, DBusMessage *message, DBusMess goto fail; } - /* Create a throw-away fd */ - if (pipe(pipe_fds) < 0) { - r = -errno; - goto fail; - } - - close_nointr_nofail(pipe_fds[0]); - pipe_fds[0] = -1; - p = session_bus_path(session); if (!p) { r = -ENOMEM; @@ -383,7 +380,7 @@ static int bus_manager_create_session(Manager *m, DBusMessage *message, DBusMess DBUS_TYPE_STRING, &session->id, DBUS_TYPE_OBJECT_PATH, &p, DBUS_TYPE_STRING, &session->user->runtime_path, - DBUS_TYPE_UNIX_FD, &pipe_fds[1], + DBUS_TYPE_UNIX_FD, &fifo_fd, DBUS_TYPE_INVALID); free(p); @@ -392,7 +389,7 @@ static int bus_manager_create_session(Manager *m, DBusMessage *message, DBusMess goto fail; } - close_nointr_nofail(pipe_fds[1]); + close_nointr_nofail(fifo_fd); *_reply = reply; return 0; @@ -467,16 +464,12 @@ static int bus_manager_create_session(Manager *m, DBusMessage *message, DBusMess } } - if (pipe(pipe_fds) < 0) { - r = -errno; + fifo_fd = session_create_fifo(session); + if (fifo_fd < 0) { + r = fifo_fd; goto fail; } - r = session_set_pipe_fd(session, pipe_fds[0]); - if (r < 0) - goto fail; - pipe_fds[0] = -1; - if (s) { r = seat_attach_session(s, session); if (r < 0) @@ -504,7 +497,7 @@ static int bus_manager_create_session(Manager *m, DBusMessage *message, DBusMess DBUS_TYPE_STRING, &session->id, DBUS_TYPE_OBJECT_PATH, &p, DBUS_TYPE_STRING, &session->user->runtime_path, - DBUS_TYPE_UNIX_FD, &pipe_fds[1], + DBUS_TYPE_UNIX_FD, &fifo_fd, DBUS_TYPE_INVALID); free(p); @@ -513,7 +506,7 @@ static int bus_manager_create_session(Manager *m, DBusMessage *message, DBusMess goto fail; } - close_nointr_nofail(pipe_fds[1]); + close_nointr_nofail(fifo_fd); *_reply = reply; return 0; @@ -528,7 +521,8 @@ fail: if (user) user_add_to_gc_queue(user); - close_pipe(pipe_fds); + if (fifo_fd >= 0) + close_nointr_nofail(fifo_fd); if (reply) dbus_message_unref(reply); @@ -611,7 +605,7 @@ static int attach_device(Manager *m, const char *seat, const char *sysfs) { const char *p; p = udev_list_entry_get_name(item); - if (!startswith(p, sysfs)) + if (!path_startswith(p, sysfs)) continue; t = strappend(p, "/uevent"); diff --git a/src/logind-seat.c b/src/logind-seat.c index 5663aeea..1bc05705 100644 --- a/src/logind-seat.c +++ b/src/logind-seat.c @@ -449,6 +449,9 @@ int seat_get_idle_hint(Seat *s, dual_timestamp *t) { int seat_check_gc(Seat *s) { assert(s); + if (!s->started) + return 0; + if (seat_is_vtconsole(s)) return 1; diff --git a/src/logind-session.c b/src/logind-session.c index d68423bd..76718500 100644 --- a/src/logind-session.c +++ b/src/logind-session.c @@ -23,6 +23,7 @@ #include #include #include +#include #include "logind-session.h" #include "strv.h" @@ -56,7 +57,7 @@ Session* session_new(Manager *m, User *u, const char *id) { } s->manager = m; - s->pipe_fd = -1; + s->fifo_fd = -1; s->user = u; LIST_PREPEND(Session, sessions_by_user, u->sessions, s); @@ -98,7 +99,7 @@ void session_free(Session *s) { hashmap_remove(s->manager->sessions, s->id); - session_unset_pipe_fd(s); + session_remove_fifo(s); free(s->state_file); free(s); @@ -149,6 +150,11 @@ int session_save(Session *s) { "CGROUP=%s\n", s->cgroup_path); + if (s->fifo_path) + fprintf(f, + "FIFO=%s\n", + s->fifo_path); + if (s->seat) fprintf(f, "SEAT=%s\n", @@ -229,6 +235,7 @@ int session_load(Session *s) { "REMOTE", &remote, "KILL_PROCESSES", &kill_processes, "CGROUP", &s->cgroup_path, + "FIFO", &s->fifo_path, "SEAT", &seat, "TTY", &s->tty, "DISPLAY", &s->display, @@ -290,6 +297,8 @@ int session_load(Session *s) { s->type = t; } + session_open_fifo(s); + finish: free(remote); free(kill_processes); @@ -746,43 +755,77 @@ void session_set_idle_hint(Session *s, bool b) { "IdleSinceHintMonotonic\0"); } -int session_set_pipe_fd(Session *s, int fd) { +int session_open_fifo(Session *s) { struct epoll_event ev; int r; assert(s); - assert(fd >= 0); - assert(s->pipe_fd < 0); - r = hashmap_put(s->manager->pipe_fds, INT_TO_PTR(fd + 1), s); + if (s->fifo_fd >= 0) + return 0; + + if (!s->fifo_path) + return -EINVAL; + + s->fifo_fd = open(s->fifo_path, O_RDONLY|O_CLOEXEC|O_NDELAY); + if (s->fifo_fd < 0) + return -errno; + + r = hashmap_put(s->manager->fifo_fds, INT_TO_PTR(s->fifo_fd + 1), s); if (r < 0) return r; zero(ev); ev.events = 0; - ev.data.u32 = FD_PIPE_BASE + fd; + ev.data.u32 = FD_FIFO_BASE + s->fifo_fd; - if (epoll_ctl(s->manager->epoll_fd, EPOLL_CTL_ADD, fd, &ev) < 0) { - assert_se(hashmap_remove(s->manager->pipe_fds, INT_TO_PTR(fd + 1)) == s); + if (epoll_ctl(s->manager->epoll_fd, EPOLL_CTL_ADD, s->fifo_fd, &ev) < 0) return -errno; - } - s->pipe_fd = fd; return 0; } -void session_unset_pipe_fd(Session *s) { +int session_create_fifo(Session *s) { + int r; + assert(s); - if (s->pipe_fd < 0) - return; + if (!s->fifo_path) { + if (asprintf(&s->fifo_path, "/run/systemd/sessions/%s.ref", s->id) < 0) + return -ENOMEM; - assert_se(hashmap_remove(s->manager->pipe_fds, INT_TO_PTR(s->pipe_fd + 1)) == s); + if (mkfifo(s->fifo_path, 0600) < 0 && errno != EEXIST) + return -errno; + } - assert_se(epoll_ctl(s->manager->epoll_fd, EPOLL_CTL_DEL, s->pipe_fd, NULL) == 0); + /* Open reading side */ + r = session_open_fifo(s); + if (r < 0) + return r; + + /* Open writing side */ + r = open(s->fifo_path, O_WRONLY|O_CLOEXEC|O_NDELAY); + if (r < 0) + return -errno; - close_nointr_nofail(s->pipe_fd); - s->pipe_fd = -1; + return r; +} + +void session_remove_fifo(Session *s) { + assert(s); + + if (s->fifo_fd >= 0) { + assert_se(hashmap_remove(s->manager->fifo_fds, INT_TO_PTR(s->fifo_fd + 1)) == s); + assert_se(epoll_ctl(s->manager->epoll_fd, EPOLL_CTL_DEL, s->fifo_fd, NULL) == 0); + close_nointr_nofail(s->fifo_fd); + s->fifo_fd = -1; + } + + if (s->fifo_path) { + unlink(s->fifo_path); + free(s->fifo_path); + s->fifo_path = NULL; + } } int session_check_gc(Session *s) { @@ -790,9 +833,12 @@ int session_check_gc(Session *s) { assert(s); - if (s->pipe_fd >= 0) { + if (!s->started) + return 0; + + if (s->fifo_fd >= 0) { - r = pipe_eof(s->pipe_fd); + r = pipe_eof(s->fifo_fd); if (r < 0) return r; diff --git a/src/logind-session.h b/src/logind-session.h index 72f85caa..d0cf0ed8 100644 --- a/src/logind-session.h +++ b/src/logind-session.h @@ -65,7 +65,8 @@ struct Session { pid_t leader; uint32_t audit_id; - int pipe_fd; + int fifo_fd; + char *fifo_path; char *cgroup_path; char **controllers, **reset_controllers; @@ -91,8 +92,9 @@ int session_activate(Session *s); bool session_is_active(Session *s); int session_get_idle_hint(Session *s, dual_timestamp *t); void session_set_idle_hint(Session *s, bool b); -int session_set_pipe_fd(Session *s, int fd); -void session_unset_pipe_fd(Session *s); +int session_open_fifo(Session *s); +int session_create_fifo(Session *s); +void session_remove_fifo(Session *s); int session_start(Session *s); int session_stop(Session *s); int session_save(Session *s); diff --git a/src/logind-user.c b/src/logind-user.c index 177e8820..4335bf64 100644 --- a/src/logind-user.c +++ b/src/logind-user.c @@ -459,6 +459,9 @@ int user_check_gc(User *u) { assert(u); + if (!u->started) + return 0; + if (u->sessions) return 1; diff --git a/src/logind.c b/src/logind.c index a0a89c06..d38d7d51 100644 --- a/src/logind.c +++ b/src/logind.c @@ -52,7 +52,7 @@ Manager *manager_new(void) { m->sessions = hashmap_new(string_hash_func, string_compare_func); m->users = hashmap_new(trivial_hash_func, trivial_compare_func); m->cgroups = hashmap_new(string_hash_func, string_compare_func); - m->pipe_fds = hashmap_new(trivial_hash_func, trivial_compare_func); + m->fifo_fds = hashmap_new(trivial_hash_func, trivial_compare_func); if (!m->devices || !m->seats || !m->sessions || !m->users) { manager_free(m); @@ -98,7 +98,7 @@ void manager_free(Manager *m) { hashmap_free(m->devices); hashmap_free(m->seats); hashmap_free(m->cgroups); - hashmap_free(m->pipe_fds); + hashmap_free(m->fifo_fds); if (m->console_active_fd >= 0) close_nointr_nofail(m->console_active_fd); @@ -802,9 +802,9 @@ static void manager_pipe_notify_eof(Manager *m, int fd) { assert_se(m); assert_se(fd >= 0); - assert_se(s = hashmap_get(m->pipe_fds, INT_TO_PTR(fd + 1))); - assert(s->pipe_fd == fd); - session_unset_pipe_fd(s); + assert_se(s = hashmap_get(m->fifo_fds, INT_TO_PTR(fd + 1))); + assert(s->fifo_fd == fd); + session_remove_fifo(s); session_stop(s); } @@ -1081,9 +1081,6 @@ int manager_startup(Manager *m) { manager_enumerate_users(m); manager_enumerate_sessions(m); - /* Get rid of objects that are no longer used */ - manager_gc(m); - /* And start everything */ HASHMAP_FOREACH(seat, m->seats, i) seat_start(seat); @@ -1139,8 +1136,8 @@ int manager_run(Manager *m) { break; default: - if (event.data.u32 >= FD_PIPE_BASE) - manager_pipe_notify_eof(m, event.data.u32 - FD_PIPE_BASE); + if (event.data.u32 >= FD_FIFO_BASE) + manager_pipe_notify_eof(m, event.data.u32 - FD_FIFO_BASE); } } diff --git a/src/logind.h b/src/logind.h index 30954141..9b9f38bb 100644 --- a/src/logind.h +++ b/src/logind.h @@ -37,15 +37,14 @@ * spawn user systemd * direct client API * add configuration file - * D-Bus method: AttachDevices(seat, devices[]); - * use named pipes to detect when a session dies * verify access to SetIdleHint + * + * udev: * drop redundant udev_device_get_is_initialized() use as soon as libudev is fixed * properly escape/remove : and . from seat names in udev rules * use device_has_tag() as soon as it is available * trigger based on libudev if available * enumerate recursively with libudev when triggering - * make sure IMPORT{parent}="ID_SEAT" works between usb hub and sound card * * non-local X11 server * reboot/shutdown halt management @@ -94,7 +93,7 @@ struct Manager { unsigned long session_counter; Hashmap *cgroups; - Hashmap *pipe_fds; + Hashmap *fifo_fds; }; enum { @@ -102,7 +101,7 @@ enum { FD_VCSA_UDEV, FD_CONSOLE, FD_BUS, - FD_PIPE_BASE + FD_FIFO_BASE }; Manager *manager_new(void); -- 2.39.5