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);
243 fprintf(f, "CONTROLLER=%s\n", s->controller);
247 if (ferror(f) || rename(temp_path, s->state_file) < 0) {
249 unlink(s->state_file);
255 log_error("Failed to save session data for %s: %s", s->id, strerror(-r));
260 int session_load(Session *s) {
261 _cleanup_free_ char *remote = NULL,
276 r = parse_env_file(s->state_file, NEWLINE,
279 "SCOPE_JOB", &s->scope_job,
280 "FIFO", &s->fifo_path,
283 "DISPLAY", &s->display,
284 "REMOTE_HOST", &s->remote_host,
285 "REMOTE_USER", &s->remote_user,
286 "SERVICE", &s->service,
292 "REALTIME", &realtime,
293 "MONOTONIC", &monotonic,
294 "CONTROLLER", &controller,
298 log_error("Failed to read %s: %s", s->state_file, strerror(-r));
307 log_error("UID not specified for session %s", s->id);
311 r = parse_uid(uid, &u);
313 log_error("Failed to parse UID value %s for session %s.", uid, s->id);
317 user = hashmap_get(s->manager->users, ULONG_TO_PTR((unsigned long) u));
319 log_error("User of session %s not known.", s->id);
323 session_set_user(s, user);
327 k = parse_boolean(remote);
332 if (seat && !s->seat) {
335 o = hashmap_get(s->manager->seats, seat);
337 seat_attach_session(o, s);
340 if (vtnr && s->seat && seat_has_vts(s->seat)) {
343 k = safe_atoi(vtnr, &v);
344 if (k >= 0 && v >= 1)
349 k = parse_pid(leader, &s->leader);
351 audit_session_from_pid(s->leader, &s->audit_id);
357 t = session_type_from_string(type);
365 c = session_class_from_string(class);
373 /* If we open an unopened pipe for reading we will not
374 get an EOF. to trigger an EOF we hence open it for
375 reading, but close it right-away which then will
378 fd = session_create_fifo(s);
380 close_nointr_nofail(fd);
384 unsigned long long l;
385 if (sscanf(realtime, "%llu", &l) > 0)
386 s->timestamp.realtime = l;
390 unsigned long long l;
391 if (sscanf(monotonic, "%llu", &l) > 0)
392 s->timestamp.monotonic = l;
396 if (bus_name_has_owner(s->manager->bus, controller, NULL) > 0)
397 session_set_controller(s, controller, false);
403 int session_activate(Session *s) {
404 unsigned int num_pending;
412 if (s->seat->active == s)
415 /* on seats with VTs, we let VTs manage session-switching */
416 if (seat_has_vts(s->seat)) {
420 return chvt(s->vtnr);
423 /* On seats without VTs, we implement session-switching in logind. We
424 * try to pause all session-devices and wait until the session
425 * controller acknowledged them. Once all devices are asleep, we simply
426 * switch the active session and be done.
427 * We save the session we want to switch to in seat->pending_switch and
428 * seat_complete_switch() will perform the final switch. */
430 s->seat->pending_switch = s;
432 /* if no devices are running, immediately perform the session switch */
433 num_pending = session_device_try_pause_all(s);
435 seat_complete_switch(s->seat);
440 static int session_link_x11_socket(Session *s) {
441 _cleanup_free_ char *t = NULL, *f = NULL;
447 assert(s->user->runtime_path);
449 if (s->user->display)
452 if (!s->display || !display_is_local(s->display))
455 k = strspn(s->display+1, "0123456789");
456 f = new(char, sizeof("/tmp/.X11-unix/X") + k);
460 c = stpcpy(f, "/tmp/.X11-unix/X");
461 memcpy(c, s->display+1, k);
464 if (access(f, F_OK) < 0) {
465 log_warning("Session %s has display %s with non-existing socket %s.", s->id, s->display, f);
469 /* Note that this cannot be in a subdir to avoid
470 * vulnerabilities since we are privileged but the runtime
471 * path is owned by the user */
473 t = strappend(s->user->runtime_path, "/X11-display");
477 if (link(f, t) < 0) {
478 if (errno == EEXIST) {
485 if (symlink(f, t) < 0) {
487 if (errno == EEXIST) {
490 if (symlink(f, t) >= 0)
494 log_error("Failed to link %s to %s: %m", f, t);
500 log_info("Linked %s to %s.", f, t);
501 s->user->display = s;
506 static int session_start_scope(Session *s) {
511 assert(s->user->slice);
514 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
515 _cleanup_free_ char *description = NULL;
516 const char *kill_mode;
519 description = strjoin("Session ", s->id, " of user ", s->user->name, NULL);
523 scope = strjoin("session-", s->id, ".scope", NULL);
527 kill_mode = manager_shall_kill(s->manager, s->user->name) ? "control-group" : "none";
529 r = manager_start_scope(s->manager, scope, s->leader, s->user->slice, description, "systemd-user-sessions.service", kill_mode, &error, &job);
531 log_error("Failed to start session scope %s: %s %s",
532 scope, bus_error_message(&error, r), error.name);
544 hashmap_put(s->manager->session_units, s->scope, s);
549 int session_start(Session *s) {
560 r = user_start(s->user);
565 r = session_start_scope(s);
569 log_struct(s->type == SESSION_TTY || s->type == SESSION_X11 ? LOG_INFO : LOG_DEBUG,
570 MESSAGE_ID(SD_MESSAGE_SESSION_START),
571 "SESSION_ID=%s", s->id,
572 "USER_ID=%s", s->user->name,
573 "LEADER=%lu", (unsigned long) s->leader,
574 "MESSAGE=New session %s of user %s.", s->id, s->user->name,
577 /* Create X11 symlink */
578 session_link_x11_socket(s);
580 if (!dual_timestamp_is_set(&s->timestamp))
581 dual_timestamp_get(&s->timestamp);
584 seat_read_active_vt(s->seat);
588 /* Save session data */
592 session_send_signal(s, true);
597 if (s->seat->active == s)
598 seat_send_changed(s->seat, "Sessions", "ActiveSession", NULL);
600 seat_send_changed(s->seat, "Sessions", NULL);
603 user_send_changed(s->user, "Sessions", NULL);
608 static int session_stop_scope(Session *s) {
609 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
618 r = manager_stop_unit(s->manager, s->scope, &error, &job);
620 log_error("Failed to stop session scope: %s", bus_error_message(&error, r));
630 static int session_unlink_x11_socket(Session *s) {
631 _cleanup_free_ char *t = NULL;
637 if (s->user->display != s)
640 s->user->display = NULL;
642 t = strappend(s->user->runtime_path, "/X11-display");
647 return r < 0 ? -errno : 0;
650 int session_stop(Session *s) {
659 r = session_stop_scope(s);
667 int session_finalize(Session *s) {
677 log_struct(s->type == SESSION_TTY || s->type == SESSION_X11 ? LOG_INFO : LOG_DEBUG,
678 MESSAGE_ID(SD_MESSAGE_SESSION_STOP),
679 "SESSION_ID=%s", s->id,
680 "USER_ID=%s", s->user->name,
681 "LEADER=%lu", (unsigned long) s->leader,
682 "MESSAGE=Removed session %s.", s->id,
685 /* Kill session devices */
686 while ((sd = hashmap_first(s->devices)))
687 session_device_free(sd);
689 /* Remove X11 symlink */
690 session_unlink_x11_socket(s);
692 unlink(s->state_file);
693 session_add_to_gc_queue(s);
694 user_add_to_gc_queue(s->user);
697 session_send_signal(s, false);
702 if (s->seat->active == s)
703 seat_set_active(s->seat, NULL);
705 seat_send_changed(s->seat, "Sessions", NULL);
709 user_send_changed(s->user, "Sessions", NULL);
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);
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_fd, 0, session_dispatch_fifo, s, &s->fifo_event_source);
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 void session_remove_fifo(Session *s) {
893 if (s->fifo_event_source)
894 s->fifo_event_source = sd_event_source_unref(s->fifo_event_source);
896 if (s->fifo_fd >= 0) {
897 close_nointr_nofail(s->fifo_fd);
902 unlink(s->fifo_path);
908 bool session_check_gc(Session *s, bool drop_not_started) {
913 if (drop_not_started && !s->started)
919 if (s->fifo_fd >= 0) {
920 r = pipe_eof(s->fifo_fd);
928 if (s->scope_job && manager_job_is_active(s->manager, s->scope_job))
931 if (s->scope && manager_unit_is_active(s->manager, s->scope))
937 void session_add_to_gc_queue(Session *s) {
943 LIST_PREPEND(gc_queue, s->manager->session_gc_queue, s);
944 s->in_gc_queue = true;
947 SessionState session_get_state(Session *s) {
951 return SESSION_CLOSING;
954 return SESSION_OPENING;
957 return SESSION_CLOSING;
959 if (session_is_active(s))
960 return SESSION_ACTIVE;
962 return SESSION_ONLINE;
965 int session_kill(Session *s, KillWho who, int signo) {
971 return manager_kill_unit(s->manager, s->scope, who, signo, NULL);
974 bool session_is_controller(Session *s, const char *sender) {
977 return streq_ptr(s->controller, sender);
980 static void session_swap_controller(Session *s, char *name) {
984 manager_drop_busname(s->manager, s->controller);
986 s->controller = NULL;
988 /* Drop all devices as they're now unused. Do that after the
989 * controller is released to avoid sending out useles
991 while ((sd = hashmap_first(s->devices)))
992 session_device_free(sd);
995 s->controller = name;
999 int session_set_controller(Session *s, const char *sender, bool force) {
1006 if (session_is_controller(s, sender))
1008 if (s->controller && !force)
1015 r = manager_watch_busname(s->manager, sender);
1021 session_swap_controller(s, t);
1026 void session_drop_controller(Session *s) {
1032 session_swap_controller(s, NULL);
1035 static const char* const session_state_table[_SESSION_STATE_MAX] = {
1036 [SESSION_OPENING] = "opening",
1037 [SESSION_ONLINE] = "online",
1038 [SESSION_ACTIVE] = "active",
1039 [SESSION_CLOSING] = "closing"
1042 DEFINE_STRING_TABLE_LOOKUP(session_state, SessionState);
1044 static const char* const session_type_table[_SESSION_TYPE_MAX] = {
1045 [SESSION_TTY] = "tty",
1046 [SESSION_X11] = "x11",
1047 [SESSION_UNSPECIFIED] = "unspecified"
1050 DEFINE_STRING_TABLE_LOOKUP(session_type, SessionType);
1052 static const char* const session_class_table[_SESSION_CLASS_MAX] = {
1053 [SESSION_USER] = "user",
1054 [SESSION_GREETER] = "greeter",
1055 [SESSION_LOCK_SCREEN] = "lock-screen",
1056 [SESSION_BACKGROUND] = "background"
1059 DEFINE_STRING_TABLE_LOOKUP(session_class, SessionClass);
1061 static const char* const kill_who_table[_KILL_WHO_MAX] = {
1062 [KILL_LEADER] = "leader",
1066 DEFINE_STRING_TABLE_LOOKUP(kill_who, KillWho);