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 Session* session_new(Manager *m, const char *id) {
52 assert(session_id_valid(id));
58 s->state_file = strappend("/run/systemd/sessions/", id);
64 s->devices = hashmap_new(devt_hash_func, devt_compare_func);
71 s->id = basename(s->state_file);
73 if (hashmap_put(m->sessions, s->id, s) < 0) {
74 hashmap_free(s->devices);
87 void session_free(Session *s) {
93 LIST_REMOVE(gc_queue, s->manager->session_gc_queue, s);
95 s->timer_event_source = sd_event_source_unref(s->timer_event_source);
97 session_remove_fifo(s);
99 session_drop_controller(s);
101 while ((sd = hashmap_first(s->devices)))
102 session_device_free(sd);
104 hashmap_free(s->devices);
107 LIST_REMOVE(sessions_by_user, s->user->sessions, s);
109 if (s->user->display == s)
110 s->user->display = NULL;
114 if (s->seat->active == s)
115 s->seat->active = NULL;
116 if (s->seat->pending_switch == s)
117 s->seat->pending_switch = NULL;
119 seat_evict_position(s->seat, s);
120 LIST_REMOVE(sessions_by_seat, s->seat->sessions, s);
124 hashmap_remove(s->manager->session_units, s->scope);
130 sd_bus_message_unref(s->create_message);
134 free(s->remote_host);
135 free(s->remote_user);
139 hashmap_remove(s->manager->sessions, s->id);
145 void session_set_user(Session *s, User *u) {
150 LIST_PREPEND(sessions_by_user, u->sessions, s);
153 int session_save(Session *s) {
154 _cleanup_free_ char *temp_path = NULL;
155 _cleanup_fclose_ FILE *f = NULL;
166 r = mkdir_safe_label("/run/systemd/sessions", 0755, 0, 0);
170 r = fopen_temporary(s->state_file, &f, &temp_path);
176 fchmod(fileno(f), 0644);
179 "# This is private data. Do not parse.\n"
187 session_is_active(s),
188 session_state_to_string(session_get_state(s)),
192 fprintf(f, "TYPE=%s\n", session_type_to_string(s->type));
195 fprintf(f, "CLASS=%s\n", session_class_to_string(s->class));
198 fprintf(f, "SCOPE=%s\n", s->scope);
200 fprintf(f, "SCOPE_JOB=%s\n", s->scope_job);
203 fprintf(f, "FIFO=%s\n", s->fifo_path);
206 fprintf(f, "SEAT=%s\n", s->seat->id);
209 fprintf(f, "TTY=%s\n", s->tty);
212 fprintf(f, "DISPLAY=%s\n", s->display);
214 if (s->remote_host) {
215 _cleanup_free_ char *escaped;
217 escaped = cescape(s->remote_host);
223 fprintf(f, "REMOTE_HOST=%s\n", escaped);
226 if (s->remote_user) {
227 _cleanup_free_ char *escaped;
229 escaped = cescape(s->remote_user);
235 fprintf(f, "REMOTE_USER=%s\n", escaped);
239 _cleanup_free_ char *escaped;
241 escaped = cescape(s->service);
247 fprintf(f, "SERVICE=%s\n", escaped);
251 _cleanup_free_ char *escaped;
254 escaped = cescape(s->desktop);
260 fprintf(f, "DESKTOP=%s\n", escaped);
263 if (s->seat && seat_has_vts(s->seat))
264 fprintf(f, "VTNR=%u\n", s->vtnr);
267 fprintf(f, "POS=%u\n", s->pos);
270 fprintf(f, "LEADER="PID_FMT"\n", s->leader);
273 fprintf(f, "AUDIT=%"PRIu32"\n", s->audit_id);
275 if (dual_timestamp_is_set(&s->timestamp))
277 "REALTIME="USEC_FMT"\n"
278 "MONOTONIC="USEC_FMT"\n",
279 s->timestamp.realtime,
280 s->timestamp.monotonic);
283 fprintf(f, "CONTROLLER=%s\n", s->controller);
287 if (ferror(f) || rename(temp_path, s->state_file) < 0) {
289 unlink(s->state_file);
295 log_error("Failed to save session data %s: %s", s->state_file, strerror(-r));
300 int session_load(Session *s) {
301 _cleanup_free_ char *remote = NULL,
317 r = parse_env_file(s->state_file, NEWLINE,
320 "SCOPE_JOB", &s->scope_job,
321 "FIFO", &s->fifo_path,
324 "DISPLAY", &s->display,
325 "REMOTE_HOST", &s->remote_host,
326 "REMOTE_USER", &s->remote_user,
327 "SERVICE", &s->service,
328 "DESKTOP", &s->desktop,
335 "REALTIME", &realtime,
336 "MONOTONIC", &monotonic,
337 "CONTROLLER", &controller,
341 log_error("Failed to read %s: %s", s->state_file, strerror(-r));
350 log_error("UID not specified for session %s", s->id);
354 r = parse_uid(uid, &u);
356 log_error("Failed to parse UID value %s for session %s.", uid, s->id);
360 user = hashmap_get(s->manager->users, ULONG_TO_PTR((unsigned long) u));
362 log_error("User of session %s not known.", s->id);
366 session_set_user(s, user);
370 k = parse_boolean(remote);
376 safe_atou(vtnr, &s->vtnr);
378 if (seat && !s->seat) {
381 o = hashmap_get(s->manager->seats, seat);
383 r = seat_attach_session(o, s);
385 log_error("Cannot attach session %s to seat %s", s->id, seat);
388 if (!s->seat || !seat_has_vts(s->seat))
391 if (pos && s->seat) {
394 safe_atou(pos, &npos);
395 seat_claim_position(s->seat, s, npos);
399 k = parse_pid(leader, &s->leader);
401 audit_session_from_pid(s->leader, &s->audit_id);
407 t = session_type_from_string(type);
415 c = session_class_from_string(class);
423 /* If we open an unopened pipe for reading we will not
424 get an EOF. to trigger an EOF we hence open it for
425 reading, but close it right-away which then will
428 fd = session_create_fifo(s);
433 unsigned long long l;
434 if (sscanf(realtime, "%llu", &l) > 0)
435 s->timestamp.realtime = l;
439 unsigned long long l;
440 if (sscanf(monotonic, "%llu", &l) > 0)
441 s->timestamp.monotonic = l;
445 if (bus_name_has_owner(s->manager->bus, controller, NULL) > 0)
446 session_set_controller(s, controller, false);
448 session_restore_vt(s);
454 int session_activate(Session *s) {
455 unsigned int num_pending;
463 if (s->seat->active == s)
466 /* on seats with VTs, we let VTs manage session-switching */
467 if (seat_has_vts(s->seat)) {
471 return chvt(s->vtnr);
474 /* On seats without VTs, we implement session-switching in logind. We
475 * try to pause all session-devices and wait until the session
476 * controller acknowledged them. Once all devices are asleep, we simply
477 * switch the active session and be done.
478 * We save the session we want to switch to in seat->pending_switch and
479 * seat_complete_switch() will perform the final switch. */
481 s->seat->pending_switch = s;
483 /* if no devices are running, immediately perform the session switch */
484 num_pending = session_device_try_pause_all(s);
486 seat_complete_switch(s->seat);
491 static int session_start_scope(Session *s) {
496 assert(s->user->slice);
499 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
500 _cleanup_free_ char *description = NULL;
501 char *scope, *job = NULL;
503 description = strjoin("Session ", s->id, " of user ", s->user->name, NULL);
507 scope = strjoin("session-", s->id, ".scope", NULL);
511 r = manager_start_scope(s->manager, scope, s->leader, s->user->slice, description, "systemd-logind.service", "systemd-user-sessions.service", &error, &job);
513 log_error("Failed to start session scope %s: %s %s",
514 scope, bus_error_message(&error, r), error.name);
526 hashmap_put(s->manager->session_units, s->scope, s);
531 int session_start(Session *s) {
542 r = user_start(s->user);
547 r = session_start_scope(s);
551 log_struct(s->class == SESSION_BACKGROUND ? LOG_DEBUG : LOG_INFO,
552 MESSAGE_ID(SD_MESSAGE_SESSION_START),
553 "SESSION_ID=%s", s->id,
554 "USER_ID=%s", s->user->name,
555 "LEADER="PID_FMT, s->leader,
556 "MESSAGE=New session %s of user %s.", s->id, s->user->name,
559 if (!dual_timestamp_is_set(&s->timestamp))
560 dual_timestamp_get(&s->timestamp);
563 seat_read_active_vt(s->seat);
567 user_elect_display(s->user);
576 session_send_signal(s, true);
577 user_send_changed(s->user, "Sessions", "Display", NULL);
579 if (s->seat->active == s)
580 seat_send_changed(s->seat, "Sessions", "ActiveSession", NULL);
582 seat_send_changed(s->seat, "Sessions", NULL);
588 static int session_stop_scope(Session *s, bool force) {
589 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
598 if (force || manager_shall_kill(s->manager, s->user->name)) {
599 r = manager_stop_unit(s->manager, s->scope, &error, &job);
601 log_error("Failed to stop session scope: %s", bus_error_message(&error, r));
608 r = manager_abandon_scope(s->manager, s->scope, &error);
610 log_error("Failed to abandon session scope: %s", bus_error_message(&error, r));
618 int session_stop(Session *s, bool force) {
626 s->timer_event_source = sd_event_source_unref(s->timer_event_source);
628 /* We are going down, don't care about FIFOs anymore */
629 session_remove_fifo(s);
632 r = session_stop_scope(s, force);
636 user_elect_display(s->user);
644 int session_finalize(Session *s) {
654 log_struct(s->class == SESSION_BACKGROUND ? LOG_DEBUG : LOG_INFO,
655 MESSAGE_ID(SD_MESSAGE_SESSION_STOP),
656 "SESSION_ID=%s", s->id,
657 "USER_ID=%s", s->user->name,
658 "LEADER="PID_FMT, s->leader,
659 "MESSAGE=Removed session %s.", s->id,
662 s->timer_event_source = sd_event_source_unref(s->timer_event_source);
664 /* Kill session devices */
665 while ((sd = hashmap_first(s->devices)))
666 session_device_free(sd);
668 unlink(s->state_file);
669 session_add_to_gc_queue(s);
670 user_add_to_gc_queue(s->user);
673 session_send_signal(s, false);
678 if (s->seat->active == s)
679 seat_set_active(s->seat, NULL);
682 seat_send_changed(s->seat, "Sessions", NULL);
686 user_send_changed(s->user, "Sessions", "Display", NULL);
691 static int release_timeout_callback(sd_event_source *es, uint64_t usec, void *userdata) {
692 Session *s = userdata;
697 session_stop(s, false);
701 void session_release(Session *s) {
704 if (!s->started || s->stopping)
707 if (!s->timer_event_source)
708 sd_event_add_time(s->manager->event,
709 &s->timer_event_source,
711 now(CLOCK_MONOTONIC) + RELEASE_USEC, 0,
712 release_timeout_callback, s);
715 bool session_is_active(Session *s) {
721 return s->seat->active == s;
724 static int get_tty_atime(const char *tty, usec_t *atime) {
725 _cleanup_free_ char *p = NULL;
731 if (!path_is_absolute(tty)) {
732 p = strappend("/dev/", tty);
737 } else if (!path_startswith(tty, "/dev/"))
740 if (lstat(tty, &st) < 0)
743 *atime = timespec_load(&st.st_atim);
747 static int get_process_ctty_atime(pid_t pid, usec_t *atime) {
748 _cleanup_free_ char *p = NULL;
754 r = get_ctty(pid, NULL, &p);
758 return get_tty_atime(p, atime);
761 int session_get_idle_hint(Session *s, dual_timestamp *t) {
767 /* Explicit idle hint is set */
770 *t = s->idle_hint_timestamp;
775 /* Graphical sessions should really implement a real
780 /* For sessions with an explicitly configured tty, let's check
783 r = get_tty_atime(s->tty, &atime);
788 /* For sessions with a leader but no explicitly configured
789 * tty, let's check the controlling tty of the leader */
791 r = get_process_ctty_atime(s->leader, &atime);
798 *t = s->idle_hint_timestamp;
804 dual_timestamp_from_realtime(t, atime);
806 n = now(CLOCK_REALTIME);
808 if (s->manager->idle_action_usec <= 0)
811 return atime + s->manager->idle_action_usec <= n;
814 void session_set_idle_hint(Session *s, bool b) {
817 if (s->idle_hint == b)
821 dual_timestamp_get(&s->idle_hint_timestamp);
823 session_send_changed(s, "IdleHint", "IdleSinceHint", "IdleSinceHintMonotonic", NULL);
826 seat_send_changed(s->seat, "IdleHint", "IdleSinceHint", "IdleSinceHintMonotonic", NULL);
828 user_send_changed(s->user, "IdleHint", "IdleSinceHint", "IdleSinceHintMonotonic", NULL);
829 manager_send_changed(s->manager, "IdleHint", "IdleSinceHint", "IdleSinceHintMonotonic", NULL);
832 static int session_dispatch_fifo(sd_event_source *es, int fd, uint32_t revents, void *userdata) {
833 Session *s = userdata;
836 assert(s->fifo_fd == fd);
838 /* EOF on the FIFO means the session died abnormally. */
840 session_remove_fifo(s);
841 session_stop(s, false);
846 int session_create_fifo(Session *s) {
853 r = mkdir_safe_label("/run/systemd/sessions", 0755, 0, 0);
857 if (asprintf(&s->fifo_path, "/run/systemd/sessions/%s.ref", s->id) < 0)
860 if (mkfifo(s->fifo_path, 0600) < 0 && errno != EEXIST)
864 /* Open reading side */
865 if (s->fifo_fd < 0) {
866 s->fifo_fd = open(s->fifo_path, O_RDONLY|O_CLOEXEC|O_NDELAY);
872 if (!s->fifo_event_source) {
873 r = sd_event_add_io(s->manager->event, &s->fifo_event_source, s->fifo_fd, 0, session_dispatch_fifo, s);
877 r = sd_event_source_set_priority(s->fifo_event_source, SD_EVENT_PRIORITY_IDLE);
882 /* Open writing side */
883 r = open(s->fifo_path, O_WRONLY|O_CLOEXEC|O_NDELAY);
890 static void session_remove_fifo(Session *s) {
893 s->fifo_event_source = sd_event_source_unref(s->fifo_event_source);
894 s->fifo_fd = safe_close(s->fifo_fd);
897 unlink(s->fifo_path);
903 bool session_check_gc(Session *s, bool drop_not_started) {
906 if (drop_not_started && !s->started)
912 if (s->fifo_fd >= 0) {
913 if (pipe_eof(s->fifo_fd) <= 0)
917 if (s->scope_job && manager_job_is_active(s->manager, s->scope_job))
920 if (s->scope && manager_unit_is_active(s->manager, s->scope))
926 void session_add_to_gc_queue(Session *s) {
932 LIST_PREPEND(gc_queue, s->manager->session_gc_queue, s);
933 s->in_gc_queue = true;
936 SessionState session_get_state(Session *s) {
939 /* always check closing first */
940 if (s->stopping || s->timer_event_source)
941 return SESSION_CLOSING;
943 if (s->scope_job || s->fifo_fd < 0)
944 return SESSION_OPENING;
946 if (session_is_active(s))
947 return SESSION_ACTIVE;
949 return SESSION_ONLINE;
952 int session_kill(Session *s, KillWho who, int signo) {
958 return manager_kill_unit(s->manager, s->scope, who, signo, NULL);
961 static int session_open_vt(Session *s) {
962 char path[sizeof("/dev/tty") + DECIMAL_STR_MAX(s->vtnr)];
970 sprintf(path, "/dev/tty%u", s->vtnr);
971 s->vtfd = open(path, O_RDWR | O_CLOEXEC | O_NONBLOCK | O_NOCTTY);
973 log_error("cannot open VT %s of session %s: %m", path, s->id);
980 int session_prepare_vt(Session *s) {
982 struct vt_mode mode = { 0 };
987 vt = session_open_vt(s);
991 r = fchown(vt, s->user->uid, -1);
994 log_error("Cannot change owner of /dev/tty%u: %m", s->vtnr);
998 r = ioctl(vt, KDSKBMODE, K_OFF);
1001 log_error("Cannot set K_OFF on /dev/tty%u: %m", s->vtnr);
1005 r = ioctl(vt, KDSETMODE, KD_GRAPHICS);
1008 log_error("Cannot set KD_GRAPHICS on /dev/tty%u: %m", s->vtnr);
1012 /* Oh, thanks to the VT layer, VT_AUTO does not work with KD_GRAPHICS.
1013 * So we need a dummy handler here which just acknowledges *all* VT
1014 * switch requests. */
1015 mode.mode = VT_PROCESS;
1016 mode.relsig = SIGRTMIN;
1017 mode.acqsig = SIGRTMIN + 1;
1018 r = ioctl(vt, VT_SETMODE, &mode);
1021 log_error("Cannot set VT_PROCESS on /dev/tty%u: %m", s->vtnr);
1028 session_restore_vt(s);
1032 void session_restore_vt(Session *s) {
1033 _cleanup_free_ char *utf8 = NULL;
1034 int vt, kb = K_XLATE;
1035 struct vt_mode mode = { 0 };
1037 vt = session_open_vt(s);
1041 ioctl(vt, KDSETMODE, KD_TEXT);
1043 if (read_one_line_file("/sys/module/vt/parameters/default_utf8", &utf8) >= 0 && *utf8 == '1')
1046 ioctl(vt, KDSKBMODE, kb);
1048 mode.mode = VT_AUTO;
1049 ioctl(vt, VT_SETMODE, &mode);
1053 s->vtfd = safe_close(s->vtfd);
1056 bool session_is_controller(Session *s, const char *sender) {
1059 return streq_ptr(s->controller, sender);
1062 static void session_swap_controller(Session *s, char *name) {
1065 if (s->controller) {
1066 manager_drop_busname(s->manager, s->controller);
1067 free(s->controller);
1068 s->controller = NULL;
1070 /* Drop all devices as they're now unused. Do that after the
1071 * controller is released to avoid sending out useles
1073 while ((sd = hashmap_first(s->devices)))
1074 session_device_free(sd);
1077 session_restore_vt(s);
1080 s->controller = name;
1084 int session_set_controller(Session *s, const char *sender, bool force) {
1091 if (session_is_controller(s, sender))
1093 if (s->controller && !force)
1100 r = manager_watch_busname(s->manager, sender);
1106 /* When setting a session controller, we forcibly mute the VT and set
1107 * it into graphics-mode. Applications can override that by changing
1108 * VT state after calling TakeControl(). However, this serves as a good
1109 * default and well-behaving controllers can now ignore VTs entirely.
1110 * Note that we reset the VT on ReleaseControl() and if the controller
1112 * If logind crashes/restarts, we restore the controller during restart
1113 * or reset the VT in case it crashed/exited, too. */
1114 r = session_prepare_vt(s);
1118 session_swap_controller(s, t);
1123 void session_drop_controller(Session *s) {
1129 session_swap_controller(s, NULL);
1132 static const char* const session_state_table[_SESSION_STATE_MAX] = {
1133 [SESSION_OPENING] = "opening",
1134 [SESSION_ONLINE] = "online",
1135 [SESSION_ACTIVE] = "active",
1136 [SESSION_CLOSING] = "closing"
1139 DEFINE_STRING_TABLE_LOOKUP(session_state, SessionState);
1141 static const char* const session_type_table[_SESSION_TYPE_MAX] = {
1142 [SESSION_UNSPECIFIED] = "unspecified",
1143 [SESSION_TTY] = "tty",
1144 [SESSION_X11] = "x11",
1145 [SESSION_WAYLAND] = "wayland",
1146 [SESSION_MIR] = "mir",
1147 [SESSION_WEB] = "web",
1150 DEFINE_STRING_TABLE_LOOKUP(session_type, SessionType);
1152 static const char* const session_class_table[_SESSION_CLASS_MAX] = {
1153 [SESSION_USER] = "user",
1154 [SESSION_GREETER] = "greeter",
1155 [SESSION_LOCK_SCREEN] = "lock-screen",
1156 [SESSION_BACKGROUND] = "background"
1159 DEFINE_STRING_TABLE_LOOKUP(session_class, SessionClass);
1161 static const char* const kill_who_table[_KILL_WHO_MAX] = {
1162 [KILL_LEADER] = "leader",
1166 DEFINE_STRING_TABLE_LOOKUP(kill_who, KillWho);