summaryrefslogtreecommitdiff
path: root/src/login/logind.c
diff options
context:
space:
mode:
authorFranck Bui <fbui@suse.com>2017-03-16 11:17:09 +0100
committerSven Eden <yamakuzure@gmx.net>2017-07-25 09:46:51 +0200
commit6179ccf82559f78ee6526452d6052b4a964f7f3b (patch)
treeb7f96d0b874c4d4fc97f8b43ec21a5d479cb4b85 /src/login/logind.c
parent91d60274701a12d2bbcd2b8e40f8b8abe00be0e7 (diff)
logind: save/restore session devices and their respective file descriptors
This patch ensures that session devices are saved for each session. In order to make the revokation logic work when logind is restarted, the session devices are now saved in the session state files and their respective file descriptors sent to PID1's fdstore in order to keep them open accross restart. This is mandatory in order to keep the revokation logic working. Indeed in case of input-devices, the same file descriptors must be shared by logind and a given session controller in order EVIOCREVOKE to work otherwise multiple sessions can have device access in parallel. This should be the only remaining and missing piece for making logind fully restartable. Fixes: #1163
Diffstat (limited to 'src/login/logind.c')
-rw-r--r--src/login/logind.c79
1 files changed, 72 insertions, 7 deletions
diff --git a/src/login/logind.c b/src/login/logind.c
index 83b06afa3..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;
}
@@ -1047,10 +1112,10 @@ static int manager_parse_config_file(Manager *m) {
assert(m);
return config_parse_many_nulstr(PKGSYSCONFDIR "/logind.conf",
- CONF_PATHS_NULSTR("systemd/logind.conf.d"),
- "Login\0",
- config_item_perf_lookup, logind_gperf_lookup,
- false, m);
+ CONF_PATHS_NULSTR("systemd/logind.conf.d"),
+ "Login\0",
+ config_item_perf_lookup, logind_gperf_lookup,
+ false, m);
#else
const char* logind_conf = getenv("ELOGIND_CONF_FILE");