1 /* SPDX-License-Identifier: LGPL-2.1+ */
3 Copyright 2011 Lennart Poettering
12 #include <sys/ioctl.h>
15 #include "sd-messages.h"
17 #include "alloc-util.h"
18 #include "audit-util.h"
19 #include "bus-error.h"
24 #include "format-util.h"
26 #include "logind-session.h"
28 #include "parse-util.h"
29 #include "path-util.h"
30 #include "string-table.h"
31 #include "terminal-util.h"
32 #include "user-util.h"
34 #include "process-util.h"
36 #define RELEASE_USEC (20*USEC_PER_SEC)
38 static void session_remove_fifo(Session
*s
);
40 Session
* session_new(Manager
*m
, const char *id
) {
45 assert(session_id_valid(id
));
51 s
->state_file
= strappend("/run/systemd/sessions/", id
);
55 s
->devices
= hashmap_new(&devt_hash_ops
);
61 s
->id
= basename(s
->state_file
);
63 if (hashmap_put(m
->sessions
, s
->id
, s
) < 0) {
64 hashmap_free(s
->devices
);
72 s
->audit_id
= AUDIT_SESSION_INVALID
;
77 void session_free(Session
*s
) {
83 LIST_REMOVE(gc_queue
, s
->manager
->session_gc_queue
, s
);
85 s
->timer_event_source
= sd_event_source_unref(s
->timer_event_source
);
87 session_remove_fifo(s
);
89 session_drop_controller(s
);
91 while ((sd
= hashmap_first(s
->devices
)))
92 session_device_free(sd
);
94 hashmap_free(s
->devices
);
97 LIST_REMOVE(sessions_by_user
, s
->user
->sessions
, s
);
99 if (s
->user
->display
== s
)
100 s
->user
->display
= NULL
;
104 if (s
->seat
->active
== s
)
105 s
->seat
->active
= NULL
;
106 if (s
->seat
->pending_switch
== s
)
107 s
->seat
->pending_switch
= NULL
;
109 seat_evict_position(s
->seat
, s
);
110 LIST_REMOVE(sessions_by_seat
, s
->seat
->sessions
, s
);
114 hashmap_remove(s
->manager
->session_units
, s
->scope
);
120 sd_bus_message_unref(s
->create_message
);
124 free(s
->remote_host
);
125 free(s
->remote_user
);
129 hashmap_remove(s
->manager
->sessions
, s
->id
);
135 void session_set_user(Session
*s
, User
*u
) {
140 LIST_PREPEND(sessions_by_user
, u
->sessions
, s
);
143 static void session_save_devices(Session
*s
, FILE *f
) {
147 if (!hashmap_isempty(s
->devices
)) {
148 fprintf(f
, "DEVICES=");
149 HASHMAP_FOREACH(sd
, s
->devices
, i
)
150 fprintf(f
, "%u:%u ", major(sd
->dev
), minor(sd
->dev
));
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, MKDIR_WARN_MODE
);
172 r
= fopen_temporary(s
->state_file
, &f
, &temp_path
);
178 fchmod(fileno(f
), 0644);
181 "# This is private data. Do not parse.\n"
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
);
202 fprintf(f
, "SCOPE_JOB=%s\n", s
->scope_job
);
205 fprintf(f
, "FIFO=%s\n", s
->fifo_path
);
208 fprintf(f
, "SEAT=%s\n", s
->seat
->id
);
211 fprintf(f
, "TTY=%s\n", s
->tty
);
214 fprintf(f
, "DISPLAY=%s\n", s
->display
);
216 if (s
->remote_host
) {
217 _cleanup_free_
char *escaped
;
219 escaped
= cescape(s
->remote_host
);
225 fprintf(f
, "REMOTE_HOST=%s\n", escaped
);
228 if (s
->remote_user
) {
229 _cleanup_free_
char *escaped
;
231 escaped
= cescape(s
->remote_user
);
237 fprintf(f
, "REMOTE_USER=%s\n", escaped
);
241 _cleanup_free_
char *escaped
;
243 escaped
= cescape(s
->service
);
249 fprintf(f
, "SERVICE=%s\n", escaped
);
253 _cleanup_free_
char *escaped
;
255 escaped
= cescape(s
->desktop
);
261 fprintf(f
, "DESKTOP=%s\n", escaped
);
264 if (s
->seat
&& seat_has_vts(s
->seat
))
265 fprintf(f
, "VTNR=%u\n", s
->vtnr
);
268 fprintf(f
, "POSITION=%u\n", s
->position
);
270 if (pid_is_valid(s
->leader
))
271 fprintf(f
, "LEADER="PID_FMT
"\n", s
->leader
);
273 if (audit_session_is_valid(s
->audit_id
))
274 fprintf(f
, "AUDIT=%"PRIu32
"\n", s
->audit_id
);
276 if (dual_timestamp_is_set(&s
->timestamp
))
278 "REALTIME="USEC_FMT
"\n"
279 "MONOTONIC="USEC_FMT
"\n",
280 s
->timestamp
.realtime
,
281 s
->timestamp
.monotonic
);
284 fprintf(f
, "CONTROLLER=%s\n", s
->controller
);
285 session_save_devices(s
, f
);
288 r
= fflush_and_check(f
);
292 if (rename(temp_path
, s
->state_file
) < 0) {
300 (void) unlink(s
->state_file
);
303 (void) unlink(temp_path
);
305 return log_error_errno(r
, "Failed to save session data %s: %m", s
->state_file
);
308 static int session_load_devices(Session
*s
, const char *devices
) {
314 for (p
= devices
;;) {
315 _cleanup_free_
char *word
= NULL
;
320 k
= extract_first_word(&p
, &word
, NULL
, 0);
328 k
= parse_dev(word
, &dev
);
334 /* The file descriptors for loaded devices will be reattached later. */
335 k
= session_device_new(s
, dev
, false, &sd
);
341 log_error_errno(r
, "Loading session devices for session %s failed: %m", s
->id
);
346 int session_load(Session
*s
) {
347 _cleanup_free_
char *remote
= NULL
,
366 r
= parse_env_file(NULL
, s
->state_file
, NEWLINE
,
369 "SCOPE_JOB", &s
->scope_job
,
370 "FIFO", &s
->fifo_path
,
373 "DISPLAY", &s
->display
,
374 "REMOTE_HOST", &s
->remote_host
,
375 "REMOTE_USER", &s
->remote_user
,
376 "SERVICE", &s
->service
,
377 "DESKTOP", &s
->desktop
,
380 "POSITION", &position
,
385 "REALTIME", &realtime
,
386 "MONOTONIC", &monotonic
,
387 "CONTROLLER", &controller
,
393 return log_error_errno(r
, "Failed to read %s: %m", s
->state_file
);
400 log_error("UID not specified for session %s", s
->id
);
404 r
= parse_uid(uid
, &u
);
406 log_error("Failed to parse UID value %s for session %s.", uid
, s
->id
);
410 user
= hashmap_get(s
->manager
->users
, UID_TO_PTR(u
));
412 log_error("User of session %s not known.", s
->id
);
416 session_set_user(s
, user
);
420 k
= parse_boolean(remote
);
426 safe_atou(vtnr
, &s
->vtnr
);
428 if (seat
&& !s
->seat
) {
431 o
= hashmap_get(s
->manager
->seats
, seat
);
433 r
= seat_attach_session(o
, s
);
435 log_error("Cannot attach session %s to seat %s", s
->id
, seat
);
438 if (!s
->seat
|| !seat_has_vts(s
->seat
))
441 if (position
&& s
->seat
) {
444 safe_atou(position
, &npos
);
445 seat_claim_position(s
->seat
, s
, npos
);
449 if (parse_pid(leader
, &s
->leader
) >= 0)
450 (void) audit_session_from_pid(s
->leader
, &s
->audit_id
);
456 t
= session_type_from_string(type
);
464 c
= session_class_from_string(class);
469 if (state
&& streq(state
, "closing"))
475 /* If we open an unopened pipe for reading we will not
476 get an EOF. to trigger an EOF we hence open it for
477 writing, but close it right away which then will
478 trigger the EOF. This will happen immediately if no
479 other process has the FIFO open for writing, i. e.
480 when the session died before logind (re)started. */
482 fd
= session_create_fifo(s
);
487 timestamp_deserialize(realtime
, &s
->timestamp
.realtime
);
489 timestamp_deserialize(monotonic
, &s
->timestamp
.monotonic
);
492 k
= parse_boolean(active
);
498 if (bus_name_has_owner(s
->manager
->bus
, controller
, NULL
) > 0) {
499 session_set_controller(s
, controller
, false, false);
500 session_load_devices(s
, devices
);
502 session_restore_vt(s
);
508 int session_activate(Session
*s
) {
509 unsigned int num_pending
;
517 if (s
->seat
->active
== s
)
520 /* on seats with VTs, we let VTs manage session-switching */
521 if (seat_has_vts(s
->seat
)) {
525 return chvt(s
->vtnr
);
528 /* On seats without VTs, we implement session-switching in logind. We
529 * try to pause all session-devices and wait until the session
530 * controller acknowledged them. Once all devices are asleep, we simply
531 * switch the active session and be done.
532 * We save the session we want to switch to in seat->pending_switch and
533 * seat_complete_switch() will perform the final switch. */
535 s
->seat
->pending_switch
= s
;
537 /* if no devices are running, immediately perform the session switch */
538 num_pending
= session_device_try_pause_all(s
);
540 seat_complete_switch(s
->seat
);
545 static int session_start_scope(Session
*s
, sd_bus_message
*properties
) {
552 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
553 char *scope
, *job
= NULL
;
554 const char *description
;
556 scope
= strjoin("session-", s
->id
, ".scope");
560 description
= strjoina("Session ", s
->id
, " of user ", s
->user
->name
);
562 r
= manager_start_scope(
568 "systemd-logind.service",
569 "systemd-user-sessions.service",
574 log_error_errno(r
, "Failed to start session scope %s: %s", scope
, bus_error_message(&error
, r
));
586 (void) hashmap_put(s
->manager
->session_units
, s
->scope
, s
);
591 int session_start(Session
*s
, sd_bus_message
*properties
) {
602 r
= user_start(s
->user
);
607 r
= session_start_scope(s
, properties
);
611 log_struct(s
->class == SESSION_BACKGROUND
? LOG_DEBUG
: LOG_INFO
,
612 "MESSAGE_ID=" SD_MESSAGE_SESSION_START_STR
,
613 "SESSION_ID=%s", s
->id
,
614 "USER_ID=%s", s
->user
->name
,
615 "LEADER="PID_FMT
, s
->leader
,
616 LOG_MESSAGE("New session %s of user %s.", s
->id
, s
->user
->name
));
618 if (!dual_timestamp_is_set(&s
->timestamp
))
619 dual_timestamp_get(&s
->timestamp
);
622 seat_read_active_vt(s
->seat
);
626 user_elect_display(s
->user
);
635 session_send_signal(s
, true);
636 user_send_changed(s
->user
, "Display", NULL
);
638 if (s
->seat
->active
== s
)
639 seat_send_changed(s
->seat
, "ActiveSession", NULL
);
645 static int session_stop_scope(Session
*s
, bool force
) {
646 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
654 /* Let's always abandon the scope first. This tells systemd that we are not interested anymore, and everything
655 * that is left in the scope is "left-over". Informing systemd about this has the benefit that it will log
656 * when killing any processes left after this point. */
657 r
= manager_abandon_scope(s
->manager
, s
->scope
, &error
);
659 log_warning_errno(r
, "Failed to abandon session scope, ignoring: %s", bus_error_message(&error
, r
));
661 /* Optionally, let's kill everything that's left now. */
662 if (force
|| manager_shall_kill(s
->manager
, s
->user
->name
)) {
665 r
= manager_stop_unit(s
->manager
, s
->scope
, &error
, &job
);
667 return log_error_errno(r
, "Failed to stop session scope: %s", bus_error_message(&error
, r
));
672 s
->scope_job
= mfree(s
->scope_job
);
674 /* With no killing, this session is allowed to persist in "closing" state indefinitely.
675 * Therefore session stop and session removal may be two distinct events.
676 * Session stop is quite significant on its own, let's log it. */
677 log_struct(s
->class == SESSION_BACKGROUND
? LOG_DEBUG
: LOG_INFO
,
678 "SESSION_ID=%s", s
->id
,
679 "USER_ID=%s", s
->user
->name
,
680 "LEADER="PID_FMT
, s
->leader
,
681 LOG_MESSAGE("Session %s logged out. Waiting for processes to exit.", s
->id
));
687 int session_stop(Session
*s
, bool force
) {
695 s
->timer_event_source
= sd_event_source_unref(s
->timer_event_source
);
698 seat_evict_position(s
->seat
, s
);
700 /* We are going down, don't care about FIFOs anymore */
701 session_remove_fifo(s
);
704 r
= session_stop_scope(s
, force
);
708 user_elect_display(s
->user
);
716 int session_finalize(Session
*s
) {
725 log_struct(s
->class == SESSION_BACKGROUND
? LOG_DEBUG
: LOG_INFO
,
726 "MESSAGE_ID=" SD_MESSAGE_SESSION_STOP_STR
,
727 "SESSION_ID=%s", s
->id
,
728 "USER_ID=%s", s
->user
->name
,
729 "LEADER="PID_FMT
, s
->leader
,
730 LOG_MESSAGE("Removed session %s.", s
->id
));
732 s
->timer_event_source
= sd_event_source_unref(s
->timer_event_source
);
735 seat_evict_position(s
->seat
, s
);
737 /* Kill session devices */
738 while ((sd
= hashmap_first(s
->devices
)))
739 session_device_free(sd
);
741 (void) unlink(s
->state_file
);
742 session_add_to_gc_queue(s
);
743 user_add_to_gc_queue(s
->user
);
746 session_send_signal(s
, false);
751 if (s
->seat
->active
== s
)
752 seat_set_active(s
->seat
, NULL
);
758 user_send_changed(s
->user
, "Display", NULL
);
763 static int release_timeout_callback(sd_event_source
*es
, uint64_t usec
, void *userdata
) {
764 Session
*s
= userdata
;
769 session_stop(s
, false);
773 int session_release(Session
*s
) {
776 if (!s
->started
|| s
->stopping
)
779 if (s
->timer_event_source
)
782 return sd_event_add_time(s
->manager
->event
,
783 &s
->timer_event_source
,
785 now(CLOCK_MONOTONIC
) + RELEASE_USEC
, 0,
786 release_timeout_callback
, s
);
789 bool session_is_active(Session
*s
) {
795 return s
->seat
->active
== s
;
798 static int get_tty_atime(const char *tty
, usec_t
*atime
) {
799 _cleanup_free_
char *p
= NULL
;
805 if (!path_is_absolute(tty
)) {
806 p
= strappend("/dev/", tty
);
811 } else if (!path_startswith(tty
, "/dev/"))
814 if (lstat(tty
, &st
) < 0)
817 *atime
= timespec_load(&st
.st_atim
);
821 static int get_process_ctty_atime(pid_t pid
, usec_t
*atime
) {
822 _cleanup_free_
char *p
= NULL
;
828 r
= get_ctty(pid
, NULL
, &p
);
832 return get_tty_atime(p
, atime
);
835 int session_get_idle_hint(Session
*s
, dual_timestamp
*t
) {
841 /* Explicit idle hint is set */
844 *t
= s
->idle_hint_timestamp
;
849 /* Graphical sessions should really implement a real
851 if (SESSION_TYPE_IS_GRAPHICAL(s
->type
))
854 /* For sessions with an explicitly configured tty, let's check
857 r
= get_tty_atime(s
->tty
, &atime
);
862 /* For sessions with a leader but no explicitly configured
863 * tty, let's check the controlling tty of the leader */
865 r
= get_process_ctty_atime(s
->leader
, &atime
);
872 *t
= s
->idle_hint_timestamp
;
878 dual_timestamp_from_realtime(t
, atime
);
880 n
= now(CLOCK_REALTIME
);
882 if (s
->manager
->idle_action_usec
<= 0)
885 return atime
+ s
->manager
->idle_action_usec
<= n
;
888 void session_set_idle_hint(Session
*s
, bool b
) {
891 if (s
->idle_hint
== b
)
895 dual_timestamp_get(&s
->idle_hint_timestamp
);
897 session_send_changed(s
, "IdleHint", "IdleSinceHint", "IdleSinceHintMonotonic", NULL
);
900 seat_send_changed(s
->seat
, "IdleHint", "IdleSinceHint", "IdleSinceHintMonotonic", NULL
);
902 user_send_changed(s
->user
, "IdleHint", "IdleSinceHint", "IdleSinceHintMonotonic", NULL
);
903 manager_send_changed(s
->manager
, "IdleHint", "IdleSinceHint", "IdleSinceHintMonotonic", NULL
);
906 int session_get_locked_hint(Session
*s
) {
909 return s
->locked_hint
;
912 void session_set_locked_hint(Session
*s
, bool b
) {
915 if (s
->locked_hint
== b
)
920 session_send_changed(s
, "LockedHint", NULL
);
923 static int session_dispatch_fifo(sd_event_source
*es
, int fd
, uint32_t revents
, void *userdata
) {
924 Session
*s
= userdata
;
927 assert(s
->fifo_fd
== fd
);
929 /* EOF on the FIFO means the session died abnormally. */
931 session_remove_fifo(s
);
932 session_stop(s
, false);
937 int session_create_fifo(Session
*s
) {
944 r
= mkdir_safe_label("/run/systemd/sessions", 0755, 0, 0, MKDIR_WARN_MODE
);
948 if (asprintf(&s
->fifo_path
, "/run/systemd/sessions/%s.ref", s
->id
) < 0)
951 if (mkfifo(s
->fifo_path
, 0600) < 0 && errno
!= EEXIST
)
955 /* Open reading side */
956 if (s
->fifo_fd
< 0) {
957 s
->fifo_fd
= open(s
->fifo_path
, O_RDONLY
|O_CLOEXEC
|O_NONBLOCK
);
963 if (!s
->fifo_event_source
) {
964 r
= sd_event_add_io(s
->manager
->event
, &s
->fifo_event_source
, s
->fifo_fd
, 0, session_dispatch_fifo
, s
);
968 /* Let's make sure we noticed dead sessions before we process new bus requests (which might create new
970 r
= sd_event_source_set_priority(s
->fifo_event_source
, SD_EVENT_PRIORITY_NORMAL
-10);
975 /* Open writing side */
976 r
= open(s
->fifo_path
, O_WRONLY
|O_CLOEXEC
|O_NONBLOCK
);
983 static void session_remove_fifo(Session
*s
) {
986 s
->fifo_event_source
= sd_event_source_unref(s
->fifo_event_source
);
987 s
->fifo_fd
= safe_close(s
->fifo_fd
);
990 unlink(s
->fifo_path
);
991 s
->fifo_path
= mfree(s
->fifo_path
);
995 bool session_may_gc(Session
*s
, bool drop_not_started
) {
998 if (drop_not_started
&& !s
->started
)
1004 if (s
->fifo_fd
>= 0) {
1005 if (pipe_eof(s
->fifo_fd
) <= 0)
1009 if (s
->scope_job
&& manager_job_is_active(s
->manager
, s
->scope_job
))
1012 if (s
->scope
&& manager_unit_is_active(s
->manager
, s
->scope
))
1018 void session_add_to_gc_queue(Session
*s
) {
1024 LIST_PREPEND(gc_queue
, s
->manager
->session_gc_queue
, s
);
1025 s
->in_gc_queue
= true;
1028 SessionState
session_get_state(Session
*s
) {
1031 /* always check closing first */
1032 if (s
->stopping
|| s
->timer_event_source
)
1033 return SESSION_CLOSING
;
1035 if (s
->scope_job
|| s
->fifo_fd
< 0)
1036 return SESSION_OPENING
;
1038 if (session_is_active(s
))
1039 return SESSION_ACTIVE
;
1041 return SESSION_ONLINE
;
1044 int session_kill(Session
*s
, KillWho who
, int signo
) {
1050 return manager_kill_unit(s
->manager
, s
->scope
, who
, signo
, NULL
);
1053 static int session_open_vt(Session
*s
) {
1054 char path
[sizeof("/dev/tty") + DECIMAL_STR_MAX(s
->vtnr
)];
1062 sprintf(path
, "/dev/tty%u", s
->vtnr
);
1063 s
->vtfd
= open_terminal(path
, O_RDWR
| O_CLOEXEC
| O_NONBLOCK
| O_NOCTTY
);
1065 return log_error_errno(s
->vtfd
, "cannot open VT %s of session %s: %m", path
, s
->id
);
1070 int session_prepare_vt(Session
*s
) {
1072 struct vt_mode mode
= { 0 };
1077 vt
= session_open_vt(s
);
1081 r
= fchown(vt
, s
->user
->uid
, -1);
1083 r
= log_error_errno(errno
,
1084 "Cannot change owner of /dev/tty%u: %m",
1089 r
= ioctl(vt
, KDSKBMODE
, K_OFF
);
1091 r
= log_error_errno(errno
,
1092 "Cannot set K_OFF on /dev/tty%u: %m",
1097 r
= ioctl(vt
, KDSETMODE
, KD_GRAPHICS
);
1099 r
= log_error_errno(errno
,
1100 "Cannot set KD_GRAPHICS on /dev/tty%u: %m",
1105 /* Oh, thanks to the VT layer, VT_AUTO does not work with KD_GRAPHICS.
1106 * So we need a dummy handler here which just acknowledges *all* VT
1107 * switch requests. */
1108 mode
.mode
= VT_PROCESS
;
1109 mode
.relsig
= SIGRTMIN
;
1110 mode
.acqsig
= SIGRTMIN
+ 1;
1111 r
= ioctl(vt
, VT_SETMODE
, &mode
);
1113 r
= log_error_errno(errno
,
1114 "Cannot set VT_PROCESS on /dev/tty%u: %m",
1122 session_restore_vt(s
);
1126 void session_restore_vt(Session
*s
) {
1128 static const struct vt_mode mode
= {
1134 /* We need to get a fresh handle to the virtual terminal,
1135 * since the old file-descriptor is potentially in a hung-up
1136 * state after the controlling process exited; we do a
1137 * little dance to avoid having the terminal be available
1138 * for reuse before we've cleaned it up.
1140 old_fd
= TAKE_FD(s
->vtfd
);
1142 vt
= session_open_vt(s
);
1148 (void) ioctl(vt
, KDSETMODE
, KD_TEXT
);
1150 (void) vt_reset_keyboard(vt
);
1152 (void) ioctl(vt
, VT_SETMODE
, &mode
);
1153 (void) fchown(vt
, 0, (gid_t
) -1);
1155 s
->vtfd
= safe_close(s
->vtfd
);
1158 void session_leave_vt(Session
*s
) {
1163 /* This is called whenever we get a VT-switch signal from the kernel.
1164 * We acknowledge all of them unconditionally. Note that session are
1165 * free to overwrite those handlers and we only register them for
1166 * sessions with controllers. Legacy sessions are not affected.
1167 * However, if we switch from a non-legacy to a legacy session, we must
1168 * make sure to pause all device before acknowledging the switch. We
1169 * process the real switch only after we are notified via sysfs, so the
1170 * legacy session might have already started using the devices. If we
1171 * don't pause the devices before the switch, we might confuse the
1172 * session we switch to. */
1177 session_device_pause_all(s
);
1178 r
= ioctl(s
->vtfd
, VT_RELDISP
, 1);
1180 log_debug_errno(errno
, "Cannot release VT of session %s: %m", s
->id
);
1183 bool session_is_controller(Session
*s
, const char *sender
) {
1186 return streq_ptr(s
->controller
, sender
);
1189 static void session_release_controller(Session
*s
, bool notify
) {
1190 _cleanup_free_
char *name
= NULL
;
1196 name
= s
->controller
;
1198 /* By resetting the controller before releasing the devices, we won't
1199 * send notification signals. This avoids sending useless notifications
1200 * if the controller is released on disconnects. */
1202 s
->controller
= NULL
;
1204 while ((sd
= hashmap_first(s
->devices
)))
1205 session_device_free(sd
);
1207 s
->controller
= NULL
;
1208 s
->track
= sd_bus_track_unref(s
->track
);
1211 static int on_bus_track(sd_bus_track
*track
, void *userdata
) {
1212 Session
*s
= userdata
;
1217 session_drop_controller(s
);
1222 int session_set_controller(Session
*s
, const char *sender
, bool force
, bool prepare
) {
1223 _cleanup_free_
char *name
= NULL
;
1229 if (session_is_controller(s
, sender
))
1231 if (s
->controller
&& !force
)
1234 name
= strdup(sender
);
1238 s
->track
= sd_bus_track_unref(s
->track
);
1239 r
= sd_bus_track_new(s
->manager
->bus
, &s
->track
, on_bus_track
, s
);
1243 r
= sd_bus_track_add_name(s
->track
, name
);
1247 /* When setting a session controller, we forcibly mute the VT and set
1248 * it into graphics-mode. Applications can override that by changing
1249 * VT state after calling TakeControl(). However, this serves as a good
1250 * default and well-behaving controllers can now ignore VTs entirely.
1251 * Note that we reset the VT on ReleaseControl() and if the controller
1253 * If logind crashes/restarts, we restore the controller during restart
1254 * (without preparing the VT since the controller has probably overridden
1255 * VT state by now) or reset the VT in case it crashed/exited, too. */
1257 r
= session_prepare_vt(s
);
1259 s
->track
= sd_bus_track_unref(s
->track
);
1264 session_release_controller(s
, true);
1265 s
->controller
= TAKE_PTR(name
);
1271 void session_drop_controller(Session
*s
) {
1277 s
->track
= sd_bus_track_unref(s
->track
);
1278 session_release_controller(s
, false);
1280 session_restore_vt(s
);
1283 static const char* const session_state_table
[_SESSION_STATE_MAX
] = {
1284 [SESSION_OPENING
] = "opening",
1285 [SESSION_ONLINE
] = "online",
1286 [SESSION_ACTIVE
] = "active",
1287 [SESSION_CLOSING
] = "closing"
1290 DEFINE_STRING_TABLE_LOOKUP(session_state
, SessionState
);
1292 static const char* const session_type_table
[_SESSION_TYPE_MAX
] = {
1293 [SESSION_UNSPECIFIED
] = "unspecified",
1294 [SESSION_TTY
] = "tty",
1295 [SESSION_X11
] = "x11",
1296 [SESSION_WAYLAND
] = "wayland",
1297 [SESSION_MIR
] = "mir",
1298 [SESSION_WEB
] = "web",
1301 DEFINE_STRING_TABLE_LOOKUP(session_type
, SessionType
);
1303 static const char* const session_class_table
[_SESSION_CLASS_MAX
] = {
1304 [SESSION_USER
] = "user",
1305 [SESSION_GREETER
] = "greeter",
1306 [SESSION_LOCK_SCREEN
] = "lock-screen",
1307 [SESSION_BACKGROUND
] = "background"
1310 DEFINE_STRING_TABLE_LOOKUP(session_class
, SessionClass
);
1312 static const char* const kill_who_table
[_KILL_WHO_MAX
] = {
1313 [KILL_LEADER
] = "leader",
1317 DEFINE_STRING_TABLE_LOOKUP(kill_who
, KillWho
);