From d5673993ad3bf38d0aeba8dbd025d6f4527f0169 Mon Sep 17 00:00:00 2001 From: Sven Eden Date: Tue, 25 Jul 2017 10:19:45 +0200 Subject: [PATCH 1/1] Prep v234: Apply missing upstream fixes in src/login (3/6) --- src/login/logind-session-dbus.c | 15 ++++++- src/login/logind-session-device.c | 1 + src/login/logind-session.c | 71 +++++++++++++++++++++++++++++-- src/login/logind-session.h | 2 + src/login/logind.c | 71 +++++++++++++++++++++++++++++-- 5 files changed, 151 insertions(+), 9 deletions(-) diff --git a/src/login/logind-session-dbus.c b/src/login/logind-session-dbus.c index 93495fbe8..1316c5008 100644 --- a/src/login/logind-session-dbus.c +++ b/src/login/logind-session-dbus.c @@ -444,14 +444,23 @@ static int method_take_device(sd_bus_message *message, void *userdata, sd_bus_er * equivalent). */ return sd_bus_error_setf(error, BUS_ERROR_DEVICE_IS_TAKEN, "Device already taken"); - r = session_device_new(s, dev, &sd); + r = session_device_new(s, dev, true, &sd); if (r < 0) return r; + r = session_device_save(sd); + if (r < 0) + goto error; + r = sd_bus_reply_method_return(message, "hb", sd->fd, !sd->active); if (r < 0) - session_device_free(sd); + goto error; + + session_save(s); + return 0; +error: + session_device_free(sd); return r; } @@ -478,6 +487,8 @@ static int method_release_device(sd_bus_message *message, void *userdata, sd_bus return sd_bus_error_setf(error, BUS_ERROR_DEVICE_NOT_TAKEN, "Device not taken"); session_device_free(sd); + session_save(s); + return sd_bus_reply_method_return(message, NULL); } diff --git a/src/login/logind-session-device.c b/src/login/logind-session-device.c index 915f87dd5..b46644894 100644 --- a/src/login/logind-session-device.c +++ b/src/login/logind-session-device.c @@ -34,6 +34,7 @@ #include "fd-util.h" #include "logind-session-device.h" #include "missing.h" +#include "sd-daemon.h" #include "util.h" enum SessionDeviceNotifications { diff --git a/src/login/logind-session.c b/src/login/logind-session.c index d67eb02f7..28784a867 100644 --- a/src/login/logind-session.c +++ b/src/login/logind-session.c @@ -33,6 +33,7 @@ #include "bus-error.h" #include "bus-util.h" #include "escape.h" +#include "extract-word.h" #include "fd-util.h" #include "fileio.h" #include "format-util.h" @@ -154,6 +155,18 @@ void session_set_user(Session *s, User *u) { LIST_PREPEND(sessions_by_user, u->sessions, s); } +static void session_save_devices(Session *s, FILE *f) { + SessionDevice *sd; + Iterator i; + + if (!hashmap_isempty(s->devices)) { + fprintf(f, "DEVICES="); + HASHMAP_FOREACH(sd, s->devices, i) + fprintf(f, "%u:%u ", major(sd->dev), minor(sd->dev)); + fprintf(f, "\n"); + } +} + int session_save(Session *s) { _cleanup_free_ char *temp_path = NULL; _cleanup_fclose_ FILE *f = NULL; @@ -285,8 +298,10 @@ int session_save(Session *s) { s->timestamp.realtime, s->timestamp.monotonic); - if (s->controller) + if (s->controller) { fprintf(f, "CONTROLLER=%s\n", s->controller); + session_save_devices(s, f); + } r = fflush_and_check(f); if (r < 0) @@ -308,6 +323,43 @@ fail: return log_error_errno(r, "Failed to save session data %s: %m", s->state_file); } +static int session_load_devices(Session *s, const char *devices) { + const char *p; + int r = 0; + + assert(s); + + for (p = devices;;) { + _cleanup_free_ char *word = NULL; + SessionDevice *sd; + dev_t dev; + int k; + + k = extract_first_word(&p, &word, NULL, 0); + if (k == 0) + break; + if (k < 0) { + r = k; + break; + } + + k = parse_dev(word, &dev); + if (k < 0) { + r = k; + continue; + } + + /* The file descriptors for loaded devices will be reattached later. */ + k = session_device_new(s, dev, false, &sd); + if (k < 0) + r = k; + } + + if (r < 0) + log_error_errno(r, "Loading session devices for session %s failed: %m", s->id); + + return r; +} int session_load(Session *s) { _cleanup_free_ char *remote = NULL, @@ -321,7 +373,9 @@ int session_load(Session *s) { *uid = NULL, *realtime = NULL, *monotonic = NULL, - *controller = NULL; + *controller = NULL, + *active = NULL, + *devices = NULL; int k, r; @@ -351,6 +405,8 @@ int session_load(Session *s) { "REALTIME", &realtime, "MONOTONIC", &monotonic, "CONTROLLER", &controller, + "ACTIVE", &active, + "DEVICES", &devices, NULL); if (r < 0) @@ -453,10 +509,17 @@ int session_load(Session *s) { if (monotonic) timestamp_deserialize(monotonic, &s->timestamp.monotonic); + if (active) { + k = parse_boolean(active); + if (k >= 0) + s->was_active = k; + } + if (controller) { - if (bus_name_has_owner(s->manager->bus, controller, NULL) > 0) + if (bus_name_has_owner(s->manager->bus, controller, NULL) > 0) { session_set_controller(s, controller, false, false); - else + session_load_devices(s, devices); + } else session_restore_vt(s); } diff --git a/src/login/logind-session.h b/src/login/logind-session.h index 924b0a072..1e7f3ad49 100644 --- a/src/login/logind-session.h +++ b/src/login/logind-session.h @@ -113,6 +113,8 @@ struct Session { bool started:1; bool stopping:1; + bool was_active:1; + sd_bus_message *create_message; sd_event_source *timer_event_source; diff --git a/src/login/logind.c b/src/login/logind.c index 4b040e7a7..d46358e31 100644 --- a/src/login/logind.c +++ b/src/login/logind.c @@ -436,10 +436,71 @@ static int manager_enumerate_users(Manager *m) { return r; } +static int manager_attach_fds(Manager *m) { + _cleanup_strv_free_ char **fdnames = NULL; + int n, i, fd; + + /* Upon restart, PID1 will send us back all fds of session devices + * that we previously opened. Each file descriptor is associated + * with a given session. The session ids are passed through FDNAMES. */ + + n = sd_listen_fds_with_names(true, &fdnames); + if (n <= 0) + return n; + + for (i = 0; i < n; i++) { + struct stat st; + SessionDevice *sd; + Session *s; + char *id; + + fd = SD_LISTEN_FDS_START + i; + + id = startswith(fdnames[i], "session-"); + if (!id) + continue; + + s = hashmap_get(m->sessions, id); + if (!s) { + /* If the session doesn't exist anymore, the associated session + * device attached to this fd doesn't either. Let's simply close + * this fd. */ + log_debug("Failed to attach fd for unknown session: %s", id); + close_nointr(fd); + continue; + } + + if (fstat(fd, &st) < 0) { + /* The device is allowed to go away at a random point, in which + * case fstat failing is expected. */ + log_debug_errno(errno, "Failed to stat device fd for session %s: %m", id); + close_nointr(fd); + continue; + } + + sd = hashmap_get(s->devices, &st.st_rdev); + if (!sd) { + /* Weird we got an fd for a session device which wasn't + * recorded in the session state file... */ + log_warning("Got fd for missing session device [%u:%u] in session %s", + major(st.st_rdev), minor(st.st_rdev), s->id); + close_nointr(fd); + continue; + } + + log_debug("Attaching fd to session device [%u:%u] for session %s", + major(st.st_rdev), minor(st.st_rdev), s->id); + + session_device_attach_fd(sd, fd, s->was_active); + } + + return 0; +} + static int manager_enumerate_sessions(Manager *m) { _cleanup_closedir_ DIR *d = NULL; struct dirent *de; - int r = 0; + int r = 0, k; assert(m); @@ -454,7 +515,6 @@ static int manager_enumerate_sessions(Manager *m) { FOREACH_DIRENT(de, d, return -errno) { struct Session *s; - int k; if (!dirent_is_file(de)) continue; @@ -468,7 +528,6 @@ static int manager_enumerate_sessions(Manager *m) { k = manager_add_session(m, de->d_name, &s); if (k < 0) { log_error_errno(k, "Failed to add session by file name %s: %m", de->d_name); - r = k; continue; } @@ -480,6 +539,12 @@ static int manager_enumerate_sessions(Manager *m) { r = k; } + /* We might be restarted and PID1 could have sent us back the + * session device fds we previously saved. */ + k = manager_attach_fds(m); + if (k < 0) + log_warning_errno(k, "Failed to reattach session device fds: %m"); + return r; } -- 2.30.2