logind-session.c revision 9209d5121dfb3049cbf280139c4cc40c2038edcc
eacbb4d33e2bb5c54311544851140efe3dd0f774Zbigniew Jędrzejewski-Szmek/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
eacbb4d33e2bb5c54311544851140efe3dd0f774Zbigniew Jędrzejewski-Szmek This file is part of systemd.
eacbb4d33e2bb5c54311544851140efe3dd0f774Zbigniew Jędrzejewski-Szmek Copyright 2011 Lennart Poettering
eacbb4d33e2bb5c54311544851140efe3dd0f774Zbigniew Jędrzejewski-Szmek systemd is free software; you can redistribute it and/or modify it
eacbb4d33e2bb5c54311544851140efe3dd0f774Zbigniew Jędrzejewski-Szmek under the terms of the GNU Lesser General Public License as published by
eacbb4d33e2bb5c54311544851140efe3dd0f774Zbigniew Jędrzejewski-Szmek the Free Software Foundation; either version 2.1 of the License, or
eacbb4d33e2bb5c54311544851140efe3dd0f774Zbigniew Jędrzejewski-Szmek (at your option) any later version.
eacbb4d33e2bb5c54311544851140efe3dd0f774Zbigniew Jędrzejewski-Szmek systemd is distributed in the hope that it will be useful, but
eacbb4d33e2bb5c54311544851140efe3dd0f774Zbigniew Jędrzejewski-Szmek WITHOUT ANY WARRANTY; without even the implied warranty of
eacbb4d33e2bb5c54311544851140efe3dd0f774Zbigniew Jędrzejewski-Szmek MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
eacbb4d33e2bb5c54311544851140efe3dd0f774Zbigniew Jędrzejewski-Szmek Lesser General Public License for more details.
eacbb4d33e2bb5c54311544851140efe3dd0f774Zbigniew Jędrzejewski-Szmek You should have received a copy of the GNU Lesser General Public License
eacbb4d33e2bb5c54311544851140efe3dd0f774Zbigniew Jędrzejewski-Szmek along with systemd; If not, see <http://www.gnu.org/licenses/>.
eacbb4d33e2bb5c54311544851140efe3dd0f774Zbigniew Jędrzejewski-SzmekSession* session_new(Manager *m, const char *id) {
eacbb4d33e2bb5c54311544851140efe3dd0f774Zbigniew Jędrzejewski-Szmek s->state_file = strappend("/run/systemd/sessions/", id);
eacbb4d33e2bb5c54311544851140efe3dd0f774Zbigniew Jędrzejewski-Szmek s->id = path_get_file_name(s->state_file);
eacbb4d33e2bb5c54311544851140efe3dd0f774Zbigniew Jędrzejewski-Szmek if (hashmap_put(m->sessions, s->id, s) < 0) {
eacbb4d33e2bb5c54311544851140efe3dd0f774Zbigniew Jędrzejewski-Szmek LIST_REMOVE(Session, gc_queue, s->manager->session_gc_queue, s);
eacbb4d33e2bb5c54311544851140efe3dd0f774Zbigniew Jędrzejewski-Szmek LIST_REMOVE(Session, sessions_by_user, s->user->sessions, s);
eacbb4d33e2bb5c54311544851140efe3dd0f774Zbigniew Jędrzejewski-Szmek LIST_REMOVE(Session, sessions_by_seat, s->seat->sessions, s);
eacbb4d33e2bb5c54311544851140efe3dd0f774Zbigniew Jędrzejewski-Szmek hashmap_remove(s->manager->session_units, s->scope);
eacbb4d33e2bb5c54311544851140efe3dd0f774Zbigniew Jędrzejewski-Szmek dbus_message_unref(s->create_message);
eacbb4d33e2bb5c54311544851140efe3dd0f774Zbigniew Jędrzejewski-Szmek hashmap_remove(s->manager->sessions, s->id);
eacbb4d33e2bb5c54311544851140efe3dd0f774Zbigniew Jędrzejewski-Szmekvoid session_set_user(Session *s, User *u) {
eacbb4d33e2bb5c54311544851140efe3dd0f774Zbigniew Jędrzejewski-Szmek LIST_PREPEND(Session, sessions_by_user, u->sessions, s);
eacbb4d33e2bb5c54311544851140efe3dd0f774Zbigniew Jędrzejewski-Szmek _cleanup_fclose_ FILE *f = NULL;
eacbb4d33e2bb5c54311544851140efe3dd0f774Zbigniew Jędrzejewski-Szmek _cleanup_free_ char *temp_path = NULL;
eacbb4d33e2bb5c54311544851140efe3dd0f774Zbigniew Jędrzejewski-Szmek r = mkdir_safe_label("/run/systemd/sessions", 0755, 0, 0);
eacbb4d33e2bb5c54311544851140efe3dd0f774Zbigniew Jędrzejewski-Szmek r = fopen_temporary(s->state_file, &f, &temp_path);
eacbb4d33e2bb5c54311544851140efe3dd0f774Zbigniew Jędrzejewski-Szmek "# This is private data. Do not parse.\n"
eacbb4d33e2bb5c54311544851140efe3dd0f774Zbigniew Jędrzejewski-Szmek session_state_to_string(session_get_state(s)),
eacbb4d33e2bb5c54311544851140efe3dd0f774Zbigniew Jędrzejewski-Szmek fprintf(f, "TYPE=%s\n", session_type_to_string(s->type));
eacbb4d33e2bb5c54311544851140efe3dd0f774Zbigniew Jędrzejewski-Szmek fprintf(f, "CLASS=%s\n", session_class_to_string(s->class));
eacbb4d33e2bb5c54311544851140efe3dd0f774Zbigniew Jędrzejewski-Szmek fprintf(f, "SCOPE=%s\n", s->scope);
eacbb4d33e2bb5c54311544851140efe3dd0f774Zbigniew Jędrzejewski-Szmek fprintf(f, "SCOPE_JOB=%s\n", s->scope_job);
eacbb4d33e2bb5c54311544851140efe3dd0f774Zbigniew Jędrzejewski-Szmek fprintf(f, "FIFO=%s\n", s->fifo_path);
eacbb4d33e2bb5c54311544851140efe3dd0f774Zbigniew Jędrzejewski-Szmek fprintf(f, "SEAT=%s\n", s->seat->id);
eacbb4d33e2bb5c54311544851140efe3dd0f774Zbigniew Jędrzejewski-Szmek fprintf(f, "DISPLAY=%s\n", s->display);
eacbb4d33e2bb5c54311544851140efe3dd0f774Zbigniew Jędrzejewski-Szmek fprintf(f, "REMOTE_HOST=%s\n", s->remote_host);
eacbb4d33e2bb5c54311544851140efe3dd0f774Zbigniew Jędrzejewski-Szmek fprintf(f, "REMOTE_USER=%s\n", s->remote_user);
eacbb4d33e2bb5c54311544851140efe3dd0f774Zbigniew Jędrzejewski-Szmek fprintf(f, "SERVICE=%s\n", s->service);
eacbb4d33e2bb5c54311544851140efe3dd0f774Zbigniew Jędrzejewski-Szmek if (s->seat && seat_can_multi_session(s->seat))
eacbb4d33e2bb5c54311544851140efe3dd0f774Zbigniew Jędrzejewski-Szmek fprintf(f, "VTNR=%i\n", s->vtnr);
eacbb4d33e2bb5c54311544851140efe3dd0f774Zbigniew Jędrzejewski-Szmek fprintf(f, "LEADER=%lu\n", (unsigned long) s->leader);
eacbb4d33e2bb5c54311544851140efe3dd0f774Zbigniew Jędrzejewski-Szmek fprintf(f, "AUDIT=%"PRIu32"\n", s->audit_id);
eacbb4d33e2bb5c54311544851140efe3dd0f774Zbigniew Jędrzejewski-Szmek if (dual_timestamp_is_set(&s->timestamp))
eacbb4d33e2bb5c54311544851140efe3dd0f774Zbigniew Jędrzejewski-Szmek "REALTIME=%llu\n"
eacbb4d33e2bb5c54311544851140efe3dd0f774Zbigniew Jędrzejewski-Szmek "MONOTONIC=%llu\n",
eacbb4d33e2bb5c54311544851140efe3dd0f774Zbigniew Jędrzejewski-Szmek (unsigned long long) s->timestamp.realtime,
eacbb4d33e2bb5c54311544851140efe3dd0f774Zbigniew Jędrzejewski-Szmek (unsigned long long) s->timestamp.monotonic);
eacbb4d33e2bb5c54311544851140efe3dd0f774Zbigniew Jędrzejewski-Szmek if (ferror(f) || rename(temp_path, s->state_file) < 0) {
eacbb4d33e2bb5c54311544851140efe3dd0f774Zbigniew Jędrzejewski-Szmek log_error("Failed to save session data for %s: %s", s->id, strerror(-r));
eacbb4d33e2bb5c54311544851140efe3dd0f774Zbigniew Jędrzejewski-Szmek _cleanup_free_ char *remote = NULL,
eacbb4d33e2bb5c54311544851140efe3dd0f774Zbigniew Jędrzejewski-Szmek r = parse_env_file(s->state_file, NEWLINE,
eacbb4d33e2bb5c54311544851140efe3dd0f774Zbigniew Jędrzejewski-Szmek log_error("Failed to read %s: %s", s->state_file, strerror(-r));
eacbb4d33e2bb5c54311544851140efe3dd0f774Zbigniew Jędrzejewski-Szmek log_error("UID not specified for session %s", s->id);
eacbb4d33e2bb5c54311544851140efe3dd0f774Zbigniew Jędrzejewski-Szmek log_error("Failed to parse UID value %s for session %s.", uid, s->id);
eacbb4d33e2bb5c54311544851140efe3dd0f774Zbigniew Jędrzejewski-Szmek user = hashmap_get(s->manager->users, ULONG_TO_PTR((unsigned long) u));
eacbb4d33e2bb5c54311544851140efe3dd0f774Zbigniew Jędrzejewski-Szmek log_error("User of session %s not known.", s->id);
eacbb4d33e2bb5c54311544851140efe3dd0f774Zbigniew Jędrzejewski-Szmek o = hashmap_get(s->manager->seats, seat);
eacbb4d33e2bb5c54311544851140efe3dd0f774Zbigniew Jędrzejewski-Szmek if (vtnr && s->seat && seat_can_multi_session(s->seat)) {
eacbb4d33e2bb5c54311544851140efe3dd0f774Zbigniew Jędrzejewski-Szmek if (k >= 0 && v >= 1)
eacbb4d33e2bb5c54311544851140efe3dd0f774Zbigniew Jędrzejewski-Szmek k = parse_pid(leader, &s->leader);
eacbb4d33e2bb5c54311544851140efe3dd0f774Zbigniew Jędrzejewski-Szmek audit_session_from_pid(s->leader, &s->audit_id);
eacbb4d33e2bb5c54311544851140efe3dd0f774Zbigniew Jędrzejewski-Szmek t = session_type_from_string(type);
eacbb4d33e2bb5c54311544851140efe3dd0f774Zbigniew Jędrzejewski-Szmek c = session_class_from_string(class);
eacbb4d33e2bb5c54311544851140efe3dd0f774Zbigniew Jędrzejewski-Szmek /* If we open an unopened pipe for reading we will not
eacbb4d33e2bb5c54311544851140efe3dd0f774Zbigniew Jędrzejewski-Szmek get an EOF. to trigger an EOF we hence open it for
eacbb4d33e2bb5c54311544851140efe3dd0f774Zbigniew Jędrzejewski-Szmek reading, but close it right-away which then will
eacbb4d33e2bb5c54311544851140efe3dd0f774Zbigniew Jędrzejewski-Szmek trigger the EOF. */
eacbb4d33e2bb5c54311544851140efe3dd0f774Zbigniew Jędrzejewski-Szmek unsigned long long l;
eacbb4d33e2bb5c54311544851140efe3dd0f774Zbigniew Jędrzejewski-Szmek if (sscanf(realtime, "%llu", &l) > 0)
eb56eb9b40950f1edcffdb7313f8de4f8572a6d5Michal Schmidt unsigned long long l;
eacbb4d33e2bb5c54311544851140efe3dd0f774Zbigniew Jędrzejewski-Szmek if (sscanf(monotonic, "%llu", &l) > 0)
eacbb4d33e2bb5c54311544851140efe3dd0f774Zbigniew Jędrzejewski-Szmekint session_activate(Session *s) {
eacbb4d33e2bb5c54311544851140efe3dd0f774Zbigniew Jędrzejewski-Szmekstatic int session_link_x11_socket(Session *s) {
eacbb4d33e2bb5c54311544851140efe3dd0f774Zbigniew Jędrzejewski-Szmek _cleanup_free_ char *t = NULL, *f = NULL;
assert(s);
return log_oom();
return -ENOENT;
return log_oom();
if (link(f, t) < 0) {
unlink(t);
if (link(f, t) >= 0)
goto done;
if (symlink(f, t) < 0) {
unlink(t);
if (symlink(f, t) >= 0)
goto done;
return -errno;
done:
assert(s);
if (!s->scope) {
const char *kill_mode;
if (!description)
return log_oom();
if (!scope)
return log_oom();
r = manager_start_scope(s->manager, scope, s->leader, s->user->slice, description, "systemd-user-sessions.service", kill_mode, &error, &job);
if (s->scope)
assert(s);
if (!s->user)
return -ESTALE;
if (s->started)
r = session_start_scope(s);
NULL);
if (s->seat)
s->started = true;
session_save(s);
session_send_signal(s, true);
if (s->seat) {
char *job;
assert(s);
if (!s->scope)
assert(s);
return log_oom();
r = unlink(t);
return r < 0 ? -errno : 0;
assert(s);
if (!s->user)
return -ESTALE;
r = session_stop_scope(s);
session_save(s);
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);
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);
if (!s->fifo_path) {
return -ENOMEM;
return -errno;
if (s->fifo_fd < 0) {
if (s->fifo_fd < 0)
return -errno;
return -errno;
return -errno;
assert(s);
if (s->fifo_fd >= 0) {
session_save(s);
if (s->fifo_path) {
assert(s);
if (!s->user)
if (s->fifo_fd >= 0) {
if (s->scope_job)
if (s->scope)
assert(s);
if (s->in_gc_queue)
s->in_gc_queue = true;
assert(s);
if (s->closing)
return SESSION_CLOSING;
if (s->scope_job)
return SESSION_OPENING;
if (s->fifo_fd < 0)
return SESSION_CLOSING;
if (session_is_active(s))
return SESSION_ACTIVE;
return SESSION_ONLINE;
assert(s);
if (!s->scope)
return -ESRCH;
assert(s);
assert(s);
return -EBUSY;
return -ENOMEM;
free(t);
s->controller = t;
assert(s);
if (!s->controller)