|
|
9fc0f6 |
From 553a962a570cade5c44953593209d25e28ec5145 Mon Sep 17 00:00:00 2001
|
|
|
9fc0f6 |
From: Michal Sekletar <msekleta@redhat.com>
|
|
|
9fc0f6 |
Date: Mon, 3 Mar 2014 15:37:49 +0100
|
|
|
9fc0f6 |
Subject: [PATCH] logind: rework session shutdown logic
|
|
|
9fc0f6 |
|
|
|
9fc0f6 |
Simplify the shutdown logic a bit:
|
|
|
9fc0f6 |
|
|
|
9fc0f6 |
- Keep the session FIFO around in the PAM module, even after the session
|
|
|
9fc0f6 |
shutdown hook has been finished. This allows logind to track precisely
|
|
|
9fc0f6 |
when the PAM handler goes away.
|
|
|
9fc0f6 |
|
|
|
9fc0f6 |
- In the ReleaseSession() call start a timer, that will stop terminate
|
|
|
9fc0f6 |
the session when elapsed.
|
|
|
9fc0f6 |
|
|
|
9fc0f6 |
- Never fiddle with the KillMode of scopes to configure whether user
|
|
|
9fc0f6 |
processes should be killed or not. Instead, simply leave the scope
|
|
|
9fc0f6 |
units around when we terminate a session whose processes should not be
|
|
|
9fc0f6 |
killed.
|
|
|
9fc0f6 |
|
|
|
9fc0f6 |
- When killing is enabled, stop the session scope on FIFO EOF or after
|
|
|
9fc0f6 |
the ReleaseSession() timeout. When killing is disabled, simply tell
|
|
|
9fc0f6 |
PID 1 to abandon the scope.
|
|
|
9fc0f6 |
|
|
|
9fc0f6 |
Because the scopes stay around and hence all processes are always member
|
|
|
9fc0f6 |
of a scope, the system shutdown logic should be more robust, as the
|
|
|
9fc0f6 |
scopes can be shutdown as part of the usual shutdown logic.
|
|
|
9fc0f6 |
|
|
|
9fc0f6 |
Based-on: 5f41d1f10fd97e93517b6a762b1bec247f4d1171
|
|
|
9fc0f6 |
---
|
|
|
9fc0f6 |
src/login/logind-dbus.c | 51 +++++++++++-------
|
|
|
9fc0f6 |
src/login/logind-session.c | 130 +++++++++++++++++++++++++++++++++++----------
|
|
|
9fc0f6 |
src/login/logind-session.h | 4 ++
|
|
|
9fc0f6 |
src/login/logind-user.c | 23 +++++---
|
|
|
9fc0f6 |
src/login/logind-user.h | 1 +
|
|
|
9fc0f6 |
src/login/logind.c | 23 ++++++--
|
|
|
9fc0f6 |
src/login/logind.h | 4 +-
|
|
|
9fc0f6 |
src/login/pam-module.c | 11 ++--
|
|
|
9fc0f6 |
8 files changed, 182 insertions(+), 65 deletions(-)
|
|
|
9fc0f6 |
|
|
|
9fc0f6 |
diff --git a/src/login/logind-dbus.c b/src/login/logind-dbus.c
|
|
|
9fc0f6 |
index 69e94aa..8de301e 100644
|
|
|
9fc0f6 |
--- a/src/login/logind-dbus.c
|
|
|
9fc0f6 |
+++ b/src/login/logind-dbus.c
|
|
|
9fc0f6 |
@@ -1747,13 +1747,7 @@ static DBusHandlerResult manager_message_handler(
|
|
|
9fc0f6 |
if (!session)
|
|
|
9fc0f6 |
return bus_send_error_reply(connection, message, &error, -ENOENT);
|
|
|
9fc0f6 |
|
|
|
9fc0f6 |
- /* We use the FIFO to detect stray sessions where the
|
|
|
9fc0f6 |
- process invoking PAM dies abnormally. We need to make
|
|
|
9fc0f6 |
- sure that that process is not killed if at the clean
|
|
|
9fc0f6 |
- end of the session it closes the FIFO. Hence, with
|
|
|
9fc0f6 |
- this call explicitly turn off the FIFO logic, so that
|
|
|
9fc0f6 |
- the PAM code can finish clean up on its own */
|
|
|
9fc0f6 |
- session_remove_fifo(session);
|
|
|
9fc0f6 |
+ session_release(session);
|
|
|
9fc0f6 |
|
|
|
9fc0f6 |
reply = dbus_message_new_method_return(message);
|
|
|
9fc0f6 |
if (!reply)
|
|
|
9fc0f6 |
@@ -2551,7 +2545,6 @@ int manager_start_scope(
|
|
|
9fc0f6 |
const char *slice,
|
|
|
9fc0f6 |
const char *description,
|
|
|
9fc0f6 |
const char *after,
|
|
|
9fc0f6 |
- const char *kill_mode,
|
|
|
9fc0f6 |
DBusError *error,
|
|
|
9fc0f6 |
char **job) {
|
|
|
9fc0f6 |
|
|
|
9fc0f6 |
@@ -2623,18 +2616,6 @@ int manager_start_scope(
|
|
|
9fc0f6 |
return log_oom();
|
|
|
9fc0f6 |
}
|
|
|
9fc0f6 |
|
|
|
9fc0f6 |
- if (!isempty(kill_mode)) {
|
|
|
9fc0f6 |
- const char *kill_mode_property = "KillMode";
|
|
|
9fc0f6 |
-
|
|
|
9fc0f6 |
- if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2) ||
|
|
|
9fc0f6 |
- !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &kill_mode_property) ||
|
|
|
9fc0f6 |
- !dbus_message_iter_open_container(&sub2, DBUS_TYPE_VARIANT, "s", &sub3) ||
|
|
|
9fc0f6 |
- !dbus_message_iter_append_basic(&sub3, DBUS_TYPE_STRING, &kill_mode) ||
|
|
|
9fc0f6 |
- !dbus_message_iter_close_container(&sub2, &sub3) ||
|
|
|
9fc0f6 |
- !dbus_message_iter_close_container(&sub, &sub2))
|
|
|
9fc0f6 |
- return log_oom();
|
|
|
9fc0f6 |
- }
|
|
|
9fc0f6 |
-
|
|
|
9fc0f6 |
/* cgroup empty notification is not available in containers
|
|
|
9fc0f6 |
* currently. To make this less problematic, let's shorten the
|
|
|
9fc0f6 |
* stop timeout for sessions, so that we don't wait
|
|
|
9fc0f6 |
@@ -2793,6 +2774,36 @@ int manager_stop_unit(Manager *manager, const char *unit, DBusError *error, char
|
|
|
9fc0f6 |
return 1;
|
|
|
9fc0f6 |
}
|
|
|
9fc0f6 |
|
|
|
9fc0f6 |
+int manager_abandon_scope(Manager *manager, const char *scope, DBusError *error) {
|
|
|
9fc0f6 |
+ _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
|
|
|
9fc0f6 |
+ _cleanup_free_ char *path = NULL;
|
|
|
9fc0f6 |
+ int r;
|
|
|
9fc0f6 |
+
|
|
|
9fc0f6 |
+ assert(manager);
|
|
|
9fc0f6 |
+ assert(scope);
|
|
|
9fc0f6 |
+
|
|
|
9fc0f6 |
+ path = unit_dbus_path_from_name(scope);
|
|
|
9fc0f6 |
+ if (!path)
|
|
|
9fc0f6 |
+ return -ENOMEM;
|
|
|
9fc0f6 |
+
|
|
|
9fc0f6 |
+ r = bus_method_call_with_reply(
|
|
|
9fc0f6 |
+ manager->bus,
|
|
|
9fc0f6 |
+ "org.freedesktop.systemd1",
|
|
|
9fc0f6 |
+ path,
|
|
|
9fc0f6 |
+ "org.freedesktop.systemd1.Scope",
|
|
|
9fc0f6 |
+ "Abandon",
|
|
|
9fc0f6 |
+ &reply,
|
|
|
9fc0f6 |
+ error,
|
|
|
9fc0f6 |
+ DBUS_TYPE_INVALID);
|
|
|
9fc0f6 |
+
|
|
|
9fc0f6 |
+ if (r < 0) {
|
|
|
9fc0f6 |
+ log_error("Failed to abandon scope %s", scope);
|
|
|
9fc0f6 |
+ return r;
|
|
|
9fc0f6 |
+ }
|
|
|
9fc0f6 |
+
|
|
|
9fc0f6 |
+ return 1;
|
|
|
9fc0f6 |
+}
|
|
|
9fc0f6 |
+
|
|
|
9fc0f6 |
int manager_kill_unit(Manager *manager, const char *unit, KillWho who, int signo, DBusError *error) {
|
|
|
9fc0f6 |
_cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
|
|
|
9fc0f6 |
const char *w;
|
|
|
9fc0f6 |
diff --git a/src/login/logind-session.c b/src/login/logind-session.c
|
|
|
9fc0f6 |
index 27aa335..78e6d74 100644
|
|
|
9fc0f6 |
--- a/src/login/logind-session.c
|
|
|
9fc0f6 |
+++ b/src/login/logind-session.c
|
|
|
9fc0f6 |
@@ -24,6 +24,7 @@
|
|
|
9fc0f6 |
#include <unistd.h>
|
|
|
9fc0f6 |
#include <sys/epoll.h>
|
|
|
9fc0f6 |
#include <fcntl.h>
|
|
|
9fc0f6 |
+#include <sys/timerfd.h>
|
|
|
9fc0f6 |
|
|
|
9fc0f6 |
#include <systemd/sd-id128.h>
|
|
|
9fc0f6 |
#include <systemd/sd-messages.h>
|
|
|
9fc0f6 |
@@ -36,6 +37,8 @@
|
|
|
9fc0f6 |
#include "dbus-common.h"
|
|
|
9fc0f6 |
#include "logind-session.h"
|
|
|
9fc0f6 |
|
|
|
9fc0f6 |
+#define RELEASE_SEC 20
|
|
|
9fc0f6 |
+
|
|
|
9fc0f6 |
static unsigned devt_hash_func(const void *p) {
|
|
|
9fc0f6 |
uint64_t u = *(const dev_t*)p;
|
|
|
9fc0f6 |
|
|
|
9fc0f6 |
@@ -505,7 +508,6 @@ static int session_start_scope(Session *s) {
|
|
|
9fc0f6 |
|
|
|
9fc0f6 |
if (!s->scope) {
|
|
|
9fc0f6 |
_cleanup_free_ char *description = NULL;
|
|
|
9fc0f6 |
- const char *kill_mode;
|
|
|
9fc0f6 |
char *scope, *job;
|
|
|
9fc0f6 |
|
|
|
9fc0f6 |
description = strjoin("Session ", s->id, " of user ", s->user->name, NULL);
|
|
|
9fc0f6 |
@@ -516,9 +518,7 @@ static int session_start_scope(Session *s) {
|
|
|
9fc0f6 |
if (!scope)
|
|
|
9fc0f6 |
return log_oom();
|
|
|
9fc0f6 |
|
|
|
9fc0f6 |
- kill_mode = manager_shall_kill(s->manager, s->user->name) ? "control-group" : "none";
|
|
|
9fc0f6 |
-
|
|
|
9fc0f6 |
- r = manager_start_scope(s->manager, scope, s->leader, s->user->slice, description, "systemd-user-sessions.service", kill_mode, &error, &job;;
|
|
|
9fc0f6 |
+ r = manager_start_scope(s->manager, scope, s->leader, s->user->slice, description, "systemd-logind.service", &error, &job;;
|
|
|
9fc0f6 |
if (r < 0) {
|
|
|
9fc0f6 |
log_error("Failed to start session scope %s: %s %s",
|
|
|
9fc0f6 |
scope, bus_error(&error, r), error.name);
|
|
|
9fc0f6 |
@@ -579,23 +579,22 @@ int session_start(Session *s) {
|
|
|
9fc0f6 |
|
|
|
9fc0f6 |
s->started = true;
|
|
|
9fc0f6 |
|
|
|
9fc0f6 |
- /* Save session data */
|
|
|
9fc0f6 |
+ /* Save data */
|
|
|
9fc0f6 |
session_save(s);
|
|
|
9fc0f6 |
user_save(s->user);
|
|
|
9fc0f6 |
+ if (s->seat)
|
|
|
9fc0f6 |
+ seat_save(s->seat);
|
|
|
9fc0f6 |
|
|
|
9fc0f6 |
+ /* Send signals */
|
|
|
9fc0f6 |
session_send_signal(s, true);
|
|
|
9fc0f6 |
|
|
|
9fc0f6 |
if (s->seat) {
|
|
|
9fc0f6 |
- seat_save(s->seat);
|
|
|
9fc0f6 |
-
|
|
|
9fc0f6 |
if (s->seat->active == s)
|
|
|
9fc0f6 |
seat_send_changed(s->seat, "Sessions\0ActiveSession\0");
|
|
|
9fc0f6 |
else
|
|
|
9fc0f6 |
seat_send_changed(s->seat, "Sessions\0");
|
|
|
9fc0f6 |
}
|
|
|
9fc0f6 |
|
|
|
9fc0f6 |
- user_send_changed(s->user, "Sessions\0");
|
|
|
9fc0f6 |
-
|
|
|
9fc0f6 |
return 0;
|
|
|
9fc0f6 |
}
|
|
|
9fc0f6 |
|
|
|
9fc0f6 |
@@ -611,15 +610,24 @@ static int session_stop_scope(Session *s) {
|
|
|
9fc0f6 |
if (!s->scope)
|
|
|
9fc0f6 |
return 0;
|
|
|
9fc0f6 |
|
|
|
9fc0f6 |
- r = manager_stop_unit(s->manager, s->scope, &error, &job;;
|
|
|
9fc0f6 |
- if (r < 0) {
|
|
|
9fc0f6 |
- log_error("Failed to stop session scope: %s", bus_error(&error, r));
|
|
|
9fc0f6 |
- dbus_error_free(&error);
|
|
|
9fc0f6 |
- return r;
|
|
|
9fc0f6 |
- }
|
|
|
9fc0f6 |
+ if (manager_shall_kill(s->manager, s->user->name)) {
|
|
|
9fc0f6 |
+ r = manager_stop_unit(s->manager, s->scope, &error, &job;;
|
|
|
9fc0f6 |
+ if (r < 0) {
|
|
|
9fc0f6 |
+ log_error("Failed to stop session scope: %s", bus_error(&error, r));
|
|
|
9fc0f6 |
+ dbus_error_free(&error);
|
|
|
9fc0f6 |
+ return r;
|
|
|
9fc0f6 |
+ }
|
|
|
9fc0f6 |
|
|
|
9fc0f6 |
- free(s->scope_job);
|
|
|
9fc0f6 |
- s->scope_job = job;
|
|
|
9fc0f6 |
+ free(s->scope_job);
|
|
|
9fc0f6 |
+ s->scope_job = job;
|
|
|
9fc0f6 |
+ } else {
|
|
|
9fc0f6 |
+ r = manager_abandon_scope(s->manager, s->scope, &error);
|
|
|
9fc0f6 |
+ if (r < 0) {
|
|
|
9fc0f6 |
+ log_error("Failed to abandon session scope: %s", bus_error(&error, r));
|
|
|
9fc0f6 |
+ dbus_error_free(&error);
|
|
|
9fc0f6 |
+ return r;
|
|
|
9fc0f6 |
+ }
|
|
|
9fc0f6 |
+ }
|
|
|
9fc0f6 |
|
|
|
9fc0f6 |
return 0;
|
|
|
9fc0f6 |
}
|
|
|
9fc0f6 |
@@ -644,6 +652,19 @@ static int session_unlink_x11_socket(Session *s) {
|
|
|
9fc0f6 |
return r < 0 ? -errno : 0;
|
|
|
9fc0f6 |
}
|
|
|
9fc0f6 |
|
|
|
9fc0f6 |
+static void session_close_timer_fd(Session *s) {
|
|
|
9fc0f6 |
+ assert(s);
|
|
|
9fc0f6 |
+
|
|
|
9fc0f6 |
+ if (s->timer_fd <= 0)
|
|
|
9fc0f6 |
+ return;
|
|
|
9fc0f6 |
+
|
|
|
9fc0f6 |
+ hashmap_remove(s->manager->timer_fds, INT_TO_PTR(s->timer_fd + 1));
|
|
|
9fc0f6 |
+ epoll_ctl(s->manager->epoll_fd, EPOLL_CTL_DEL, s->timer_fd, NULL);
|
|
|
9fc0f6 |
+
|
|
|
9fc0f6 |
+ close_nointr(s->timer_fd);
|
|
|
9fc0f6 |
+ s->timer_fd = -1;
|
|
|
9fc0f6 |
+}
|
|
|
9fc0f6 |
+
|
|
|
9fc0f6 |
int session_stop(Session *s) {
|
|
|
9fc0f6 |
int r;
|
|
|
9fc0f6 |
|
|
|
9fc0f6 |
@@ -652,11 +673,18 @@ int session_stop(Session *s) {
|
|
|
9fc0f6 |
if (!s->user)
|
|
|
9fc0f6 |
return -ESTALE;
|
|
|
9fc0f6 |
|
|
|
9fc0f6 |
+ session_close_timer_fd(s);
|
|
|
9fc0f6 |
+
|
|
|
9fc0f6 |
+ /* We are going down, don't care about FIFOs anymore */
|
|
|
9fc0f6 |
+ session_remove_fifo(s);
|
|
|
9fc0f6 |
+
|
|
|
9fc0f6 |
/* Kill cgroup */
|
|
|
9fc0f6 |
r = session_stop_scope(s);
|
|
|
9fc0f6 |
|
|
|
9fc0f6 |
session_save(s);
|
|
|
9fc0f6 |
|
|
|
9fc0f6 |
+ s->stopping = true;
|
|
|
9fc0f6 |
+
|
|
|
9fc0f6 |
return r;
|
|
|
9fc0f6 |
}
|
|
|
9fc0f6 |
|
|
|
9fc0f6 |
@@ -678,6 +706,8 @@ int session_finalize(Session *s) {
|
|
|
9fc0f6 |
"MESSAGE=Removed session %s.", s->id,
|
|
|
9fc0f6 |
NULL);
|
|
|
9fc0f6 |
|
|
|
9fc0f6 |
+ session_close_timer_fd(s);
|
|
|
9fc0f6 |
+
|
|
|
9fc0f6 |
/* Kill session devices */
|
|
|
9fc0f6 |
while ((sd = hashmap_first(s->devices)))
|
|
|
9fc0f6 |
session_device_free(sd);
|
|
|
9fc0f6 |
@@ -698,16 +728,64 @@ int session_finalize(Session *s) {
|
|
|
9fc0f6 |
if (s->seat->active == s)
|
|
|
9fc0f6 |
seat_set_active(s->seat, NULL);
|
|
|
9fc0f6 |
|
|
|
9fc0f6 |
- seat_send_changed(s->seat, "Sessions\0");
|
|
|
9fc0f6 |
seat_save(s->seat);
|
|
|
9fc0f6 |
+ seat_send_changed(s->seat, "Sessions\0");
|
|
|
9fc0f6 |
}
|
|
|
9fc0f6 |
|
|
|
9fc0f6 |
- user_send_changed(s->user, "Sessions\0");
|
|
|
9fc0f6 |
user_save(s->user);
|
|
|
9fc0f6 |
+ user_send_changed(s->user, "Sessions\0");
|
|
|
9fc0f6 |
|
|
|
9fc0f6 |
return r;
|
|
|
9fc0f6 |
}
|
|
|
9fc0f6 |
|
|
|
9fc0f6 |
+void session_release(Session *s) {
|
|
|
9fc0f6 |
+ int r;
|
|
|
9fc0f6 |
+
|
|
|
9fc0f6 |
+ struct itimerspec its = { .it_value.tv_sec = RELEASE_SEC };
|
|
|
9fc0f6 |
+ struct epoll_event ev = {};
|
|
|
9fc0f6 |
+
|
|
|
9fc0f6 |
+ assert(s);
|
|
|
9fc0f6 |
+
|
|
|
9fc0f6 |
+ if (!s->started || s->stopping)
|
|
|
9fc0f6 |
+ return;
|
|
|
9fc0f6 |
+
|
|
|
9fc0f6 |
+ if (s->timer_fd >= 0)
|
|
|
9fc0f6 |
+ return;
|
|
|
9fc0f6 |
+
|
|
|
9fc0f6 |
+ s->timer_fd = timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK|TFD_CLOEXEC);
|
|
|
9fc0f6 |
+ if (s->timer_fd < 0) {
|
|
|
9fc0f6 |
+ log_error("Failed to create session release timer fd");
|
|
|
9fc0f6 |
+ goto out;
|
|
|
9fc0f6 |
+ }
|
|
|
9fc0f6 |
+
|
|
|
9fc0f6 |
+ r = hashmap_put(s->manager->timer_fds, INT_TO_PTR(s->timer_fd + 1), s);
|
|
|
9fc0f6 |
+ if (r < 0) {
|
|
|
9fc0f6 |
+ log_error("Failed to store session release timer fd");
|
|
|
9fc0f6 |
+ goto out;
|
|
|
9fc0f6 |
+ }
|
|
|
9fc0f6 |
+
|
|
|
9fc0f6 |
+ ev.events = EPOLLONESHOT;
|
|
|
9fc0f6 |
+ ev.data.u32 = FD_OTHER_BASE + s->timer_fd;
|
|
|
9fc0f6 |
+
|
|
|
9fc0f6 |
+ r = epoll_ctl(s->manager->epoll_fd, EPOLL_CTL_ADD, s->timer_fd, &ev;;
|
|
|
9fc0f6 |
+ if (r < 0) {
|
|
|
9fc0f6 |
+ log_error("Failed to add session release timer fd to epoll instance");
|
|
|
9fc0f6 |
+ goto out;
|
|
|
9fc0f6 |
+ }
|
|
|
9fc0f6 |
+
|
|
|
9fc0f6 |
+ r = timerfd_settime(s->timer_fd, TFD_TIMER_ABSTIME, &its, NULL);
|
|
|
9fc0f6 |
+ if (r < 0) {
|
|
|
9fc0f6 |
+ log_error("Failed to arm timer : %m");
|
|
|
9fc0f6 |
+ goto out;
|
|
|
9fc0f6 |
+ }
|
|
|
9fc0f6 |
+
|
|
|
9fc0f6 |
+out:
|
|
|
9fc0f6 |
+ if (s->timer_fd >= 0) {
|
|
|
9fc0f6 |
+ close_nointr(s->timer_fd);
|
|
|
9fc0f6 |
+ s->timer_fd = -1;
|
|
|
9fc0f6 |
+ }
|
|
|
9fc0f6 |
+}
|
|
|
9fc0f6 |
+
|
|
|
9fc0f6 |
bool session_is_active(Session *s) {
|
|
|
9fc0f6 |
assert(s);
|
|
|
9fc0f6 |
|
|
|
9fc0f6 |
@@ -904,8 +982,6 @@ void session_remove_fifo(Session *s) {
|
|
|
9fc0f6 |
}
|
|
|
9fc0f6 |
|
|
|
9fc0f6 |
int session_check_gc(Session *s, bool drop_not_started) {
|
|
|
9fc0f6 |
- int r;
|
|
|
9fc0f6 |
-
|
|
|
9fc0f6 |
assert(s);
|
|
|
9fc0f6 |
|
|
|
9fc0f6 |
if (drop_not_started && !s->started)
|
|
|
9fc0f6 |
@@ -915,11 +991,7 @@ int session_check_gc(Session *s, bool drop_not_started) {
|
|
|
9fc0f6 |
return 0;
|
|
|
9fc0f6 |
|
|
|
9fc0f6 |
if (s->fifo_fd >= 0) {
|
|
|
9fc0f6 |
- r = pipe_eof(s->fifo_fd);
|
|
|
9fc0f6 |
- if (r < 0)
|
|
|
9fc0f6 |
- return r;
|
|
|
9fc0f6 |
-
|
|
|
9fc0f6 |
- if (r == 0)
|
|
|
9fc0f6 |
+ if (pipe_eof(s->fifo_fd) <= 0)
|
|
|
9fc0f6 |
return 1;
|
|
|
9fc0f6 |
}
|
|
|
9fc0f6 |
|
|
|
9fc0f6 |
@@ -945,15 +1017,15 @@ void session_add_to_gc_queue(Session *s) {
|
|
|
9fc0f6 |
SessionState session_get_state(Session *s) {
|
|
|
9fc0f6 |
assert(s);
|
|
|
9fc0f6 |
|
|
|
9fc0f6 |
+ if (s->stopping || s->timer_fd >= 0)
|
|
|
9fc0f6 |
+ return SESSION_CLOSING;
|
|
|
9fc0f6 |
+
|
|
|
9fc0f6 |
if (s->closing)
|
|
|
9fc0f6 |
return SESSION_CLOSING;
|
|
|
9fc0f6 |
|
|
|
9fc0f6 |
if (s->scope_job)
|
|
|
9fc0f6 |
return SESSION_OPENING;
|
|
|
9fc0f6 |
|
|
|
9fc0f6 |
- if (s->fifo_fd < 0)
|
|
|
9fc0f6 |
- return SESSION_CLOSING;
|
|
|
9fc0f6 |
-
|
|
|
9fc0f6 |
if (session_is_active(s))
|
|
|
9fc0f6 |
return SESSION_ACTIVE;
|
|
|
9fc0f6 |
|
|
|
9fc0f6 |
diff --git a/src/login/logind-session.h b/src/login/logind-session.h
|
|
|
9fc0f6 |
index f175a89..9b76582 100644
|
|
|
9fc0f6 |
--- a/src/login/logind-session.h
|
|
|
9fc0f6 |
+++ b/src/login/logind-session.h
|
|
|
9fc0f6 |
@@ -98,11 +98,14 @@ struct Session {
|
|
|
9fc0f6 |
int fifo_fd;
|
|
|
9fc0f6 |
char *fifo_path;
|
|
|
9fc0f6 |
|
|
|
9fc0f6 |
+ int timer_fd;
|
|
|
9fc0f6 |
+
|
|
|
9fc0f6 |
bool idle_hint;
|
|
|
9fc0f6 |
dual_timestamp idle_hint_timestamp;
|
|
|
9fc0f6 |
|
|
|
9fc0f6 |
bool in_gc_queue:1;
|
|
|
9fc0f6 |
bool started:1;
|
|
|
9fc0f6 |
+ bool stopping:1;
|
|
|
9fc0f6 |
bool closing:1;
|
|
|
9fc0f6 |
|
|
|
9fc0f6 |
DBusMessage *create_message;
|
|
|
9fc0f6 |
@@ -130,6 +133,7 @@ void session_remove_fifo(Session *s);
|
|
|
9fc0f6 |
int session_start(Session *s);
|
|
|
9fc0f6 |
int session_stop(Session *s);
|
|
|
9fc0f6 |
int session_finalize(Session *s);
|
|
|
9fc0f6 |
+void session_release(Session *s);
|
|
|
9fc0f6 |
int session_save(Session *s);
|
|
|
9fc0f6 |
int session_load(Session *s);
|
|
|
9fc0f6 |
int session_kill(Session *s, KillWho who, int signo);
|
|
|
9fc0f6 |
diff --git a/src/login/logind-user.c b/src/login/logind-user.c
|
|
|
9fc0f6 |
index 8e7256b..653574e 100644
|
|
|
9fc0f6 |
--- a/src/login/logind-user.c
|
|
|
9fc0f6 |
+++ b/src/login/logind-user.c
|
|
|
9fc0f6 |
@@ -487,6 +487,8 @@ int user_stop(User *u) {
|
|
|
9fc0f6 |
if (k < 0)
|
|
|
9fc0f6 |
r = k;
|
|
|
9fc0f6 |
|
|
|
9fc0f6 |
+ u->stopping = true;
|
|
|
9fc0f6 |
+
|
|
|
9fc0f6 |
user_save(u);
|
|
|
9fc0f6 |
|
|
|
9fc0f6 |
return r;
|
|
|
9fc0f6 |
@@ -602,22 +604,27 @@ void user_add_to_gc_queue(User *u) {
|
|
|
9fc0f6 |
|
|
|
9fc0f6 |
UserState user_get_state(User *u) {
|
|
|
9fc0f6 |
Session *i;
|
|
|
9fc0f6 |
- bool all_closing = true;
|
|
|
9fc0f6 |
|
|
|
9fc0f6 |
assert(u);
|
|
|
9fc0f6 |
|
|
|
9fc0f6 |
+ if (u->stopping)
|
|
|
9fc0f6 |
+ return USER_CLOSING;
|
|
|
9fc0f6 |
+
|
|
|
9fc0f6 |
if (u->slice_job || u->service_job)
|
|
|
9fc0f6 |
return USER_OPENING;
|
|
|
9fc0f6 |
|
|
|
9fc0f6 |
- LIST_FOREACH(sessions_by_user, i, u->sessions) {
|
|
|
9fc0f6 |
- if (session_is_active(i))
|
|
|
9fc0f6 |
- return USER_ACTIVE;
|
|
|
9fc0f6 |
- if (session_get_state(i) != SESSION_CLOSING)
|
|
|
9fc0f6 |
- all_closing = false;
|
|
|
9fc0f6 |
- }
|
|
|
9fc0f6 |
+ if (u->sessions) {
|
|
|
9fc0f6 |
+ bool all_closing = true;
|
|
|
9fc0f6 |
+
|
|
|
9fc0f6 |
+ LIST_FOREACH(sessions_by_user, i, u->sessions) {
|
|
|
9fc0f6 |
+ if (session_is_active(i))
|
|
|
9fc0f6 |
+ return USER_ACTIVE;
|
|
|
9fc0f6 |
+ if (session_get_state(i) != SESSION_CLOSING)
|
|
|
9fc0f6 |
+ all_closing = false;
|
|
|
9fc0f6 |
+ }
|
|
|
9fc0f6 |
|
|
|
9fc0f6 |
- if (u->sessions)
|
|
|
9fc0f6 |
return all_closing ? USER_CLOSING : USER_ONLINE;
|
|
|
9fc0f6 |
+ }
|
|
|
9fc0f6 |
|
|
|
9fc0f6 |
if (user_check_linger_file(u) > 0)
|
|
|
9fc0f6 |
return USER_LINGERING;
|
|
|
9fc0f6 |
diff --git a/src/login/logind-user.h b/src/login/logind-user.h
|
|
|
9fc0f6 |
index a36f456..a12532e 100644
|
|
|
9fc0f6 |
--- a/src/login/logind-user.h
|
|
|
9fc0f6 |
+++ b/src/login/logind-user.h
|
|
|
9fc0f6 |
@@ -61,6 +61,7 @@ struct User {
|
|
|
9fc0f6 |
|
|
|
9fc0f6 |
bool in_gc_queue:1;
|
|
|
9fc0f6 |
bool started:1;
|
|
|
9fc0f6 |
+ bool stopping:1;
|
|
|
9fc0f6 |
|
|
|
9fc0f6 |
LIST_HEAD(Session, sessions);
|
|
|
9fc0f6 |
LIST_FIELDS(User, gc_queue);
|
|
|
9fc0f6 |
diff --git a/src/login/logind.c b/src/login/logind.c
|
|
|
9fc0f6 |
index 0628032..5180be7 100644
|
|
|
9fc0f6 |
--- a/src/login/logind.c
|
|
|
9fc0f6 |
+++ b/src/login/logind.c
|
|
|
9fc0f6 |
@@ -80,10 +80,11 @@ Manager *manager_new(void) {
|
|
|
9fc0f6 |
m->session_fds = hashmap_new(trivial_hash_func, trivial_compare_func);
|
|
|
9fc0f6 |
m->inhibitor_fds = hashmap_new(trivial_hash_func, trivial_compare_func);
|
|
|
9fc0f6 |
m->button_fds = hashmap_new(trivial_hash_func, trivial_compare_func);
|
|
|
9fc0f6 |
+ m->timer_fds = hashmap_new(trivial_hash_func, trivial_compare_func);
|
|
|
9fc0f6 |
|
|
|
9fc0f6 |
if (!m->devices || !m->seats || !m->sessions || !m->users || !m->inhibitors || !m->buttons || !m->busnames ||
|
|
|
9fc0f6 |
!m->user_units || !m->session_units ||
|
|
|
9fc0f6 |
- !m->session_fds || !m->inhibitor_fds || !m->button_fds) {
|
|
|
9fc0f6 |
+ !m->session_fds || !m->inhibitor_fds || !m->button_fds || !m->timer_fds) {
|
|
|
9fc0f6 |
manager_free(m);
|
|
|
9fc0f6 |
return NULL;
|
|
|
9fc0f6 |
}
|
|
|
9fc0f6 |
@@ -149,6 +150,7 @@ void manager_free(Manager *m) {
|
|
|
9fc0f6 |
hashmap_free(m->session_fds);
|
|
|
9fc0f6 |
hashmap_free(m->inhibitor_fds);
|
|
|
9fc0f6 |
hashmap_free(m->button_fds);
|
|
|
9fc0f6 |
+ hashmap_free(m->timer_fds);
|
|
|
9fc0f6 |
|
|
|
9fc0f6 |
if (m->console_active_fd >= 0)
|
|
|
9fc0f6 |
close_nointr_nofail(m->console_active_fd);
|
|
|
9fc0f6 |
@@ -620,6 +622,13 @@ static void manager_dispatch_other(Manager *m, int fd) {
|
|
|
9fc0f6 |
return;
|
|
|
9fc0f6 |
}
|
|
|
9fc0f6 |
|
|
|
9fc0f6 |
+ s = hashmap_get(m->timer_fds, INT_TO_PTR(fd + 1));
|
|
|
9fc0f6 |
+ if (s) {
|
|
|
9fc0f6 |
+ assert(s->timer_fd == fd);
|
|
|
9fc0f6 |
+ session_stop(s);
|
|
|
9fc0f6 |
+ return;
|
|
|
9fc0f6 |
+ }
|
|
|
9fc0f6 |
+
|
|
|
9fc0f6 |
i = hashmap_get(m->inhibitor_fds, INT_TO_PTR(fd + 1));
|
|
|
9fc0f6 |
if (i) {
|
|
|
9fc0f6 |
assert(i->fifo_fd == fd);
|
|
|
9fc0f6 |
@@ -942,8 +951,12 @@ void manager_gc(Manager *m, bool drop_not_started) {
|
|
|
9fc0f6 |
LIST_REMOVE(Session, gc_queue, m->session_gc_queue, session);
|
|
|
9fc0f6 |
session->in_gc_queue = false;
|
|
|
9fc0f6 |
|
|
|
9fc0f6 |
- if (session_check_gc(session, drop_not_started) == 0) {
|
|
|
9fc0f6 |
+ /* First, if we are not closing yet, initiate stopping */
|
|
|
9fc0f6 |
+ if (!session_check_gc(session, drop_not_started) &&
|
|
|
9fc0f6 |
+ session_get_state(session) != SESSION_CLOSING)
|
|
|
9fc0f6 |
session_stop(session);
|
|
|
9fc0f6 |
+
|
|
|
9fc0f6 |
+ if (!session_check_gc(session, drop_not_started)) {
|
|
|
9fc0f6 |
session_finalize(session);
|
|
|
9fc0f6 |
session_free(session);
|
|
|
9fc0f6 |
}
|
|
|
9fc0f6 |
@@ -953,8 +966,11 @@ void manager_gc(Manager *m, bool drop_not_started) {
|
|
|
9fc0f6 |
LIST_REMOVE(User, gc_queue, m->user_gc_queue, user);
|
|
|
9fc0f6 |
user->in_gc_queue = false;
|
|
|
9fc0f6 |
|
|
|
9fc0f6 |
- if (user_check_gc(user, drop_not_started) == 0) {
|
|
|
9fc0f6 |
+ if (!user_check_gc(user, drop_not_started) &&
|
|
|
9fc0f6 |
+ user_get_state(user) != USER_CLOSING)
|
|
|
9fc0f6 |
user_stop(user);
|
|
|
9fc0f6 |
+
|
|
|
9fc0f6 |
+ if (!user_check_gc(user, drop_not_started)) {
|
|
|
9fc0f6 |
user_finalize(user);
|
|
|
9fc0f6 |
user_free(user);
|
|
|
9fc0f6 |
}
|
|
|
9fc0f6 |
@@ -1032,6 +1048,7 @@ finish:
|
|
|
9fc0f6 |
|
|
|
9fc0f6 |
return r;
|
|
|
9fc0f6 |
}
|
|
|
9fc0f6 |
+
|
|
|
9fc0f6 |
int manager_startup(Manager *m) {
|
|
|
9fc0f6 |
int r;
|
|
|
9fc0f6 |
Seat *seat;
|
|
|
9fc0f6 |
diff --git a/src/login/logind.h b/src/login/logind.h
|
|
|
9fc0f6 |
index 9e6296c..0d2248f 100644
|
|
|
9fc0f6 |
--- a/src/login/logind.h
|
|
|
9fc0f6 |
+++ b/src/login/logind.h
|
|
|
9fc0f6 |
@@ -88,6 +88,7 @@ struct Manager {
|
|
|
9fc0f6 |
Hashmap *session_fds;
|
|
|
9fc0f6 |
Hashmap *inhibitor_fds;
|
|
|
9fc0f6 |
Hashmap *button_fds;
|
|
|
9fc0f6 |
+ Hashmap *timer_fds;
|
|
|
9fc0f6 |
|
|
|
9fc0f6 |
usec_t inhibit_delay_max;
|
|
|
9fc0f6 |
|
|
|
9fc0f6 |
@@ -183,9 +184,10 @@ int manager_send_changed(Manager *manager, const char *properties);
|
|
|
9fc0f6 |
|
|
|
9fc0f6 |
int manager_dispatch_delayed(Manager *manager);
|
|
|
9fc0f6 |
|
|
|
9fc0f6 |
-int manager_start_scope(Manager *manager, const char *scope, pid_t pid, const char *slice, const char *description, const char *after, const char *kill_mode, DBusError *error, char **job);
|
|
|
9fc0f6 |
+int manager_start_scope(Manager *manager, const char *scope, pid_t pid, const char *slice, const char *description, const char *after, DBusError *error, char **job);
|
|
|
9fc0f6 |
int manager_start_unit(Manager *manager, const char *unit, DBusError *error, char **job);
|
|
|
9fc0f6 |
int manager_stop_unit(Manager *manager, const char *unit, DBusError *error, char **job);
|
|
|
9fc0f6 |
+int manager_abandon_scope(Manager *manager, const char *scope, DBusError *error);
|
|
|
9fc0f6 |
int manager_kill_unit(Manager *manager, const char *unit, KillWho who, int signo, DBusError *error);
|
|
|
9fc0f6 |
int manager_unit_is_active(Manager *manager, const char *unit);
|
|
|
9fc0f6 |
|
|
|
9fc0f6 |
diff --git a/src/login/pam-module.c b/src/login/pam-module.c
|
|
|
9fc0f6 |
index 22d9733..7bd4783 100644
|
|
|
9fc0f6 |
--- a/src/login/pam-module.c
|
|
|
9fc0f6 |
+++ b/src/login/pam-module.c
|
|
|
9fc0f6 |
@@ -478,7 +478,7 @@ _public_ PAM_EXTERN int pam_sm_close_session(
|
|
|
9fc0f6 |
int flags,
|
|
|
9fc0f6 |
int argc, const char **argv) {
|
|
|
9fc0f6 |
|
|
|
9fc0f6 |
- const void *p = NULL, *existing = NULL;
|
|
|
9fc0f6 |
+ const void *existing = NULL;
|
|
|
9fc0f6 |
const char *id;
|
|
|
9fc0f6 |
DBusConnection *bus = NULL;
|
|
|
9fc0f6 |
DBusMessage *m = NULL, *reply = NULL;
|
|
|
9fc0f6 |
@@ -535,12 +535,15 @@ _public_ PAM_EXTERN int pam_sm_close_session(
|
|
|
9fc0f6 |
}
|
|
|
9fc0f6 |
}
|
|
|
9fc0f6 |
|
|
|
9fc0f6 |
+
|
|
|
9fc0f6 |
+ /* Note that we are knowingly leaking the FIFO fd here. This
|
|
|
9fc0f6 |
+ * way, logind can watch us die. If we closed it here it would
|
|
|
9fc0f6 |
+ * not have any clue when that is completed. Given that one
|
|
|
9fc0f6 |
+ * cannot really have multiple PAM sessions open from the same
|
|
|
9fc0f6 |
+ * process this means we will leak one FD at max. */
|
|
|
9fc0f6 |
r = PAM_SUCCESS;
|
|
|
9fc0f6 |
|
|
|
9fc0f6 |
finish:
|
|
|
9fc0f6 |
- pam_get_data(handle, "systemd.session-fd", &p);
|
|
|
9fc0f6 |
- if (p)
|
|
|
9fc0f6 |
- close_nointr(PTR_TO_INT(p) - 1);
|
|
|
9fc0f6 |
|
|
|
9fc0f6 |
dbus_error_free(&error);
|
|
|
9fc0f6 |
|