logind-session.c revision 5f41d1f10fd97e93517b6a762b1bec247f4d1171
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering This file is part of systemd.
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering Copyright 2011 Lennart Poettering
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering systemd is free software; you can redistribute it and/or modify it
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering under the terms of the GNU Lesser General Public License as published by
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering the Free Software Foundation; either version 2.1 of the License, or
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering (at your option) any later version.
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering systemd is distributed in the hope that it will be useful, but
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering WITHOUT ANY WARRANTY; without even the implied warranty of
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering Lesser General Public License for more details.
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering You should have received a copy of the GNU Lesser General Public License
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering along with systemd; If not, see <http://www.gnu.org/licenses/>.
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poetteringstatic void session_remove_fifo(Session *s);
3f9da416457c4265b8f1179516a32ad1a987ff7dLennart Poetteringstatic unsigned long devt_hash_func(const void *p, const uint8_t hash_key[HASH_KEY_SIZE]) {
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poetteringstatic int devt_compare_func(const void *_a, const void *_b) {
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart PoetteringSession* session_new(Manager *m, const char *id) {
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering s->state_file = strappend("/run/systemd/sessions/", id);
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering s->devices = hashmap_new(devt_hash_func, devt_compare_func);
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering if (hashmap_put(m->sessions, s->id, s) < 0) {
5892a914d173e4b968d2a14fbf717373dee3999aDaniel Mack LIST_REMOVE(gc_queue, s->manager->session_gc_queue, s);
5892a914d173e4b968d2a14fbf717373dee3999aDaniel Mack s->timer_event_source = sd_event_source_unref(s->timer_event_source);
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering LIST_REMOVE(sessions_by_user, s->user->sessions, s);
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering LIST_REMOVE(sessions_by_seat, s->seat->sessions, s);
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering hashmap_remove(s->manager->session_units, s->scope);
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering hashmap_remove(s->manager->sessions, s->id);
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering s->vt_source = sd_event_source_unref(s->vt_source);
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poetteringvoid session_set_user(Session *s, User *u) {
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering LIST_PREPEND(sessions_by_user, u->sessions, s);
5892a914d173e4b968d2a14fbf717373dee3999aDaniel Mack r = mkdir_safe_label("/run/systemd/sessions", 0755, 0, 0);
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering r = fopen_temporary(s->state_file, &f, &temp_path);
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering "# This is private data. Do not parse.\n"
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering "REMOTE=%i\n",
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering session_state_to_string(session_get_state(s)),
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering fprintf(f, "TYPE=%s\n", session_type_to_string(s->type));
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering fprintf(f, "CLASS=%s\n", session_class_to_string(s->class));
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering fprintf(f, "SCOPE_JOB=%s\n", s->scope_job);
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering fprintf(f, "REMOTE_HOST=%s\n", s->remote_host);
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering fprintf(f, "REMOTE_USER=%s\n", s->remote_user);
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering fprintf(f, "LEADER="PID_FMT"\n", s->leader);
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering fprintf(f, "AUDIT=%"PRIu32"\n", s->audit_id);
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering if (dual_timestamp_is_set(&s->timestamp))
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering fprintf(f, "CONTROLLER=%s\n", s->controller);
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering if (ferror(f) || rename(temp_path, s->state_file) < 0) {
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering log_error("Failed to save session data %s: %s", s->state_file, strerror(-r));
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering r = parse_env_file(s->state_file, NEWLINE,
5892a914d173e4b968d2a14fbf717373dee3999aDaniel Mack if (r < 0) {
5892a914d173e4b968d2a14fbf717373dee3999aDaniel Mack log_error("Failed to read %s: %s", s->state_file, strerror(-r));
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering log_error("UID not specified for session %s", s->id);
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering log_error("Failed to parse UID value %s for session %s.", uid, s->id);
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering user = hashmap_get(s->manager->users, ULONG_TO_PTR((unsigned long) u));
5892a914d173e4b968d2a14fbf717373dee3999aDaniel Mack log_error("User of session %s not known.", s->id);
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering o = hashmap_get(s->manager->seats, seat);
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering if (!o || r < 0)
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering log_error("Cannot attach session %s to seat %s", s->id, seat);
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering audit_session_from_pid(s->leader, &s->audit_id);
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering /* If we open an unopened pipe for reading we will not
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering get an EOF. to trigger an EOF we hence open it for
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering reading, but close it right-away which then will
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering trigger the EOF. */
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering unsigned long long l;
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering unsigned long long l;
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering if (bus_name_has_owner(s->manager->bus, controller, NULL) > 0)
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering session_set_controller(s, controller, false);
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering /* on seats with VTs, we let VTs manage session-switching */
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering /* On seats without VTs, we implement session-switching in logind. We
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering * try to pause all session-devices and wait until the session
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering * controller acknowledged them. Once all devices are asleep, we simply
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering * switch the active session and be done.
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering * We save the session we want to switch to in seat->pending_switch and
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering * seat_complete_switch() will perform the final switch. */
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering /* if no devices are running, immediately perform the session switch */
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering num_pending = session_device_try_pause_all(s);
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poetteringstatic int session_start_scope(Session *s) {
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering description = strjoin("Session ", s->id, " of user ", s->user->name, NULL);
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering scope = strjoin("session-", s->id, ".scope", NULL);
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering r = manager_start_scope(s->manager, scope, s->leader, s->user->slice, description, "systemd-logind.service", &error, &job);
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering log_error("Failed to start session scope %s: %s %s",
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering scope, bus_error_message(&error, r), error.name);
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering hashmap_put(s->manager->session_units, s->scope, s);
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering /* Create cgroup */
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering log_struct(s->class == SESSION_BACKGROUND ? LOG_DEBUG : LOG_INFO,
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering "MESSAGE=New session %s of user %s.", s->id, s->user->name,
2f671520ebade4877cbf6aca3572a5f8c4e1871dLennart Poettering if (!dual_timestamp_is_set(&s->timestamp))
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering /* Save data */
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering /* Send signals */
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering user_send_changed(s->user, "Sessions", NULL);
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering seat_send_changed(s->seat, "Sessions", "ActiveSession", NULL);
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering seat_send_changed(s->seat, "Sessions", NULL);
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poetteringstatic int session_stop_scope(Session *s) {
54d76c92868838e17d6aad0a3bb0cc7a5b11e35fDaniel Mack _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering if (manager_shall_kill(s->manager, s->user->name)) {
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering r = manager_stop_unit(s->manager, s->scope, &error, &job);
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering log_error("Failed to stop session scope: %s", bus_error_message(&error, r));
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering r = manager_abandon_scope(s->manager, s->scope, &error);
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering log_error("Failed to abandon session scope: %s", bus_error_message(&error, r));
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering s->timer_event_source = sd_event_source_unref(s->timer_event_source);
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering /* We are going down, don't care about FIFOs anymore */
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering /* Kill cgroup */
assert(s);
if (!s->user)
return -ESTALE;
if (s->started)
NULL);
if (s->started) {
session_send_signal(s, false);
s->started = false;
if (s->seat) {
assert(s);
session_stop(s);
assert(s);
if (!s->timer_event_source)
sd_event_add_monotonic(s->manager->event, now(CLOCK_MONOTONIC) + RELEASE_USEC, 0, release_timeout_callback, s, &s->timer_event_source);
assert(s);
if (!s->seat)
return -ENOMEM;
tty = p;
return -ENOENT;
return -errno;
assert(s);
if (s->idle_hint) {
*t = s->idle_hint_timestamp;
return s->idle_hint;
if (s->display)
goto dont_know;
if (s->tty) {
goto found_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);
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_fd, 0, session_dispatch_fifo, s, &s->fifo_event_source);
return -errno;
assert(s);
if (s->fifo_event_source)
if (s->fifo_fd >= 0) {
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;
if (s->scope_job)
return SESSION_OPENING;
if (session_is_active(s))
return SESSION_ACTIVE;
return SESSION_ONLINE;
assert(s);
if (!s->scope)
return -ESRCH;
if (!s->vtnr)
if (s->vtfd >= 0)
return s->vtfd;
if (s->vtfd < 0) {
return s->vtfd;
if (s->vtfd >= 0)
int vt, r;
if (vt < 0)
goto error;
goto error;
goto error;
goto error;
if (vt < 0)
assert(s);
if (s->controller) {
if (!name)
session_save(s);
assert(s);
return -EBUSY;
return -ENOMEM;
free(t);
session_swap_controller(s, t);
session_mute_vt(s);
assert(s);
if (!s->controller)