summaryrefslogtreecommitdiffstats
path: root/src/login/logind-session.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/login/logind-session.c')
-rw-r--r--src/login/logind-session.c452
1 files changed, 253 insertions, 199 deletions
diff --git a/src/login/logind-session.c b/src/login/logind-session.c
index 3988e55..4713aa0 100644
--- a/src/login/logind-session.c
+++ b/src/login/logind-session.c
@@ -15,6 +15,7 @@
#include "audit-util.h"
#include "bus-error.h"
#include "bus-util.h"
+#include "daemon-util.h"
#include "devnum-util.h"
#include "env-file.h"
#include "escape.h"
@@ -37,7 +38,7 @@
#include "strv.h"
#include "terminal-util.h"
#include "tmpfile-util.h"
-#include "uid-alloc-range.h"
+#include "uid-classification.h"
#include "user-util.h"
#define RELEASE_USEC (20*USEC_PER_SEC)
@@ -45,13 +46,13 @@
static void session_remove_fifo(Session *s);
static void session_restore_vt(Session *s);
-int session_new(Session **ret, Manager *m, const char *id) {
+int session_new(Manager *m, const char *id, Session **ret) {
_cleanup_(session_freep) Session *s = NULL;
int r;
- assert(ret);
assert(m);
assert(id);
+ assert(ret);
if (!session_id_valid(id))
return -EINVAL;
@@ -62,19 +63,17 @@ int session_new(Session **ret, Manager *m, const char *id) {
*s = (Session) {
.manager = m,
+ .id = strdup(id),
+ .state_file = path_join("/run/systemd/sessions/", id),
.fifo_fd = -EBADF,
.vtfd = -EBADF,
.audit_id = AUDIT_SESSION_INVALID,
.tty_validity = _TTY_VALIDITY_INVALID,
.leader = PIDREF_NULL,
};
-
- s->state_file = path_join("/run/systemd/sessions", id);
- if (!s->state_file)
+ if (!s->id || !s->state_file)
return -ENOMEM;
- s->id = basename(s->state_file);
-
s->devices = hashmap_new(&devt_hash_ops);
if (!s->devices)
return -ENOMEM;
@@ -87,12 +86,53 @@ int session_new(Session **ret, Manager *m, const char *id) {
return 0;
}
-static void session_reset_leader(Session *s) {
+static int session_dispatch_leader_pidfd(sd_event_source *es, int fd, uint32_t revents, void *userdata) {
+ Session *s = ASSERT_PTR(userdata);
+
+ assert(s->leader.fd == fd);
+ session_stop(s, /* force= */ false);
+
+ return 1;
+}
+
+static int session_watch_pidfd(Session *s) {
+ int r;
+
+ assert(s);
+ assert(s->manager);
+ assert(pidref_is_set(&s->leader));
+
+ if (s->leader.fd < 0)
+ return 0;
+
+ r = sd_event_add_io(s->manager->event, &s->leader_pidfd_event_source, s->leader.fd, EPOLLIN, session_dispatch_leader_pidfd, s);
+ if (r < 0)
+ return r;
+
+ r = sd_event_source_set_priority(s->leader_pidfd_event_source, SD_EVENT_PRIORITY_IMPORTANT);
+ if (r < 0)
+ return r;
+
+ (void) sd_event_source_set_description(s->leader_pidfd_event_source, "session-pidfd");
+
+ return 0;
+}
+
+static void session_reset_leader(Session *s, bool keep_fdstore) {
assert(s);
+ if (!keep_fdstore) {
+ /* Clear fdstore if we're asked to, no matter if s->leader is set or not, so that when
+ * initially deserializing leader fd we clear the old fd too. */
+ (void) notify_remove_fd_warnf("session-%s-leader-fd", s->id);
+ s->leader_fd_saved = false;
+ }
+
if (!pidref_is_set(&s->leader))
return;
+ s->leader_pidfd_event_source = sd_event_source_disable_unref(s->leader_pidfd_event_source);
+
(void) hashmap_remove_value(s->manager->sessions_by_leader, &s->leader, s);
return pidref_done(&s->leader);
@@ -104,10 +144,12 @@ Session* session_free(Session *s) {
if (!s)
return NULL;
+ sd_event_source_unref(s->stop_on_idle_event_source);
+
if (s->in_gc_queue)
LIST_REMOVE(gc_queue, s->manager->session_gc_queue, s);
- s->timer_event_source = sd_event_source_unref(s->timer_event_source);
+ sd_event_source_unref(s->timer_event_source);
session_drop_controller(s);
@@ -142,9 +184,10 @@ Session* session_free(Session *s) {
free(s->scope_job);
- session_reset_leader(s);
+ session_reset_leader(s, /* keep_fdstore = */ true);
sd_bus_message_unref(s->create_message);
+ sd_bus_message_unref(s->upgrade_message);
free(s->tty);
free(s->display);
@@ -160,10 +203,9 @@ Session* session_free(Session *s) {
/* Note that we remove neither the state file nor the fifo path here, since we want both to survive
* daemon restarts */
- free(s->state_file);
free(s->fifo_path);
-
- sd_event_source_unref(s->stop_on_idle_event_source);
+ free(s->state_file);
+ free(s->id);
return mfree(s);
}
@@ -188,15 +230,27 @@ int session_set_leader_consume(Session *s, PidRef _leader) {
if (pidref_equal(&s->leader, &pidref))
return 0;
- session_reset_leader(s);
+ session_reset_leader(s, /* keep_fdstore = */ false);
s->leader = TAKE_PIDREF(pidref);
+ r = session_watch_pidfd(s);
+ if (r < 0)
+ return log_error_errno(r, "Failed to watch leader pidfd for session '%s': %m", s->id);
+
r = hashmap_ensure_put(&s->manager->sessions_by_leader, &pidref_hash_ops, &s->leader, s);
if (r < 0)
return r;
assert(r > 0);
+ if (s->leader.fd >= 0) {
+ r = notify_push_fdf(s->leader.fd, "session-%s-leader-fd", s->id);
+ if (r < 0)
+ log_warning_errno(r, "Failed to push leader pidfd for session '%s', ignoring: %m", s->id);
+ else
+ s->leader_fd_saved = true;
+ }
+
(void) audit_session_from_pid(s->leader.pid, &s->audit_id);
return 1;
@@ -240,16 +294,18 @@ int session_save(Session *s) {
"# This is private data. Do not parse.\n"
"UID="UID_FMT"\n"
"USER=%s\n"
- "ACTIVE=%i\n"
- "IS_DISPLAY=%i\n"
+ "ACTIVE=%s\n"
+ "IS_DISPLAY=%s\n"
"STATE=%s\n"
- "REMOTE=%i\n",
+ "REMOTE=%s\n"
+ "LEADER_FD_SAVED=%s\n",
s->user->user_record->uid,
s->user->user_record->user_name,
- session_is_active(s),
- s->user->display == s,
+ one_zero(session_is_active(s)),
+ one_zero(s->user->display == s),
session_state_to_string(session_get_state(s)),
- s->remote);
+ one_zero(s->remote),
+ one_zero(s->leader_fd_saved));
if (s->type >= 0)
fprintf(f, "TYPE=%s\n", session_type_to_string(s->type));
@@ -377,33 +433,27 @@ static int session_load_devices(Session *s, const char *devices) {
for (const char *p = devices;;) {
_cleanup_free_ char *word = NULL;
- SessionDevice *sd;
dev_t dev;
int k;
k = extract_first_word(&p, &word, NULL, 0);
- if (k == 0)
- break;
- if (k < 0) {
- r = k;
+ if (k <= 0) {
+ RET_GATHER(r, k);
break;
}
k = parse_devnum(word, &dev);
if (k < 0) {
- r = k;
+ RET_GATHER(r, k);
continue;
}
/* The file descriptors for loaded devices will be reattached later. */
- k = session_device_new(s, dev, false, &sd);
- if (k < 0)
- r = k;
+ RET_GATHER(r, session_device_new(s, dev, /* open_device = */ false, /* ret = */ NULL));
}
if (r < 0)
- log_error_errno(r, "Loading session devices for session %s failed: %m", s->id);
-
+ log_error_errno(r, "Failed to load some session devices for session '%s': %m", s->id);
return r;
}
@@ -414,7 +464,8 @@ int session_load(Session *s) {
*vtnr = NULL,
*state = NULL,
*position = NULL,
- *leader = NULL,
+ *leader_pid = NULL,
+ *leader_fd_saved = NULL,
*type = NULL,
*original_type = NULL,
*class = NULL,
@@ -431,32 +482,33 @@ int session_load(Session *s) {
assert(s);
r = parse_env_file(NULL, s->state_file,
- "REMOTE", &remote,
- "SCOPE", &s->scope,
- "SCOPE_JOB", &s->scope_job,
- "FIFO", &s->fifo_path,
- "SEAT", &seat,
- "TTY", &s->tty,
- "TTY_VALIDITY", &tty_validity,
- "DISPLAY", &s->display,
- "REMOTE_HOST", &s->remote_host,
- "REMOTE_USER", &s->remote_user,
- "SERVICE", &s->service,
- "DESKTOP", &s->desktop,
- "VTNR", &vtnr,
- "STATE", &state,
- "POSITION", &position,
- "LEADER", &leader,
- "TYPE", &type,
- "ORIGINAL_TYPE", &original_type,
- "CLASS", &class,
- "UID", &uid,
- "REALTIME", &realtime,
- "MONOTONIC", &monotonic,
- "CONTROLLER", &controller,
- "ACTIVE", &active,
- "DEVICES", &devices,
- "IS_DISPLAY", &is_display);
+ "REMOTE", &remote,
+ "SCOPE", &s->scope,
+ "SCOPE_JOB", &s->scope_job,
+ "FIFO", &s->fifo_path,
+ "SEAT", &seat,
+ "TTY", &s->tty,
+ "TTY_VALIDITY", &tty_validity,
+ "DISPLAY", &s->display,
+ "REMOTE_HOST", &s->remote_host,
+ "REMOTE_USER", &s->remote_user,
+ "SERVICE", &s->service,
+ "DESKTOP", &s->desktop,
+ "VTNR", &vtnr,
+ "STATE", &state,
+ "POSITION", &position,
+ "LEADER", &leader_pid,
+ "LEADER_FD_SAVED", &leader_fd_saved,
+ "TYPE", &type,
+ "ORIGINAL_TYPE", &original_type,
+ "CLASS", &class,
+ "UID", &uid,
+ "REALTIME", &realtime,
+ "MONOTONIC", &monotonic,
+ "CONTROLLER", &controller,
+ "ACTIVE", &active,
+ "DEVICES", &devices,
+ "IS_DISPLAY", &is_display);
if (r < 0)
return log_error_errno(r, "Failed to read %s: %m", s->state_file);
@@ -523,19 +575,6 @@ int session_load(Session *s) {
s->tty_validity = v;
}
- if (leader) {
- _cleanup_(pidref_done) PidRef p = PIDREF_NULL;
-
- r = pidref_set_pidstr(&p, leader);
- if (r < 0)
- log_debug_errno(r, "Failed to parse leader PID of session: %s", leader);
- else {
- r = session_set_leader_consume(s, TAKE_PIDREF(p));
- if (r < 0)
- log_warning_errno(r, "Failed to set session leader PID, ignoring: %m");
- }
- }
-
if (type) {
SessionType t;
@@ -610,6 +649,33 @@ int session_load(Session *s) {
session_restore_vt(s);
}
+ if (leader_pid) {
+ assert(!pidref_is_set(&s->leader));
+
+ r = parse_pid(leader_pid, &s->deserialized_pid);
+ if (r < 0)
+ return log_error_errno(r, "Failed to parse LEADER=%s: %m", leader_pid);
+
+ if (leader_fd_saved) {
+ r = parse_boolean(leader_fd_saved);
+ if (r < 0)
+ return log_error_errno(r, "Failed to parse LEADER_FD_SAVED=%s: %m", leader_fd_saved);
+ s->leader_fd_saved = r > 0;
+
+ if (s->leader_fd_saved)
+ /* The leader fd will be acquired from fdstore later */
+ return 0;
+ }
+
+ _cleanup_(pidref_done) PidRef p = PIDREF_NULL;
+
+ r = pidref_set_pid(&p, s->deserialized_pid);
+ if (r >= 0)
+ r = session_set_leader_consume(s, TAKE_PIDREF(p));
+ if (r < 0)
+ log_warning_errno(r, "Failed to set leader PID for session '%s': %m", s->id);
+ }
+
return r;
}
@@ -651,60 +717,56 @@ int session_activate(Session *s) {
}
static int session_start_scope(Session *s, sd_bus_message *properties, sd_bus_error *error) {
+ _cleanup_free_ char *scope = NULL;
+ const char *description;
int r;
assert(s);
assert(s->user);
- if (!s->scope) {
- _cleanup_strv_free_ char **after = NULL;
- _cleanup_free_ char *scope = NULL;
- const char *description;
-
- s->scope_job = mfree(s->scope_job);
-
- scope = strjoin("session-", s->id, ".scope");
- if (!scope)
- return log_oom();
-
- description = strjoina("Session ", s->id, " of User ", s->user->user_record->user_name);
-
- /* We usually want to order session scopes after systemd-user-sessions.service since the
- * latter unit is used as login session barrier for unprivileged users. However the barrier
- * doesn't apply for root as sysadmin should always be able to log in (and without waiting
- * for any timeout to expire) in case something goes wrong during the boot process. Since
- * ordering after systemd-user-sessions.service and the user instance is optional we make use
- * of STRV_IGNORE with strv_new() to skip these order constraints when needed. */
- after = strv_new("systemd-logind.service",
- s->user->runtime_dir_service,
- !uid_is_system(s->user->user_record->uid) ? "systemd-user-sessions.service" : STRV_IGNORE,
- s->user->service);
- if (!after)
- return log_oom();
-
- r = manager_start_scope(
- s->manager,
- scope,
- &s->leader,
- s->user->slice,
- description,
- /* These two have StopWhenUnneeded= set, hence add a dep towards them */
- STRV_MAKE(s->user->runtime_dir_service,
- s->user->service),
- after,
- user_record_home_directory(s->user->user_record),
- properties,
- error,
- &s->scope_job);
- if (r < 0)
- return log_error_errno(r, "Failed to start session scope %s: %s",
- scope, bus_error_message(error, r));
+ if (!SESSION_CLASS_WANTS_SCOPE(s->class))
+ return 0;
- s->scope = TAKE_PTR(scope);
- }
+ if (s->scope)
+ goto finish;
- (void) hashmap_put(s->manager->session_units, s->scope, s);
+ s->scope_job = mfree(s->scope_job);
+ scope = strjoin("session-", s->id, ".scope");
+ if (!scope)
+ return log_oom();
+
+ description = strjoina("Session ", s->id, " of User ", s->user->user_record->user_name);
+
+ r = manager_start_scope(
+ s->manager,
+ scope,
+ &s->leader,
+ /* allow_pidfd = */ true,
+ s->user->slice,
+ description,
+ /* These should have been pulled in explicitly in user_start(). Just to be sure. */
+ STRV_MAKE_CONST(s->user->runtime_dir_unit,
+ SESSION_CLASS_WANTS_SERVICE_MANAGER(s->class) ? s->user->service_manager_unit : NULL),
+ /* We usually want to order session scopes after systemd-user-sessions.service
+ * since the unit is used as login session barrier for unprivileged users. However
+ * the barrier doesn't apply for root as sysadmin should always be able to log in
+ * (and without waiting for any timeout to expire) in case something goes wrong
+ * during the boot process. */
+ STRV_MAKE_CONST("systemd-logind.service",
+ SESSION_CLASS_IS_EARLY(s->class) ? NULL : "systemd-user-sessions.service"),
+ user_record_home_directory(s->user->user_record),
+ properties,
+ error,
+ &s->scope_job);
+ if (r < 0)
+ return log_error_errno(r, "Failed to start session scope %s: %s",
+ scope, bus_error_message(error, r));
+
+ s->scope = TAKE_PTR(scope);
+
+finish:
+ (void) hashmap_put(s->manager->session_units, s->scope, s);
return 0;
}
@@ -744,7 +806,7 @@ static int session_setup_stop_on_idle_timer(Session *s) {
assert(s);
- if (s->manager->stop_idle_session_usec == USEC_INFINITY)
+ if (s->manager->stop_idle_session_usec == USEC_INFINITY || !SESSION_CLASS_CAN_STOP_ON_IDLE(s->class))
return 0;
r = sd_event_add_time_relative(
@@ -804,17 +866,17 @@ int session_start(Session *s, sd_bus_message *properties, sd_bus_error *error) {
user_elect_display(s->user);
/* Save data */
- session_save(s);
- user_save(s->user);
+ (void) session_save(s);
+ (void) user_save(s->user);
if (s->seat)
- seat_save(s->seat);
+ (void) seat_save(s->seat);
/* Send signals */
session_send_signal(s, true);
user_send_changed(s->user, "Display", NULL);
if (s->seat && s->seat->active == s)
- seat_send_changed(s->seat, "ActiveSession", NULL);
+ (void) seat_send_changed(s->seat, "ActiveSession", NULL);
return 0;
}
@@ -900,8 +962,8 @@ int session_stop(Session *s, bool force) {
user_elect_display(s->user);
- session_save(s);
- user_save(s->user);
+ (void) session_save(s);
+ (void) user_save(s->user);
return r;
}
@@ -923,7 +985,6 @@ int session_finalize(Session *s) {
LOG_MESSAGE("Removed session %s.", s->id));
s->timer_event_source = sd_event_source_unref(s->timer_event_source);
- s->leader_pidfd_event_source = sd_event_source_unref(s->leader_pidfd_event_source);
if (s->seat)
seat_evict_position(s->seat, s);
@@ -948,10 +1009,10 @@ int session_finalize(Session *s) {
seat_save(s->seat);
}
- session_reset_leader(s);
+ session_reset_leader(s, /* keep_fdstore = */ false);
- user_save(s->user);
- user_send_changed(s->user, "Display", NULL);
+ (void) user_save(s->user);
+ (void) user_send_changed(s->user, "Display", NULL);
return 0;
}
@@ -1042,19 +1103,21 @@ int session_get_idle_hint(Session *s, dual_timestamp *t) {
return s->idle_hint;
}
- /* For sessions with an explicitly configured tty, let's check its atime */
- if (s->tty) {
- r = get_tty_atime(s->tty, &atime);
- if (r >= 0)
- goto found_atime;
- }
+ if (s->type == SESSION_TTY) {
+ /* For sessions with an explicitly configured tty, let's check its atime */
+ if (s->tty) {
+ r = get_tty_atime(s->tty, &atime);
+ if (r >= 0)
+ goto found_atime;
+ }
- /* For sessions with a leader but no explicitly configured tty, let's check the controlling tty of
- * the leader */
- if (pidref_is_set(&s->leader)) {
- r = get_process_ctty_atime(s->leader.pid, &atime);
- if (r >= 0)
- goto found_atime;
+ /* For sessions with a leader but no explicitly configured tty, let's check the controlling tty of
+ * the leader */
+ if (pidref_is_set(&s->leader)) {
+ r = get_process_ctty_atime(s->leader.pid, &atime);
+ if (r >= 0)
+ goto found_atime;
+ }
}
if (t)
@@ -1081,7 +1144,9 @@ found_atime:
int session_set_idle_hint(Session *s, bool b) {
assert(s);
- if (!SESSION_TYPE_IS_GRAPHICAL(s->type))
+ if (!SESSION_CLASS_CAN_IDLE(s->class)) /* Only some session classes know the idle concept at all */
+ return -ENOTTY;
+ if (!SESSION_TYPE_IS_GRAPHICAL(s->type)) /* And only graphical session types can set the field explicitly */
return -ENOTTY;
if (s->idle_hint == b)
@@ -1107,15 +1172,20 @@ int session_get_locked_hint(Session *s) {
return s->locked_hint;
}
-void session_set_locked_hint(Session *s, bool b) {
+int session_set_locked_hint(Session *s, bool b) {
assert(s);
+ if (!SESSION_CLASS_CAN_LOCK(s->class))
+ return -ENOTTY;
+
if (s->locked_hint == b)
- return;
+ return 0;
s->locked_hint = b;
+ (void) session_save(s);
+ (void) session_send_changed(s, "LockedHint", NULL);
- session_send_changed(s, "LockedHint", NULL);
+ return 1;
}
void session_set_type(Session *s, SessionType t) {
@@ -1125,9 +1195,22 @@ void session_set_type(Session *s, SessionType t) {
return;
s->type = t;
- session_save(s);
+ (void) session_save(s);
+ (void) session_send_changed(s, "Type", NULL);
+}
+
+void session_set_class(Session *s, SessionClass c) {
+ assert(s);
+
+ if (s->class == c)
+ return;
- session_send_changed(s, "Type", NULL);
+ s->class = c;
+ (void) session_save(s);
+ (void) session_send_changed(s, "Class", NULL);
+
+ /* This class change might mean we need the per-user session manager now. Try to start it. */
+ (void) user_start_service_manager(s->user);
}
int session_set_display(Session *s, const char *display) {
@@ -1140,9 +1223,8 @@ int session_set_display(Session *s, const char *display) {
if (r <= 0) /* 0 means the strings were equal */
return r;
- session_save(s);
-
- session_send_changed(s, "Display", NULL);
+ (void) session_save(s);
+ (void) session_send_changed(s, "Display", NULL);
return 1;
}
@@ -1157,9 +1239,8 @@ int session_set_tty(Session *s, const char *tty) {
if (r <= 0) /* 0 means the strings were equal */
return r;
- session_save(s);
-
- session_send_changed(s, "TTY", NULL);
+ (void) session_save(s);
+ (void) session_send_changed(s, "TTY", NULL);
return 1;
}
@@ -1224,41 +1305,7 @@ static void session_remove_fifo(Session *s) {
s->fifo_event_source = sd_event_source_unref(s->fifo_event_source);
s->fifo_fd = safe_close(s->fifo_fd);
-
- if (s->fifo_path) {
- (void) unlink(s->fifo_path);
- s->fifo_path = mfree(s->fifo_path);
- }
-}
-
-static int session_dispatch_leader_pidfd(sd_event_source *es, int fd, uint32_t revents, void *userdata) {
- Session *s = ASSERT_PTR(userdata);
-
- assert(s->leader.fd == fd);
- session_stop(s, /* force= */ false);
-
- return 1;
-}
-
-int session_watch_pidfd(Session *s) {
- int r;
-
- assert(s);
-
- if (s->leader.fd < 0)
- return 0;
-
- r = sd_event_add_io(s->manager->event, &s->leader_pidfd_event_source, s->leader.fd, EPOLLIN, session_dispatch_leader_pidfd, s);
- if (r < 0)
- return r;
-
- r = sd_event_source_set_priority(s->leader_pidfd_event_source, SD_EVENT_PRIORITY_IMPORTANT);
- if (r < 0)
- return r;
-
- (void) sd_event_source_set_description(s->leader_pidfd_event_source, "session-pidfd");
-
- return 0;
+ s->fifo_path = unlink_and_free(s->fifo_path);
}
bool session_may_gc(Session *s, bool drop_not_started) {
@@ -1273,15 +1320,17 @@ bool session_may_gc(Session *s, bool drop_not_started) {
return true;
r = pidref_is_alive(&s->leader);
+ if (r == -ESRCH)
+ /* Session has no leader. This is probably because the leader vanished before deserializing
+ * pidfd from FD store. */
+ return true;
if (r < 0)
- log_debug_errno(r, "Unable to determine if leader PID " PID_FMT " is still alive, assuming not.", s->leader.pid);
+ log_debug_errno(r, "Unable to determine if leader PID " PID_FMT " is still alive, assuming not: %m", s->leader.pid);
if (r > 0)
return false;
- if (s->fifo_fd >= 0) {
- if (pipe_eof(s->fifo_fd) <= 0)
- return false;
- }
+ if (s->fifo_fd >= 0 && pipe_eof(s->fifo_fd) <= 0)
+ return false;
if (s->scope_job) {
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
@@ -1561,7 +1610,7 @@ int session_set_controller(Session *s, const char *sender, bool force, bool prep
session_release_controller(s, true);
s->controller = TAKE_PTR(name);
- session_save(s);
+ (void) session_save(s);
return 0;
}
@@ -1575,7 +1624,7 @@ void session_drop_controller(Session *s) {
s->track = sd_bus_track_unref(s->track);
session_set_type(s, s->original_type);
session_release_controller(s, false);
- session_save(s);
+ (void) session_save(s);
session_restore_vt(s);
}
@@ -1600,10 +1649,15 @@ static const char* const session_type_table[_SESSION_TYPE_MAX] = {
DEFINE_STRING_TABLE_LOOKUP(session_type, SessionType);
static const char* const session_class_table[_SESSION_CLASS_MAX] = {
- [SESSION_USER] = "user",
- [SESSION_GREETER] = "greeter",
- [SESSION_LOCK_SCREEN] = "lock-screen",
- [SESSION_BACKGROUND] = "background",
+ [SESSION_USER] = "user",
+ [SESSION_USER_EARLY] = "user-early",
+ [SESSION_USER_INCOMPLETE] = "user-incomplete",
+ [SESSION_GREETER] = "greeter",
+ [SESSION_LOCK_SCREEN] = "lock-screen",
+ [SESSION_BACKGROUND] = "background",
+ [SESSION_BACKGROUND_LIGHT] = "background-light",
+ [SESSION_MANAGER] = "manager",
+ [SESSION_MANAGER_EARLY] = "manager-early",
};
DEFINE_STRING_TABLE_LOOKUP(session_class, SessionClass);