1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
4 This file is part of systemd.
6 Copyright 2011 Lennart Poettering
8 systemd is free software; you can redistribute it and/or modify it
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
11 (at your option) any later version.
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
18 You should have received a copy of the GNU Lesser General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
28 #include <sys/ioctl.h>
32 #include "sd-messages.h"
36 #include "path-util.h"
40 #include "bus-error.h"
41 #include "logind-session.h"
43 #define RELEASE_USEC (20*USEC_PER_SEC)
45 static void session_remove_fifo(Session *s);
47 static unsigned long devt_hash_func(const void *p, const uint8_t hash_key[HASH_KEY_SIZE]) {
48 uint64_t u = *(const dev_t*)p;
50 return uint64_hash_func(&u, hash_key);
53 static int devt_compare_func(const void *_a, const void *_b) {
56 a = *(const dev_t*) _a;
57 b = *(const dev_t*) _b;
59 return a < b ? -1 : (a > b ? 1 : 0);
62 Session* session_new(Manager *m, const char *id) {
67 assert(session_id_valid(id));
73 s->state_file = strappend("/run/systemd/sessions/", id);
79 s->devices = hashmap_new(devt_hash_func, devt_compare_func);
86 s->id = basename(s->state_file);
88 if (hashmap_put(m->sessions, s->id, s) < 0) {
89 hashmap_free(s->devices);
102 void session_free(Session *s) {
108 LIST_REMOVE(gc_queue, s->manager->session_gc_queue, s);
110 s->timer_event_source = sd_event_source_unref(s->timer_event_source);
112 session_remove_fifo(s);
114 session_drop_controller(s);
116 while ((sd = hashmap_first(s->devices)))
117 session_device_free(sd);
119 hashmap_free(s->devices);
122 LIST_REMOVE(sessions_by_user, s->user->sessions, s);
124 if (s->user->display == s)
125 s->user->display = NULL;
129 if (s->seat->active == s)
130 s->seat->active = NULL;
131 if (s->seat->pending_switch == s)
132 s->seat->pending_switch = NULL;
134 seat_evict_position(s->seat, s);
135 LIST_REMOVE(sessions_by_seat, s->seat->sessions, s);
139 hashmap_remove(s->manager->session_units, s->scope);
145 sd_bus_message_unref(s->create_message);
149 free(s->remote_host);
150 free(s->remote_user);
154 hashmap_remove(s->manager->sessions, s->id);
156 s->vt_source = sd_event_source_unref(s->vt_source);
162 void session_set_user(Session *s, User *u) {
167 LIST_PREPEND(sessions_by_user, u->sessions, s);
170 int session_save(Session *s) {
171 _cleanup_free_ char *temp_path = NULL;
172 _cleanup_fclose_ FILE *f = NULL;
183 r = mkdir_safe_label("/run/systemd/sessions", 0755, 0, 0);
187 r = fopen_temporary(s->state_file, &f, &temp_path);
193 fchmod(fileno(f), 0644);
196 "# This is private data. Do not parse.\n"
204 session_is_active(s),
205 session_state_to_string(session_get_state(s)),
209 fprintf(f, "TYPE=%s\n", session_type_to_string(s->type));
212 fprintf(f, "CLASS=%s\n", session_class_to_string(s->class));
215 fprintf(f, "SCOPE=%s\n", s->scope);
217 fprintf(f, "SCOPE_JOB=%s\n", s->scope_job);
220 fprintf(f, "FIFO=%s\n", s->fifo_path);
223 fprintf(f, "SEAT=%s\n", s->seat->id);
226 fprintf(f, "TTY=%s\n", s->tty);
229 fprintf(f, "DISPLAY=%s\n", s->display);
231 if (s->remote_host) {
232 _cleanup_free_ char *escaped;
234 escaped = cescape(s->remote_host);
240 fprintf(f, "REMOTE_HOST=%s\n", escaped);
243 if (s->remote_user) {
244 _cleanup_free_ char *escaped;
246 escaped = cescape(s->remote_user);
252 fprintf(f, "REMOTE_USER=%s\n", escaped);
256 _cleanup_free_ char *escaped;
258 escaped = cescape(s->service);
264 fprintf(f, "SERVICE=%s\n", escaped);
268 _cleanup_free_ char *escaped;
271 escaped = cescape(s->desktop);
277 fprintf(f, "DESKTOP=%s\n", escaped);
280 if (s->seat && seat_has_vts(s->seat))
281 fprintf(f, "VTNR=%u\n", s->vtnr);
284 fprintf(f, "POS=%u\n", s->pos);
287 fprintf(f, "LEADER="PID_FMT"\n", s->leader);
290 fprintf(f, "AUDIT=%"PRIu32"\n", s->audit_id);
292 if (dual_timestamp_is_set(&s->timestamp))
294 "REALTIME="USEC_FMT"\n"
295 "MONOTONIC="USEC_FMT"\n",
296 s->timestamp.realtime,
297 s->timestamp.monotonic);
300 fprintf(f, "CONTROLLER=%s\n", s->controller);
304 if (ferror(f) || rename(temp_path, s->state_file) < 0) {
306 unlink(s->state_file);
312 log_error("Failed to save session data %s: %s", s->state_file, strerror(-r));
317 int session_load(Session *s) {
318 _cleanup_free_ char *remote = NULL,
334 r = parse_env_file(s->state_file, NEWLINE,
337 "SCOPE_JOB", &s->scope_job,
338 "FIFO", &s->fifo_path,
341 "DISPLAY", &s->display,
342 "REMOTE_HOST", &s->remote_host,
343 "REMOTE_USER", &s->remote_user,
344 "SERVICE", &s->service,
345 "DESKTOP", &s->desktop,
352 "REALTIME", &realtime,
353 "MONOTONIC", &monotonic,
354 "CONTROLLER", &controller,
358 log_error("Failed to read %s: %s", s->state_file, strerror(-r));
367 log_error("UID not specified for session %s", s->id);
371 r = parse_uid(uid, &u);
373 log_error("Failed to parse UID value %s for session %s.", uid, s->id);
377 user = hashmap_get(s->manager->users, ULONG_TO_PTR((unsigned long) u));
379 log_error("User of session %s not known.", s->id);
383 session_set_user(s, user);
387 k = parse_boolean(remote);
393 safe_atou(vtnr, &s->vtnr);
395 if (seat && !s->seat) {
398 o = hashmap_get(s->manager->seats, seat);
400 r = seat_attach_session(o, s);
402 log_error("Cannot attach session %s to seat %s", s->id, seat);
405 if (!s->seat || !seat_has_vts(s->seat))
408 if (pos && s->seat) {
411 safe_atou(pos, &npos);
412 seat_claim_position(s->seat, s, npos);
416 k = parse_pid(leader, &s->leader);
418 audit_session_from_pid(s->leader, &s->audit_id);
424 t = session_type_from_string(type);
432 c = session_class_from_string(class);
440 /* If we open an unopened pipe for reading we will not
441 get an EOF. to trigger an EOF we hence open it for
442 reading, but close it right-away which then will
445 fd = session_create_fifo(s);
450 unsigned long long l;
451 if (sscanf(realtime, "%llu", &l) > 0)
452 s->timestamp.realtime = l;
456 unsigned long long l;
457 if (sscanf(monotonic, "%llu", &l) > 0)
458 s->timestamp.monotonic = l;
462 if (bus_name_has_owner(s->manager->bus, controller, NULL) > 0)
463 session_set_controller(s, controller, false);
465 session_restore_vt(s);
471 int session_activate(Session *s) {
472 unsigned int num_pending;
480 if (s->seat->active == s)
483 /* on seats with VTs, we let VTs manage session-switching */
484 if (seat_has_vts(s->seat)) {
488 return chvt(s->vtnr);
491 /* On seats without VTs, we implement session-switching in logind. We
492 * try to pause all session-devices and wait until the session
493 * controller acknowledged them. Once all devices are asleep, we simply
494 * switch the active session and be done.
495 * We save the session we want to switch to in seat->pending_switch and
496 * seat_complete_switch() will perform the final switch. */
498 s->seat->pending_switch = s;
500 /* if no devices are running, immediately perform the session switch */
501 num_pending = session_device_try_pause_all(s);
503 seat_complete_switch(s->seat);
508 static int session_start_scope(Session *s) {
513 assert(s->user->slice);
516 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
517 _cleanup_free_ char *description = NULL;
518 char *scope, *job = NULL;
520 description = strjoin("Session ", s->id, " of user ", s->user->name, NULL);
524 scope = strjoin("session-", s->id, ".scope", NULL);
528 r = manager_start_scope(s->manager, scope, s->leader, s->user->slice, description, "systemd-logind.service", "systemd-user-sessions.service", &error, &job);
530 log_error("Failed to start session scope %s: %s %s",
531 scope, bus_error_message(&error, r), error.name);
543 hashmap_put(s->manager->session_units, s->scope, s);
548 int session_start(Session *s) {
559 r = user_start(s->user);
564 r = session_start_scope(s);
568 log_struct(s->class == SESSION_BACKGROUND ? LOG_DEBUG : LOG_INFO,
569 MESSAGE_ID(SD_MESSAGE_SESSION_START),
570 "SESSION_ID=%s", s->id,
571 "USER_ID=%s", s->user->name,
572 "LEADER="PID_FMT, s->leader,
573 "MESSAGE=New session %s of user %s.", s->id, s->user->name,
576 if (!dual_timestamp_is_set(&s->timestamp))
577 dual_timestamp_get(&s->timestamp);
580 seat_read_active_vt(s->seat);
584 user_elect_display(s->user);
593 session_send_signal(s, true);
594 user_send_changed(s->user, "Sessions", "Display", NULL);
596 if (s->seat->active == s)
597 seat_send_changed(s->seat, "Sessions", "ActiveSession", NULL);
599 seat_send_changed(s->seat, "Sessions", NULL);
605 static int session_stop_scope(Session *s, bool force) {
606 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
615 if (force || manager_shall_kill(s->manager, s->user->name)) {
616 r = manager_stop_unit(s->manager, s->scope, &error, &job);
618 log_error("Failed to stop session scope: %s", bus_error_message(&error, r));
625 r = manager_abandon_scope(s->manager, s->scope, &error);
627 log_error("Failed to abandon session scope: %s", bus_error_message(&error, r));
635 int session_stop(Session *s, bool force) {
643 s->timer_event_source = sd_event_source_unref(s->timer_event_source);
645 /* We are going down, don't care about FIFOs anymore */
646 session_remove_fifo(s);
649 r = session_stop_scope(s, force);
653 user_elect_display(s->user);
661 int session_finalize(Session *s) {
671 log_struct(s->class == SESSION_BACKGROUND ? LOG_DEBUG : LOG_INFO,
672 MESSAGE_ID(SD_MESSAGE_SESSION_STOP),
673 "SESSION_ID=%s", s->id,
674 "USER_ID=%s", s->user->name,
675 "LEADER="PID_FMT, s->leader,
676 "MESSAGE=Removed session %s.", s->id,
679 s->timer_event_source = sd_event_source_unref(s->timer_event_source);
681 /* Kill session devices */
682 while ((sd = hashmap_first(s->devices)))
683 session_device_free(sd);
685 unlink(s->state_file);
686 session_add_to_gc_queue(s);
687 user_add_to_gc_queue(s->user);
690 session_send_signal(s, false);
695 if (s->seat->active == s)
696 seat_set_active(s->seat, NULL);
699 seat_send_changed(s->seat, "Sessions", NULL);
703 user_send_changed(s->user, "Sessions", "Display", NULL);
708 static int release_timeout_callback(sd_event_source *es, uint64_t usec, void *userdata) {
709 Session *s = userdata;
714 session_stop(s, false);
718 void session_release(Session *s) {
721 if (!s->started || s->stopping)
724 if (!s->timer_event_source)
725 sd_event_add_time(s->manager->event,
726 &s->timer_event_source,
728 now(CLOCK_MONOTONIC) + RELEASE_USEC, 0,
729 release_timeout_callback, s);
732 bool session_is_active(Session *s) {
738 return s->seat->active == s;
741 static int get_tty_atime(const char *tty, usec_t *atime) {
742 _cleanup_free_ char *p = NULL;
748 if (!path_is_absolute(tty)) {
749 p = strappend("/dev/", tty);
754 } else if (!path_startswith(tty, "/dev/"))
757 if (lstat(tty, &st) < 0)
760 *atime = timespec_load(&st.st_atim);
764 static int get_process_ctty_atime(pid_t pid, usec_t *atime) {
765 _cleanup_free_ char *p = NULL;
771 r = get_ctty(pid, NULL, &p);
775 return get_tty_atime(p, atime);
778 int session_get_idle_hint(Session *s, dual_timestamp *t) {
784 /* Explicit idle hint is set */
787 *t = s->idle_hint_timestamp;
792 /* Graphical sessions should really implement a real
797 /* For sessions with an explicitly configured tty, let's check
800 r = get_tty_atime(s->tty, &atime);
805 /* For sessions with a leader but no explicitly configured
806 * tty, let's check the controlling tty of the leader */
808 r = get_process_ctty_atime(s->leader, &atime);
815 *t = s->idle_hint_timestamp;
821 dual_timestamp_from_realtime(t, atime);
823 n = now(CLOCK_REALTIME);
825 if (s->manager->idle_action_usec <= 0)
828 return atime + s->manager->idle_action_usec <= n;
831 void session_set_idle_hint(Session *s, bool b) {
834 if (s->idle_hint == b)
838 dual_timestamp_get(&s->idle_hint_timestamp);
840 session_send_changed(s, "IdleHint", "IdleSinceHint", "IdleSinceHintMonotonic", NULL);
843 seat_send_changed(s->seat, "IdleHint", "IdleSinceHint", "IdleSinceHintMonotonic", NULL);
845 user_send_changed(s->user, "IdleHint", "IdleSinceHint", "IdleSinceHintMonotonic", NULL);
846 manager_send_changed(s->manager, "IdleHint", "IdleSinceHint", "IdleSinceHintMonotonic", NULL);
849 static int session_dispatch_fifo(sd_event_source *es, int fd, uint32_t revents, void *userdata) {
850 Session *s = userdata;
853 assert(s->fifo_fd == fd);
855 /* EOF on the FIFO means the session died abnormally. */
857 session_remove_fifo(s);
858 session_stop(s, false);
863 int session_create_fifo(Session *s) {
870 r = mkdir_safe_label("/run/systemd/sessions", 0755, 0, 0);
874 if (asprintf(&s->fifo_path, "/run/systemd/sessions/%s.ref", s->id) < 0)
877 if (mkfifo(s->fifo_path, 0600) < 0 && errno != EEXIST)
881 /* Open reading side */
882 if (s->fifo_fd < 0) {
883 s->fifo_fd = open(s->fifo_path, O_RDONLY|O_CLOEXEC|O_NDELAY);
889 if (!s->fifo_event_source) {
890 r = sd_event_add_io(s->manager->event, &s->fifo_event_source, s->fifo_fd, 0, session_dispatch_fifo, s);
894 r = sd_event_source_set_priority(s->fifo_event_source, SD_EVENT_PRIORITY_IDLE);
899 /* Open writing side */
900 r = open(s->fifo_path, O_WRONLY|O_CLOEXEC|O_NDELAY);
907 static void session_remove_fifo(Session *s) {
910 s->fifo_event_source = sd_event_source_unref(s->fifo_event_source);
911 s->fifo_fd = safe_close(s->fifo_fd);
914 unlink(s->fifo_path);
920 bool session_check_gc(Session *s, bool drop_not_started) {
923 if (drop_not_started && !s->started)
929 if (s->fifo_fd >= 0) {
930 if (pipe_eof(s->fifo_fd) <= 0)
934 if (s->scope_job && manager_job_is_active(s->manager, s->scope_job))
937 if (s->scope && manager_unit_is_active(s->manager, s->scope))
943 void session_add_to_gc_queue(Session *s) {
949 LIST_PREPEND(gc_queue, s->manager->session_gc_queue, s);
950 s->in_gc_queue = true;
953 SessionState session_get_state(Session *s) {
956 /* always check closing first */
957 if (s->stopping || s->timer_event_source)
958 return SESSION_CLOSING;
960 if (s->scope_job || s->fifo_fd < 0)
961 return SESSION_OPENING;
963 if (session_is_active(s))
964 return SESSION_ACTIVE;
966 return SESSION_ONLINE;
969 int session_kill(Session *s, KillWho who, int signo) {
975 return manager_kill_unit(s->manager, s->scope, who, signo, NULL);
978 static int session_open_vt(Session *s) {
979 char path[sizeof("/dev/tty") + DECIMAL_STR_MAX(s->vtnr)];
987 sprintf(path, "/dev/tty%u", s->vtnr);
988 s->vtfd = open(path, O_RDWR | O_CLOEXEC | O_NONBLOCK | O_NOCTTY);
990 log_error("cannot open VT %s of session %s: %m", path, s->id);
997 static int session_vt_fn(sd_event_source *source, const struct signalfd_siginfo *si, void *data) {
1001 ioctl(s->vtfd, VT_RELDISP, 1);
1006 void session_prepare_vt(Session *s) {
1008 struct vt_mode mode = { 0 };
1011 vt = session_open_vt(s);
1015 r = fchown(vt, s->user->uid, -1);
1019 r = ioctl(vt, KDSKBMODE, K_OFF);
1023 r = ioctl(vt, KDSETMODE, KD_GRAPHICS);
1028 sigaddset(&mask, SIGUSR1);
1029 sigprocmask(SIG_BLOCK, &mask, NULL);
1031 r = sd_event_add_signal(s->manager->event, &s->vt_source, SIGUSR1, session_vt_fn, s);
1035 /* Oh, thanks to the VT layer, VT_AUTO does not work with KD_GRAPHICS.
1036 * So we need a dummy handler here which just acknowledges *all* VT
1037 * switch requests. */
1038 mode.mode = VT_PROCESS;
1039 mode.relsig = SIGUSR1;
1040 mode.acqsig = SIGUSR1;
1041 r = ioctl(vt, VT_SETMODE, &mode);
1048 log_error("cannot mute VT %u for session %s (%d/%d)", s->vtnr, s->id, r, errno);
1049 session_restore_vt(s);
1052 void session_restore_vt(Session *s) {
1053 _cleanup_free_ char *utf8 = NULL;
1054 int vt, kb = K_XLATE;
1055 struct vt_mode mode = { 0 };
1057 vt = session_open_vt(s);
1061 s->vt_source = sd_event_source_unref(s->vt_source);
1063 ioctl(vt, KDSETMODE, KD_TEXT);
1065 if (read_one_line_file("/sys/module/vt/parameters/default_utf8", &utf8) >= 0 && *utf8 == '1')
1068 ioctl(vt, KDSKBMODE, kb);
1070 mode.mode = VT_AUTO;
1071 ioctl(vt, VT_SETMODE, &mode);
1075 s->vtfd = safe_close(s->vtfd);
1078 bool session_is_controller(Session *s, const char *sender) {
1081 return streq_ptr(s->controller, sender);
1084 static void session_swap_controller(Session *s, char *name) {
1087 if (s->controller) {
1088 manager_drop_busname(s->manager, s->controller);
1089 free(s->controller);
1090 s->controller = NULL;
1092 /* Drop all devices as they're now unused. Do that after the
1093 * controller is released to avoid sending out useles
1095 while ((sd = hashmap_first(s->devices)))
1096 session_device_free(sd);
1099 session_restore_vt(s);
1102 s->controller = name;
1106 int session_set_controller(Session *s, const char *sender, bool force) {
1113 if (session_is_controller(s, sender))
1115 if (s->controller && !force)
1122 r = manager_watch_busname(s->manager, sender);
1128 session_swap_controller(s, t);
1130 /* When setting a session controller, we forcibly mute the VT and set
1131 * it into graphics-mode. Applications can override that by changing
1132 * VT state after calling TakeControl(). However, this serves as a good
1133 * default and well-behaving controllers can now ignore VTs entirely.
1134 * Note that we reset the VT on ReleaseControl() and if the controller
1136 * If logind crashes/restarts, we restore the controller during restart
1137 * or reset the VT in case it crashed/exited, too. */
1138 session_prepare_vt(s);
1143 void session_drop_controller(Session *s) {
1149 session_swap_controller(s, NULL);
1152 static const char* const session_state_table[_SESSION_STATE_MAX] = {
1153 [SESSION_OPENING] = "opening",
1154 [SESSION_ONLINE] = "online",
1155 [SESSION_ACTIVE] = "active",
1156 [SESSION_CLOSING] = "closing"
1159 DEFINE_STRING_TABLE_LOOKUP(session_state, SessionState);
1161 static const char* const session_type_table[_SESSION_TYPE_MAX] = {
1162 [SESSION_UNSPECIFIED] = "unspecified",
1163 [SESSION_TTY] = "tty",
1164 [SESSION_X11] = "x11",
1165 [SESSION_WAYLAND] = "wayland",
1166 [SESSION_MIR] = "mir",
1169 DEFINE_STRING_TABLE_LOOKUP(session_type, SessionType);
1171 static const char* const session_class_table[_SESSION_CLASS_MAX] = {
1172 [SESSION_USER] = "user",
1173 [SESSION_GREETER] = "greeter",
1174 [SESSION_LOCK_SCREEN] = "lock-screen",
1175 [SESSION_BACKGROUND] = "background"
1178 DEFINE_STRING_TABLE_LOOKUP(session_class, SessionClass);
1180 static const char* const kill_who_table[_KILL_WHO_MAX] = {
1181 [KILL_LEADER] = "leader",
1185 DEFINE_STRING_TABLE_LOOKUP(kill_who, KillWho);