logind-session.c revision 13f493dc9ace9861c1f27c4d37e8cd6d52fe6a32
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering This file is part of systemd.
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering Copyright 2011 Lennart Poettering
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering systemd is free software; you can redistribute it and/or modify it
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering under the terms of the GNU Lesser General Public License as published by
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering the Free Software Foundation; either version 2.1 of the License, or
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering (at your option) any later version.
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering systemd is distributed in the hope that it will be useful, but
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering WITHOUT ANY WARRANTY; without even the implied warranty of
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering Lesser General Public License for more details.
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering You should have received a copy of the GNU Lesser General Public License
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering along with systemd; If not, see <http://www.gnu.org/licenses/>.
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poetteringstatic void session_remove_fifo(Session *s);
4f5dd3943bef8a04be7e3b838b822bb9a7ad6cb3Lennart PoetteringSession* session_new(Manager *m, const char *id) {
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering s->state_file = strappend("/run/systemd/sessions/", id);
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering s->devices = hashmap_new(devt_hash_func, devt_compare_func);
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering if (hashmap_put(m->sessions, s->id, s) < 0) {
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering LIST_REMOVE(gc_queue, s->manager->session_gc_queue, s);
13790add4bf648fed816361794d8277a75253410Lennart Poettering s->timer_event_source = sd_event_source_unref(s->timer_event_source);
13790add4bf648fed816361794d8277a75253410Lennart Poettering LIST_REMOVE(sessions_by_user, s->user->sessions, s);
13790add4bf648fed816361794d8277a75253410Lennart Poettering LIST_REMOVE(sessions_by_seat, s->seat->sessions, s);
13790add4bf648fed816361794d8277a75253410Lennart Poettering hashmap_remove(s->manager->session_units, s->scope);
13790add4bf648fed816361794d8277a75253410Lennart Poettering hashmap_remove(s->manager->sessions, s->id);
13790add4bf648fed816361794d8277a75253410Lennart Poetteringvoid session_set_user(Session *s, User *u) {
13790add4bf648fed816361794d8277a75253410Lennart Poettering LIST_PREPEND(sessions_by_user, u->sessions, s);
13790add4bf648fed816361794d8277a75253410Lennart Poettering r = mkdir_safe_label("/run/systemd/sessions", 0755, 0, 0);
13790add4bf648fed816361794d8277a75253410Lennart Poettering r = fopen_temporary(s->state_file, &f, &temp_path);
13790add4bf648fed816361794d8277a75253410Lennart Poettering "# This is private data. Do not parse.\n"
13790add4bf648fed816361794d8277a75253410Lennart Poettering "REMOTE=%i\n",
13790add4bf648fed816361794d8277a75253410Lennart Poettering session_state_to_string(session_get_state(s)),
13790add4bf648fed816361794d8277a75253410Lennart Poettering fprintf(f, "TYPE=%s\n", session_type_to_string(s->type));
13790add4bf648fed816361794d8277a75253410Lennart Poettering fprintf(f, "CLASS=%s\n", session_class_to_string(s->class));
13790add4bf648fed816361794d8277a75253410Lennart Poettering fprintf(f, "SCOPE_JOB=%s\n", s->scope_job);
e3bfb7be07d9b1f4ebb12eb22c4c8bcd2a988d51Zbigniew Jędrzejewski-Szmek fprintf(f, "REMOTE_USER=%s\n", escaped);
e3bfb7be07d9b1f4ebb12eb22c4c8bcd2a988d51Zbigniew Jędrzejewski-Szmek fprintf(f, "VTNR=%u\n", s->vtnr);
e3bfb7be07d9b1f4ebb12eb22c4c8bcd2a988d51Zbigniew Jędrzejewski-Szmek fprintf(f, "POS=%u\n", s->pos);
e3bfb7be07d9b1f4ebb12eb22c4c8bcd2a988d51Zbigniew Jędrzejewski-Szmek fprintf(f, "LEADER="PID_FMT"\n", s->leader);
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering fprintf(f, "AUDIT=%"PRIu32"\n", s->audit_id);
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering if (dual_timestamp_is_set(&s->timestamp))
2de56f70941eaf91a4520bf33de47a87ebd8b2cbZbigniew Jędrzejewski-Szmek fprintf(f, "CONTROLLER=%s\n", s->controller);
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering if (ferror(f) || rename(temp_path, s->state_file) < 0) {
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering log_error("Failed to save session data %s: %s", s->state_file, strerror(-r));
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering r = parse_env_file(s->state_file, NEWLINE,
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering log_error("Failed to read %s: %s", s->state_file, strerror(-r));
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering log_error("UID not specified for session %s", s->id);
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering log_error("Failed to parse UID value %s for session %s.", uid, s->id);
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering user = hashmap_get(s->manager->users, ULONG_TO_PTR((unsigned long) u));
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering log_error("User of session %s not known.", s->id);
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering o = hashmap_get(s->manager->seats, seat);
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering if (!o || r < 0)
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering log_error("Cannot attach session %s to seat %s", s->id, seat);
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering audit_session_from_pid(s->leader, &s->audit_id);
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering /* If we open an unopened pipe for reading we will not
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering get an EOF. to trigger an EOF we hence open it for
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering reading, but close it right-away which then will
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering trigger the EOF. */
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering unsigned long long l;
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering unsigned long long l;
f9a810bedacf1da7c505c1786a2416d592665926Lennart Poettering if (bus_name_has_owner(s->manager->bus, controller, NULL) > 0)
91bf3b3e124575f6f647bff29766e9d992f55b32Lennart Poettering session_set_controller(s, controller, false);
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering /* on seats with VTs, we let VTs manage session-switching */
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering /* On seats without VTs, we implement session-switching in logind. We
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering * try to pause all session-devices and wait until the session
13790add4bf648fed816361794d8277a75253410Lennart Poettering * controller acknowledged them. Once all devices are asleep, we simply
13790add4bf648fed816361794d8277a75253410Lennart Poettering * switch the active session and be done.
13790add4bf648fed816361794d8277a75253410Lennart Poettering * We save the session we want to switch to in seat->pending_switch and
13790add4bf648fed816361794d8277a75253410Lennart Poettering * seat_complete_switch() will perform the final switch. */
13790add4bf648fed816361794d8277a75253410Lennart Poettering /* if no devices are running, immediately perform the session switch */
13790add4bf648fed816361794d8277a75253410Lennart Poettering num_pending = session_device_try_pause_all(s);
13790add4bf648fed816361794d8277a75253410Lennart Poetteringstatic int session_start_scope(Session *s) {
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
13790add4bf648fed816361794d8277a75253410Lennart Poettering description = strjoin("Session ", s->id, " of user ", s->user->name, NULL);
13790add4bf648fed816361794d8277a75253410Lennart Poettering scope = strjoin("session-", s->id, ".scope", NULL);
13790add4bf648fed816361794d8277a75253410Lennart Poettering r = manager_start_scope(s->manager, scope, s->leader, s->user->slice, description, "systemd-logind.service", "systemd-user-sessions.service", &error, &job);
13790add4bf648fed816361794d8277a75253410Lennart Poettering log_error("Failed to start session scope %s: %s %s",
13790add4bf648fed816361794d8277a75253410Lennart Poettering scope, bus_error_message(&error, r), error.name);
f9a810bedacf1da7c505c1786a2416d592665926Lennart Poettering hashmap_put(s->manager->session_units, s->scope, s);
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering /* Create cgroup */
13790add4bf648fed816361794d8277a75253410Lennart Poettering log_struct(s->class == SESSION_BACKGROUND ? LOG_DEBUG : LOG_INFO,
13790add4bf648fed816361794d8277a75253410Lennart Poettering "MESSAGE=New session %s of user %s.", s->id, s->user->name,
13790add4bf648fed816361794d8277a75253410Lennart Poettering if (!dual_timestamp_is_set(&s->timestamp))
13790add4bf648fed816361794d8277a75253410Lennart Poettering /* Save data */
13790add4bf648fed816361794d8277a75253410Lennart Poettering /* Send signals */
13790add4bf648fed816361794d8277a75253410Lennart Poettering user_send_changed(s->user, "Sessions", "Display", NULL);
13790add4bf648fed816361794d8277a75253410Lennart Poettering seat_send_changed(s->seat, "Sessions", "ActiveSession", NULL);
13790add4bf648fed816361794d8277a75253410Lennart Poettering seat_send_changed(s->seat, "Sessions", NULL);
13790add4bf648fed816361794d8277a75253410Lennart Poetteringstatic int session_stop_scope(Session *s, bool force) {
13790add4bf648fed816361794d8277a75253410Lennart Poettering _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
13790add4bf648fed816361794d8277a75253410Lennart Poettering if (force || manager_shall_kill(s->manager, s->user->name)) {
d682b3a7e7c7c2941a4d3e193f1e330dbc9fae89Lennart Poettering r = manager_stop_unit(s->manager, s->scope, &error, &job);
13790add4bf648fed816361794d8277a75253410Lennart Poettering log_error("Failed to stop session scope: %s", bus_error_message(&error, r));
13790add4bf648fed816361794d8277a75253410Lennart Poettering r = manager_abandon_scope(s->manager, s->scope, &error);
13790add4bf648fed816361794d8277a75253410Lennart Poettering log_error("Failed to abandon session scope: %s", bus_error_message(&error, r));
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poetteringint session_stop(Session *s, bool force) {
13790add4bf648fed816361794d8277a75253410Lennart Poettering s->timer_event_source = sd_event_source_unref(s->timer_event_source);
13790add4bf648fed816361794d8277a75253410Lennart Poettering /* We are going down, don't care about FIFOs anymore */
13790add4bf648fed816361794d8277a75253410Lennart Poettering /* Kill cgroup */
13790add4bf648fed816361794d8277a75253410Lennart Poettering log_struct(s->class == SESSION_BACKGROUND ? LOG_DEBUG : LOG_INFO,
13790add4bf648fed816361794d8277a75253410Lennart Poettering s->timer_event_source = sd_event_source_unref(s->timer_event_source);
13790add4bf648fed816361794d8277a75253410Lennart Poettering /* Kill session devices */
13790add4bf648fed816361794d8277a75253410Lennart Poettering seat_send_changed(s->seat, "Sessions", NULL);
13790add4bf648fed816361794d8277a75253410Lennart Poettering user_send_changed(s->user, "Sessions", "Display", NULL);
13790add4bf648fed816361794d8277a75253410Lennart Poetteringstatic int release_timeout_callback(sd_event_source *es, uint64_t usec, void *userdata) {
b92bea5d2a9481de69bb627a7b442a9f58fca43dZbigniew Jędrzejewski-Szmek sd_event_add_time(s->manager->event,
b92bea5d2a9481de69bb627a7b442a9f58fca43dZbigniew Jędrzejewski-Szmek now(CLOCK_MONOTONIC) + RELEASE_USEC, 0,
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poetteringstatic int get_tty_atime(const char *tty, usec_t *atime) {
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering } else if (!path_startswith(tty, "/dev/"))
e22aa3d3284709234f086ebebc13a905a295b7a7Lennart Poetteringstatic int get_process_ctty_atime(pid_t pid, usec_t *atime) {
e22aa3d3284709234f086ebebc13a905a295b7a7Lennart Poetteringint session_get_idle_hint(Session *s, dual_timestamp *t) {
e22aa3d3284709234f086ebebc13a905a295b7a7Lennart Poettering /* Explicit idle hint is set */
e22aa3d3284709234f086ebebc13a905a295b7a7Lennart Poettering /* Graphical sessions should really implement a real
e22aa3d3284709234f086ebebc13a905a295b7a7Lennart Poettering * idle hint logic */
e22aa3d3284709234f086ebebc13a905a295b7a7Lennart Poettering /* For sessions with an explicitly configured tty, let's check
e22aa3d3284709234f086ebebc13a905a295b7a7Lennart Poettering * its atime */
if (s->leader > 0) {
goto found_atime;
*t = s->idle_hint_timestamp;
assert(s);
if (s->idle_hint == b)
s->idle_hint = b;
if (s->seat)
assert(s);
session_stop(s, false);
assert(s);
if (!s->fifo_path) {
return -ENOMEM;
return -errno;
if (s->fifo_fd < 0) {
if (s->fifo_fd < 0)
return -errno;
if (!s->fifo_event_source) {
r = sd_event_add_io(s->manager->event, &s->fifo_event_source, s->fifo_fd, 0, session_dispatch_fifo, s);
return -errno;
assert(s);
if (s->fifo_path) {
assert(s);
if (!s->user)
if (s->fifo_fd >= 0) {
assert(s);
if (s->in_gc_queue)
s->in_gc_queue = true;
assert(s);
return SESSION_CLOSING;
return SESSION_OPENING;
if (session_is_active(s))
return SESSION_ACTIVE;
return SESSION_ONLINE;
assert(s);
if (!s->scope)
return -ESRCH;
return -ENODEV;
if (s->vtfd >= 0)
return s->vtfd;
if (s->vtfd < 0) {
return -errno;
return s->vtfd;
int vt, r;
if (vt < 0)
return vt;
r = -errno;
goto error;
r = -errno;
goto error;
r = -errno;
goto error;
r = -errno;
goto error;
if (vt < 0)
assert(s);
if (s->controller) {
c = s->controller;
free(c);
if (!name)
session_save(s);
assert(s);
return -EBUSY;
return -ENOMEM;
free(t);
r = session_prepare_vt(s);
free(t);
session_swap_controller(s, t);
assert(s);
if (!s->controller)