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 "sd-messages.h"
32 #include "path-util.h"
36 #include "bus-error.h"
37 #include "logind-session.h"
39 static unsigned devt_hash_func(const void *p) {
40 uint64_t u = *(const dev_t*)p;
42 return uint64_hash_func(&u);
45 static int devt_compare_func(const void *_a, const void *_b) {
48 a = *(const dev_t*) _a;
49 b = *(const dev_t*) _b;
51 return a < b ? -1 : (a > b ? 1 : 0);
54 Session* session_new(Manager *m, const char *id) {
59 assert(session_id_valid(id));
65 s->state_file = strappend("/run/systemd/sessions/", id);
71 s->devices = hashmap_new(devt_hash_func, devt_compare_func);
78 s->id = path_get_file_name(s->state_file);
80 if (hashmap_put(m->sessions, s->id, s) < 0) {
81 hashmap_free(s->devices);
93 void session_free(Session *s) {
99 LIST_REMOVE(gc_queue, s->manager->session_gc_queue, s);
101 session_remove_fifo(s);
103 session_drop_controller(s);
105 while ((sd = hashmap_first(s->devices)))
106 session_device_free(sd);
108 hashmap_free(s->devices);
111 LIST_REMOVE(sessions_by_user, s->user->sessions, s);
113 if (s->user->display == s)
114 s->user->display = NULL;
118 if (s->seat->active == s)
119 s->seat->active = NULL;
120 if (s->seat->pending_switch == s)
121 s->seat->pending_switch = NULL;
123 LIST_REMOVE(sessions_by_seat, s->seat->sessions, s);
127 hashmap_remove(s->manager->session_units, s->scope);
133 sd_bus_message_unref(s->create_message);
137 free(s->remote_host);
138 free(s->remote_user);
141 hashmap_remove(s->manager->sessions, s->id);
147 void session_set_user(Session *s, User *u) {
152 LIST_PREPEND(sessions_by_user, u->sessions, s);
155 int session_save(Session *s) {
156 _cleanup_free_ char *temp_path = NULL;
157 _cleanup_fclose_ FILE *f = NULL;
168 r = mkdir_safe_label("/run/systemd/sessions", 0755, 0, 0);
172 r = fopen_temporary(s->state_file, &f, &temp_path);
178 fchmod(fileno(f), 0644);
181 "# This is private data. Do not parse.\n"
187 (unsigned long) s->user->uid,
189 session_is_active(s),
190 session_state_to_string(session_get_state(s)),
194 fprintf(f, "TYPE=%s\n", session_type_to_string(s->type));
197 fprintf(f, "CLASS=%s\n", session_class_to_string(s->class));
200 fprintf(f, "SCOPE=%s\n", s->scope);
203 fprintf(f, "SCOPE_JOB=%s\n", s->scope_job);
206 fprintf(f, "FIFO=%s\n", s->fifo_path);
209 fprintf(f, "SEAT=%s\n", s->seat->id);
212 fprintf(f, "TTY=%s\n", s->tty);
215 fprintf(f, "DISPLAY=%s\n", s->display);
218 fprintf(f, "REMOTE_HOST=%s\n", s->remote_host);
221 fprintf(f, "REMOTE_USER=%s\n", s->remote_user);
224 fprintf(f, "SERVICE=%s\n", s->service);
226 if (s->seat && seat_has_vts(s->seat))
227 fprintf(f, "VTNR=%i\n", s->vtnr);
230 fprintf(f, "LEADER=%lu\n", (unsigned long) s->leader);
233 fprintf(f, "AUDIT=%"PRIu32"\n", s->audit_id);
235 if (dual_timestamp_is_set(&s->timestamp))
239 (unsigned long long) s->timestamp.realtime,
240 (unsigned long long) s->timestamp.monotonic);
244 if (ferror(f) || rename(temp_path, s->state_file) < 0) {
246 unlink(s->state_file);
252 log_error("Failed to save session data for %s: %s", s->id, strerror(-r));
257 int session_load(Session *s) {
258 _cleanup_free_ char *remote = NULL,
272 r = parse_env_file(s->state_file, NEWLINE,
275 "SCOPE_JOB", &s->scope_job,
276 "FIFO", &s->fifo_path,
279 "DISPLAY", &s->display,
280 "REMOTE_HOST", &s->remote_host,
281 "REMOTE_USER", &s->remote_user,
282 "SERVICE", &s->service,
288 "REALTIME", &realtime,
289 "MONOTONIC", &monotonic,
293 log_error("Failed to read %s: %s", s->state_file, strerror(-r));
302 log_error("UID not specified for session %s", s->id);
306 r = parse_uid(uid, &u);
308 log_error("Failed to parse UID value %s for session %s.", uid, s->id);
312 user = hashmap_get(s->manager->users, ULONG_TO_PTR((unsigned long) u));
314 log_error("User of session %s not known.", s->id);
318 session_set_user(s, user);
322 k = parse_boolean(remote);
327 if (seat && !s->seat) {
330 o = hashmap_get(s->manager->seats, seat);
332 seat_attach_session(o, s);
335 if (vtnr && s->seat && seat_has_vts(s->seat)) {
338 k = safe_atoi(vtnr, &v);
339 if (k >= 0 && v >= 1)
344 k = parse_pid(leader, &s->leader);
346 audit_session_from_pid(s->leader, &s->audit_id);
352 t = session_type_from_string(type);
360 c = session_class_from_string(class);
368 /* If we open an unopened pipe for reading we will not
369 get an EOF. to trigger an EOF we hence open it for
370 reading, but close it right-away which then will
373 fd = session_create_fifo(s);
375 close_nointr_nofail(fd);
379 unsigned long long l;
380 if (sscanf(realtime, "%llu", &l) > 0)
381 s->timestamp.realtime = l;
385 unsigned long long l;
386 if (sscanf(monotonic, "%llu", &l) > 0)
387 s->timestamp.monotonic = l;
393 int session_activate(Session *s) {
394 unsigned int num_pending;
402 if (s->seat->active == s)
405 /* on seats with VTs, we let VTs manage session-switching */
406 if (seat_has_vts(s->seat)) {
410 return chvt(s->vtnr);
413 /* On seats without VTs, we implement session-switching in logind. We
414 * try to pause all session-devices and wait until the session
415 * controller acknowledged them. Once all devices are asleep, we simply
416 * switch the active session and be done.
417 * We save the session we want to switch to in seat->pending_switch and
418 * seat_complete_switch() will perform the final switch. */
420 s->seat->pending_switch = s;
422 /* if no devices are running, immediately perform the session switch */
423 num_pending = session_device_try_pause_all(s);
425 seat_complete_switch(s->seat);
430 static int session_link_x11_socket(Session *s) {
431 _cleanup_free_ char *t = NULL, *f = NULL;
437 assert(s->user->runtime_path);
439 if (s->user->display)
442 if (!s->display || !display_is_local(s->display))
445 k = strspn(s->display+1, "0123456789");
446 f = new(char, sizeof("/tmp/.X11-unix/X") + k);
450 c = stpcpy(f, "/tmp/.X11-unix/X");
451 memcpy(c, s->display+1, k);
454 if (access(f, F_OK) < 0) {
455 log_warning("Session %s has display %s with non-existing socket %s.", s->id, s->display, f);
459 /* Note that this cannot be in a subdir to avoid
460 * vulnerabilities since we are privileged but the runtime
461 * path is owned by the user */
463 t = strappend(s->user->runtime_path, "/X11-display");
467 if (link(f, t) < 0) {
468 if (errno == EEXIST) {
475 if (symlink(f, t) < 0) {
477 if (errno == EEXIST) {
480 if (symlink(f, t) >= 0)
484 log_error("Failed to link %s to %s: %m", f, t);
490 log_info("Linked %s to %s.", f, t);
491 s->user->display = s;
496 static int session_start_scope(Session *s) {
501 assert(s->user->slice);
504 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
505 _cleanup_free_ char *description = NULL;
506 const char *kill_mode;
509 description = strjoin("Session ", s->id, " of user ", s->user->name, NULL);
513 scope = strjoin("session-", s->id, ".scope", NULL);
517 kill_mode = manager_shall_kill(s->manager, s->user->name) ? "control-group" : "none";
519 r = manager_start_scope(s->manager, scope, s->leader, s->user->slice, description, "systemd-user-sessions.service", kill_mode, &error, &job);
521 log_error("Failed to start session scope %s: %s %s",
522 scope, bus_error_message(&error, r), error.name);
534 hashmap_put(s->manager->session_units, s->scope, s);
539 int session_start(Session *s) {
550 r = user_start(s->user);
555 r = session_start_scope(s);
559 log_struct(s->type == SESSION_TTY || s->type == SESSION_X11 ? LOG_INFO : LOG_DEBUG,
560 MESSAGE_ID(SD_MESSAGE_SESSION_START),
561 "SESSION_ID=%s", s->id,
562 "USER_ID=%s", s->user->name,
563 "LEADER=%lu", (unsigned long) s->leader,
564 "MESSAGE=New session %s of user %s.", s->id, s->user->name,
567 /* Create X11 symlink */
568 session_link_x11_socket(s);
570 if (!dual_timestamp_is_set(&s->timestamp))
571 dual_timestamp_get(&s->timestamp);
574 seat_read_active_vt(s->seat);
578 /* Save session data */
582 session_send_signal(s, true);
587 if (s->seat->active == s)
588 seat_send_changed(s->seat, "Sessions", "ActiveSession", NULL);
590 seat_send_changed(s->seat, "Sessions", NULL);
593 user_send_changed(s->user, "Sessions", NULL);
598 static int session_stop_scope(Session *s) {
599 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
608 r = manager_stop_unit(s->manager, s->scope, &error, &job);
610 log_error("Failed to stop session scope: %s", bus_error_message(&error, r));
620 static int session_unlink_x11_socket(Session *s) {
621 _cleanup_free_ char *t = NULL;
627 if (s->user->display != s)
630 s->user->display = NULL;
632 t = strappend(s->user->runtime_path, "/X11-display");
637 return r < 0 ? -errno : 0;
640 int session_stop(Session *s) {
649 r = session_stop_scope(s);
657 int session_finalize(Session *s) {
667 log_struct(s->type == SESSION_TTY || s->type == SESSION_X11 ? LOG_INFO : LOG_DEBUG,
668 MESSAGE_ID(SD_MESSAGE_SESSION_STOP),
669 "SESSION_ID=%s", s->id,
670 "USER_ID=%s", s->user->name,
671 "LEADER=%lu", (unsigned long) s->leader,
672 "MESSAGE=Removed session %s.", s->id,
675 /* Kill session devices */
676 while ((sd = hashmap_first(s->devices)))
677 session_device_free(sd);
679 /* Remove X11 symlink */
680 session_unlink_x11_socket(s);
682 unlink(s->state_file);
683 session_add_to_gc_queue(s);
684 user_add_to_gc_queue(s->user);
687 session_send_signal(s, false);
692 if (s->seat->active == s)
693 seat_set_active(s->seat, NULL);
695 seat_send_changed(s->seat, "Sessions", NULL);
699 user_send_changed(s->user, "Sessions", NULL);
705 bool session_is_active(Session *s) {
711 return s->seat->active == s;
714 static int get_tty_atime(const char *tty, usec_t *atime) {
715 _cleanup_free_ char *p = NULL;
721 if (!path_is_absolute(tty)) {
722 p = strappend("/dev/", tty);
727 } else if (!path_startswith(tty, "/dev/"))
730 if (lstat(tty, &st) < 0)
733 *atime = timespec_load(&st.st_atim);
737 static int get_process_ctty_atime(pid_t pid, usec_t *atime) {
738 _cleanup_free_ char *p = NULL;
744 r = get_ctty(pid, NULL, &p);
748 return get_tty_atime(p, atime);
751 int session_get_idle_hint(Session *s, dual_timestamp *t) {
757 /* Explicit idle hint is set */
760 *t = s->idle_hint_timestamp;
765 /* Graphical sessions should really implement a real
770 /* For sessions with an explicitly configured tty, let's check
773 r = get_tty_atime(s->tty, &atime);
778 /* For sessions with a leader but no explicitly configured
779 * tty, let's check the controlling tty of the leader */
781 r = get_process_ctty_atime(s->leader, &atime);
788 *t = s->idle_hint_timestamp;
794 dual_timestamp_from_realtime(t, atime);
796 n = now(CLOCK_REALTIME);
798 if (s->manager->idle_action_usec <= 0)
801 return atime + s->manager->idle_action_usec <= n;
804 void session_set_idle_hint(Session *s, bool b) {
807 if (s->idle_hint == b)
811 dual_timestamp_get(&s->idle_hint_timestamp);
813 session_send_changed(s, "IdleHint", "IdleSinceHint", "IdleSinceHintMonotonic", NULL);
816 seat_send_changed(s->seat, "IdleHint", "IdleSinceHint", "IdleSinceHintMonotonic", NULL);
818 user_send_changed(s->user, "IdleHint", "IdleSinceHint", "IdleSinceHintMonotonic", NULL);
819 manager_send_changed(s->manager, "IdleHint", "IdleSinceHint", "IdleSinceHintMonotonic", NULL);
822 static int session_dispatch_fifo(sd_event_source *es, int fd, uint32_t revents, void *userdata) {
823 Session *s = userdata;
826 assert(s->fifo_fd == fd);
828 /* EOF on the FIFO means the session died abnormally. */
830 session_remove_fifo(s);
836 int session_create_fifo(Session *s) {
843 r = mkdir_safe_label("/run/systemd/sessions", 0755, 0, 0);
847 if (asprintf(&s->fifo_path, "/run/systemd/sessions/%s.ref", s->id) < 0)
850 if (mkfifo(s->fifo_path, 0600) < 0 && errno != EEXIST)
854 /* Open reading side */
855 if (s->fifo_fd < 0) {
856 s->fifo_fd = open(s->fifo_path, O_RDONLY|O_CLOEXEC|O_NDELAY);
862 if (!s->fifo_event_source) {
863 r = sd_event_add_io(s->manager->event, s->fifo_fd, 0, session_dispatch_fifo, s, &s->fifo_event_source);
867 r = sd_event_source_set_priority(s->fifo_event_source, SD_EVENT_PRIORITY_IDLE);
872 /* Open writing side */
873 r = open(s->fifo_path, O_WRONLY|O_CLOEXEC|O_NDELAY);
880 void session_remove_fifo(Session *s) {
883 if (s->fifo_event_source)
884 s->fifo_event_source = sd_event_source_unref(s->fifo_event_source);
886 if (s->fifo_fd >= 0) {
887 close_nointr_nofail(s->fifo_fd);
892 unlink(s->fifo_path);
898 bool session_check_gc(Session *s, bool drop_not_started) {
903 if (drop_not_started && !s->started)
909 if (s->fifo_fd >= 0) {
910 r = pipe_eof(s->fifo_fd);
918 if (s->scope_job && manager_job_is_active(s->manager, s->scope_job))
921 if (s->scope && manager_unit_is_active(s->manager, s->scope))
927 void session_add_to_gc_queue(Session *s) {
933 LIST_PREPEND(gc_queue, s->manager->session_gc_queue, s);
934 s->in_gc_queue = true;
937 SessionState session_get_state(Session *s) {
941 return SESSION_CLOSING;
944 return SESSION_OPENING;
947 return SESSION_CLOSING;
949 if (session_is_active(s))
950 return SESSION_ACTIVE;
952 return SESSION_ONLINE;
955 int session_kill(Session *s, KillWho who, int signo) {
961 return manager_kill_unit(s->manager, s->scope, who, signo, NULL);
964 bool session_is_controller(Session *s, const char *sender) {
967 return streq_ptr(s->controller, sender);
970 int session_set_controller(Session *s, const char *sender, bool force) {
977 if (session_is_controller(s, sender))
979 if (s->controller && !force)
986 r = manager_watch_busname(s->manager, sender);
992 session_drop_controller(s);
998 void session_drop_controller(Session *s) {
1006 manager_drop_busname(s->manager, s->controller);
1007 free(s->controller);
1008 s->controller = NULL;
1010 /* Drop all devices as they're now unused. Do that after the controller
1011 * is released to avoid sending out useles dbus signals. */
1012 while ((sd = hashmap_first(s->devices)))
1013 session_device_free(sd);
1016 static const char* const session_state_table[_SESSION_STATE_MAX] = {
1017 [SESSION_OPENING] = "opening",
1018 [SESSION_ONLINE] = "online",
1019 [SESSION_ACTIVE] = "active",
1020 [SESSION_CLOSING] = "closing"
1023 DEFINE_STRING_TABLE_LOOKUP(session_state, SessionState);
1025 static const char* const session_type_table[_SESSION_TYPE_MAX] = {
1026 [SESSION_TTY] = "tty",
1027 [SESSION_X11] = "x11",
1028 [SESSION_UNSPECIFIED] = "unspecified"
1031 DEFINE_STRING_TABLE_LOOKUP(session_type, SessionType);
1033 static const char* const session_class_table[_SESSION_CLASS_MAX] = {
1034 [SESSION_USER] = "user",
1035 [SESSION_GREETER] = "greeter",
1036 [SESSION_LOCK_SCREEN] = "lock-screen",
1037 [SESSION_BACKGROUND] = "background"
1040 DEFINE_STRING_TABLE_LOOKUP(session_class, SessionClass);
1042 static const char* const kill_who_table[_KILL_WHO_MAX] = {
1043 [KILL_LEADER] = "leader",
1047 DEFINE_STRING_TABLE_LOOKUP(kill_who, KillWho);