X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?p=elogind.git;a=blobdiff_plain;f=src%2Flogin%2Flogind-session.c;h=10e9327c0f2e41289843aba2044bda9d8de7a18a;hp=9b6f46b6faebd120ea6dd0615831133727da8fcb;hb=f3f6ae7c983865ea37e8ddfbd676586e55280f1e;hpb=75b4f90262d9c6cfc354f204d9981393daf08f98 diff --git a/src/login/logind-session.c b/src/login/logind-session.c index 9b6f46b6f..10e9327c0 100644 --- a/src/login/logind-session.c +++ b/src/login/logind-session.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -21,26 +19,35 @@ #include #include -#include #include +#include #include #include #include #include #include "sd-messages.h" -#include "util.h" -#include "mkdir.h" -#include "path-util.h" -#include "fileio.h" -#include "audit.h" -#include "bus-util.h" + +#include "alloc-util.h" +#include "audit-util.h" #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" +#include "io-util.h" #include "logind-session.h" -#include "formats-util.h" +#include "mkdir.h" +#include "parse-util.h" +#include "path-util.h" +#include "string-table.h" #include "terminal-util.h" +#include "user-util.h" +#include "util.h" -// #define RELEASE_USEC (20*USEC_PER_SEC) +#define RELEASE_USEC (20*USEC_PER_SEC) static void session_remove_fifo(Session *s); @@ -56,16 +63,13 @@ Session* session_new(Manager *m, const char *id) { return NULL; s->state_file = strappend("/run/systemd/sessions/", id); - if (!s->state_file) { - free(s); - return NULL; - } + if (!s->state_file) + return mfree(s); s->devices = hashmap_new(&devt_hash_ops); if (!s->devices) { free(s->state_file); - free(s); - return NULL; + return mfree(s); } s->id = basename(s->state_file); @@ -73,8 +77,7 @@ Session* session_new(Manager *m, const char *id) { if (hashmap_put(m->sessions, s->id, s) < 0) { hashmap_free(s->devices); free(s->state_file); - free(s); - return NULL; + return mfree(s); } s->manager = m; @@ -125,8 +128,7 @@ void session_free(Session *s) { free(s->scope); } -/// elogind does not support systemd scope_jobs -#if 0 +#if 0 /// elogind does not support systemd scope_jobs free(s->scope_job); #endif // 0 @@ -153,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; @@ -199,8 +213,7 @@ int session_save(Session *s) { if (s->scope) fprintf(f, "SCOPE=%s\n", s->scope); -/// elogind does not support systemd scope_jobs -#if 0 +#if 0 /// elogind does not support systemd scope_jobs if (s->scope_job) fprintf(f, "SCOPE_JOB=%s\n", s->scope_job); #endif // 0 @@ -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; @@ -330,8 +384,7 @@ int session_load(Session *s) { r = parse_env_file(s->state_file, NEWLINE, "REMOTE", &remote, "SCOPE", &s->scope, -/// elogind does not support systemd scope_jobs -#if 0 +#if 0 /// elogind does not support systemd scope_jobs "SCOPE_JOB", &s->scope_job, #endif // 0 "FIFO", &s->fifo_path, @@ -352,6 +405,8 @@ int session_load(Session *s) { "REALTIME", &realtime, "MONOTONIC", &monotonic, "CONTROLLER", &controller, + "ACTIVE", &active, + "DEVICES", &devices, NULL); if (r < 0) @@ -449,22 +504,22 @@ int session_load(Session *s) { safe_close(fd); } - if (realtime) { - unsigned long long l; - if (sscanf(realtime, "%llu", &l) > 0) - s->timestamp.realtime = l; - } + if (realtime) + timestamp_deserialize(realtime, &s->timestamp.realtime); + if (monotonic) + timestamp_deserialize(monotonic, &s->timestamp.monotonic); - if (monotonic) { - unsigned long long l; - if (sscanf(monotonic, "%llu", &l) > 0) - s->timestamp.monotonic = l; + 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) - session_set_controller(s, controller, false); - else + if (bus_name_has_owner(s->manager->bus, controller, NULL) > 0) { + session_set_controller(s, controller, false, false); + session_load_devices(s, devices); + } else session_restore_vt(s); } @@ -508,31 +563,37 @@ int session_activate(Session *s) { return 0; } -/// UNNEEDED by elogind -#if 0 +#if 0 /// UNNEEDED by elogind static int session_start_scope(Session *s) { - int r = 0; + int r; assert(s); assert(s->user); if (!s->scope) { - _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; - _cleanup_free_ char *description = NULL; - char *scope = NULL; //, *job = NULL; + _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; + char *scope, *job = NULL; + const char *description; - description = strjoin("Session ", s->id, " of user ", s->user->name, NULL); - if (!description) - return log_oom(); - - scope = strjoin("session-", s->id, ".scope", NULL); + scope = strjoin("session-", s->id, ".scope"); if (!scope) return log_oom(); - r = manager_start_scope(s->manager, scope, s->leader, s->user->slice, description, "systemd-logind.service", "systemd-user-sessions.service", &error, &job); + description = strjoina("Session ", s->id, " of user ", s->user->name); + + r = manager_start_scope( + s->manager, + scope, + s->leader, + s->user->slice, + description, + "systemd-logind.service", + "systemd-user-sessions.service", + (uint64_t) -1, /* disable TasksMax= for the scope, rely on the slice setting for it */ + &error, + &job); if (r < 0) { - log_error("Failed to start session scope %s: %s %s", - scope, bus_error_message(&error, r), error.name); + log_error_errno(r, "Failed to start session scope %s: %s", scope, bus_error_message(&error, r)); free(scope); return r; } else { @@ -544,12 +605,11 @@ static int session_start_scope(Session *s) { } if (s->scope) - hashmap_put(s->manager->session_units, s->scope, s); + (void) hashmap_put(s->manager->session_units, s->scope, s); return 0; } -#endif // 0 - +#else static int session_start_cgroup(Session *s) { int r; @@ -568,7 +628,7 @@ static int session_start_cgroup(Session *s) { return 0; } - +#endif // 0 int session_start(Session *s) { int r; @@ -586,9 +646,7 @@ int session_start(Session *s) { return r; /* Create cgroup */ -/// elogind does its own session management without systemd units, -/// slices and scopes -#if 0 +#if 0 /// elogind does its own session management r = session_start_scope(s); #else r = session_start_cgroup(s); @@ -597,7 +655,7 @@ int session_start(Session *s) { return r; log_struct(s->class == SESSION_BACKGROUND ? LOG_DEBUG : LOG_INFO, - LOG_MESSAGE_ID(SD_MESSAGE_SESSION_START), + "MESSAGE_ID=" SD_MESSAGE_SESSION_START_STR, "SESSION_ID=%s", s->id, "USER_ID=%s", s->user->name, "LEADER="PID_FMT, s->leader, @@ -622,22 +680,18 @@ int session_start(Session *s) { /* Send signals */ session_send_signal(s, true); - user_send_changed(s->user, "Sessions", "Display", NULL); + user_send_changed(s->user, "Display", NULL); if (s->seat) { if (s->seat->active == s) - seat_send_changed(s->seat, "Sessions", "ActiveSession", NULL); - else - seat_send_changed(s->seat, "Sessions", NULL); + seat_send_changed(s->seat, "ActiveSession", NULL); } return 0; } -/// UNNEEDED by elogind -#if 0 +#if 0 /// UNNEEDED by elogind static int session_stop_scope(Session *s, bool force) { - _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; - char *job = NULL; + _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; int r; assert(s); @@ -645,29 +699,31 @@ static int session_stop_scope(Session *s, bool force) { if (!s->scope) return 0; + /* Let's always abandon the scope first. This tells systemd that we are not interested anymore, and everything + * that is left in the scope is "left-over". Informing systemd about this has the benefit that it will log + * when killing any processes left after this point. */ + r = manager_abandon_scope(s->manager, s->scope, &error); + if (r < 0) + log_warning_errno(r, "Failed to abandon session scope, ignoring: %s", bus_error_message(&error, r)); + + /* Optionally, let's kill everything that's left now. */ if (force || manager_shall_kill(s->manager, s->user->name)) { + char *job = NULL; + r = manager_stop_unit(s->manager, s->scope, &error, &job); - if (r < 0) { - log_error("Failed to stop session scope: %s", bus_error_message(&error, r)); - return r; - } + if (r < 0) + return log_error_errno(r, "Failed to stop session scope: %s", bus_error_message(&error, r)); free(s->scope_job); s->scope_job = job; - } else { - r = manager_abandon_scope(s->manager, s->scope, &error); - if (r < 0) { - log_error("Failed to abandon session scope: %s", bus_error_message(&error, r)); - return r; - } - } + } else + s->scope_job = mfree(s->scope_job); return 0; } -#endif // 0 - +#else static int session_stop_cgroup(Session *s, bool force) { - _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; int r; assert(s); @@ -680,6 +736,7 @@ static int session_stop_cgroup(Session *s, bool force) { return 0; } +#endif // 0 int session_stop(Session *s, bool force) { int r; @@ -698,8 +755,7 @@ int session_stop(Session *s, bool force) { session_remove_fifo(s); /* Kill cgroup */ -/// elogind does not start scopes, but sessions -#if 0 +#if 0 /// elogind does not start scopes, but sessions r = session_stop_scope(s, force); #else r = session_stop_cgroup(s, force); @@ -712,6 +768,10 @@ int session_stop(Session *s, bool force) { session_save(s); user_save(s->user); +#if 1 /// elogind must queue this session again + session_add_to_gc_queue(s); +#endif // 1 + return r; } @@ -725,7 +785,7 @@ int session_finalize(Session *s) { if (s->started) log_struct(s->class == SESSION_BACKGROUND ? LOG_DEBUG : LOG_INFO, - LOG_MESSAGE_ID(SD_MESSAGE_SESSION_STOP), + "MESSAGE_ID=" SD_MESSAGE_SESSION_STOP_STR, "SESSION_ID=%s", s->id, "USER_ID=%s", s->user->name, "LEADER="PID_FMT, s->leader, @@ -755,17 +815,14 @@ int session_finalize(Session *s) { seat_set_active(s->seat, NULL); seat_save(s->seat); - seat_send_changed(s->seat, "Sessions", NULL); } user_save(s->user); - user_send_changed(s->user, "Sessions", "Display", NULL); + user_send_changed(s->user, "Display", NULL); return 0; } -/// UNNEEDED by elogind -#if 0 static int release_timeout_callback(sd_event_source *es, uint64_t usec, void *userdata) { Session *s = userdata; @@ -775,7 +832,6 @@ static int release_timeout_callback(sd_event_source *es, uint64_t usec, void *us session_stop(s, false); return 0; } -#endif // 0 int session_release(Session *s) { assert(s); @@ -786,19 +842,11 @@ int session_release(Session *s) { if (s->timer_event_source) return 0; - /* In systemd, session release is triggered by user jobs - dying. In elogind we don't have that so go ahead and stop - now. */ -#if 0 return sd_event_add_time(s->manager->event, &s->timer_event_source, CLOCK_MONOTONIC, now(CLOCK_MONOTONIC) + RELEASE_USEC, 0, release_timeout_callback, s); - -#else - return session_stop(s, false); -#endif // 0 } bool session_is_active(Session *s) { @@ -863,7 +911,7 @@ int session_get_idle_hint(Session *s, dual_timestamp *t) { /* Graphical sessions should really implement a real * idle hint logic */ - if (s->display) + if (SESSION_TYPE_IS_GRAPHICAL(s->type)) goto dont_know; /* For sessions with an explicitly configured tty, let's check @@ -918,6 +966,23 @@ void session_set_idle_hint(Session *s, bool b) { manager_send_changed(s->manager, "IdleHint", "IdleSinceHint", "IdleSinceHintMonotonic", NULL); } +int session_get_locked_hint(Session *s) { + assert(s); + + return s->locked_hint; +} + +void session_set_locked_hint(Session *s, bool b) { + assert(s); + + if (s->locked_hint == b) + return; + + s->locked_hint = b; + + session_send_changed(s, "LockedHint", NULL); +} + static int session_dispatch_fifo(sd_event_source *es, int fd, uint32_t revents, void *userdata) { Session *s = userdata; @@ -963,7 +1028,9 @@ int session_create_fifo(Session *s) { if (r < 0) return r; - r = sd_event_source_set_priority(s->fifo_event_source, SD_EVENT_PRIORITY_IDLE); + /* Let's make sure we noticed dead sessions before we process new bus requests (which might create new + * sessions). */ + r = sd_event_source_set_priority(s->fifo_event_source, SD_EVENT_PRIORITY_NORMAL-10); if (r < 0) return r; } @@ -1002,8 +1069,7 @@ bool session_check_gc(Session *s, bool drop_not_started) { return true; } -/// elogind supports neither scopes nor jobs -#if 0 +#if 0 /// elogind supports neither scopes nor jobs if (s->scope_job && manager_job_is_active(s->manager, s->scope_job)) return true; @@ -1011,10 +1077,6 @@ bool session_check_gc(Session *s, bool drop_not_started) { return true; #endif // 0 - if ( s->user->manager - && (cg_is_empty_recursive (SYSTEMD_CGROUP_CONTROLLER, s->user->manager->cgroup_root) > 0) ) - return true; - return false; } @@ -1035,8 +1097,7 @@ SessionState session_get_state(Session *s) { if (s->stopping || s->timer_event_source) return SESSION_CLOSING; -/// elogind does not support systemd scope_jobs -#if 0 +#if 0 /// elogind does not support systemd scope_jobs if (s->scope_job || s->fifo_fd < 0) #else if (s->fifo_fd < 0) @@ -1052,8 +1113,7 @@ SessionState session_get_state(Session *s) { int session_kill(Session *s, KillWho who, int signo) { assert(s); -/// Without direct cgroup support, elogind can not kill sessions -#if 0 +#if 0 /// Without direct cgroup support, elogind can not kill sessions if (!s->scope) return -ESRCH; @@ -1069,13 +1129,10 @@ int session_kill(Session *s, KillWho who, int signo) { return log_error_errno(errno, "Failed to kill process leader %d for session %s: %m", s->leader, s->id); } return 0; - } else { - bool sigcont = false; - bool ignore_self = true; - bool rem = true; + } else return cg_kill_recursive (SYSTEMD_CGROUP_CONTROLLER, s->id, signo, - sigcont, ignore_self, rem, NULL); - } + CGROUP_IGNORE_SELF | CGROUP_REMOVE, + NULL, NULL, NULL); #endif // 0 } @@ -1091,7 +1148,7 @@ static int session_open_vt(Session *s) { sprintf(path, "/dev/tty%u", s->vtnr); s->vtfd = open_terminal(path, O_RDWR | O_CLOEXEC | O_NONBLOCK | O_NOCTTY); if (s->vtfd < 0) - return log_error_errno(errno, "cannot open VT %s of session %s: %m", path, s->id); + return log_error_errno(s->vtfd, "cannot open VT %s of session %s: %m", path, s->id); return s->vtfd; } @@ -1255,7 +1312,7 @@ static int on_bus_track(sd_bus_track *track, void *userdata) { return 0; } -int session_set_controller(Session *s, const char *sender, bool force) { +int session_set_controller(Session *s, const char *sender, bool force, bool prepare) { _cleanup_free_ char *name = NULL; int r; @@ -1287,11 +1344,14 @@ int session_set_controller(Session *s, const char *sender, bool force) { * Note that we reset the VT on ReleaseControl() and if the controller * exits. * If logind crashes/restarts, we restore the controller during restart - * or reset the VT in case it crashed/exited, too. */ - r = session_prepare_vt(s); - if (r < 0) { - s->track = sd_bus_track_unref(s->track); - return r; + * (without preparing the VT since the controller has probably overridden + * VT state by now) or reset the VT in case it crashed/exited, too. */ + if (prepare) { + r = session_prepare_vt(s); + if (r < 0) { + s->track = sd_bus_track_unref(s->track); + return r; + } } session_release_controller(s, true);