throw std::runtime_error("Bus name lost");
}
+ void save_last_subsession(int uid, std::string_view subsession)
+ {
+ last_subsession_per_session[uid] = subsession;
+
+ try {
+ std::ofstream(get_last_subsession_path_by_user_id(uid), std::ios::out | std::ios::trunc) << subsession;
+ } catch (const std::exception &ex) {
+ LOGE("Count not save last subsession for user %d", uid);
+ }
+ }
+
bool is_subsession_currently_active(int session_uid, const std::string_view subsession_id)
{
std::string_view current_subsession_id = SUBSESSION_INITIAL_SID;
if (!switch_user_subsession(session_uid, prev_subsession_id, next_subsession_id))
return false;
- last_subsession_per_session[session_uid] = next_subsession_id;
-
- try {
- std::ofstream(get_last_subsession_path_by_user_id(session_uid), std::ios::out | std::ios::trunc) << next_subsession_id;
- } catch (const std::exception &ex) {
- LOGE("Count not save last subsession for user %d", session_uid);
- }
+ save_last_subsession(session_uid, next_subsession_id);
wait_switch.try_emplace(session_uid, session_uid, connection, "SwitchUserCompleted");
wait_switch.at(session_uid).on_start(switch_id, { std::string(prev_subsession_id), next_subsession_id });
close(fd);
}
+static std::string get_last_subsession_of_user(int uid)
+{
+ std::string last_subsession;
+ std::ifstream(get_last_subsession_path_by_user_id(uid), std::ios::in) >> last_subsession;
+ return last_subsession;
+}
+
static void restore_user_session(const fs::path& username, int uid)
{
std::string last_subsession;
try {
- std::ifstream(get_last_subsession_path_by_user_id(uid), std::ios::in) >> last_subsession;
+ last_subsession = get_last_subsession_of_user(uid);
} catch (const std::exception &ex) {
LOGE("Could not retrieve last subsession of user %s (uid %d): %s", username.c_str(), uid, ex.what());
try {
switch_user_subsession(uid, SUBSESSION_INITIAL_SID, last_subsession);
if (g_sessiond_context)
- g_sessiond_context->last_subsession_per_session[uid] = last_subsession;
+ g_sessiond_context->save_last_subsession(uid, last_subsession);
} catch (const std::exception &ex) {
LOGE("Could not switch to last subsession %s of user %s (uid %d)", last_subsession.c_str(), username.c_str(), uid);
}
LOGW("Exception while regenerating template subsessions for uid %d: %s", uid, ex.what());
}
+static std::vector <std::pair <int, std::string>> get_restorable_users()
+{
+ /* TODO: skip users such as `root` or `guest`. */
+ return OS::get_all_users();
+}
+
void restore_all_user_sessions(bool restore_only)
{
/* In theory this should live among OS or FS helpers, but
* this happens at early boot so we care about performance
* enough to skip abstractions and do things directly. */
- for (auto const& entry : fs::directory_iterator("/opt/usr/home")) {
- if (!fs::is_directory(entry.status()))
- continue;
-
- const auto& username = entry.path().filename();
- int uid;
- try {
- /* This has to be under a try clause because user
- * name doesn't necessarily map to an existing UID,
- * this can happen e.g. when you install debug rpm
- * packages which leaves some build artifacts under
- * the `abuild` folder which isn't a user on target. */
- uid = OS::get_uid_from_name(username.native());
- } catch (const std::exception &ex) {
- LOGW("Could not get uid of user '%s', skipping", username.c_str());
- continue;
- }
+ for (auto const& [uid, username] : get_restorable_users()) {
/* We rely on all image-based subsessions being mounted to
* make sure that external updates (e.g. when packages are
void regenerate_all_user_templates(void)
{
- for (auto const& entry : fs::directory_iterator("/opt/usr/home")) {
- if (!fs::is_directory(entry.status()))
- continue;
-
- const auto& username = entry.path().filename();
- int uid;
- try {
- uid = OS::get_uid_from_name(username.native());
- } catch (const std::exception &ex) {
- LOGW("Could not get uid of user '%s', skipping", username.c_str());
- continue;
- }
-
+ for (auto const& [uid, username] : get_restorable_users()) {
LOGI("Regenerating template sessions for user %s (uid %d)", username.c_str(), uid);
regenerate_template_sessions(uid);
}
throw std::runtime_error (std::string(message_on_fail));
}
+// not quite the same as "all users", just entries in /home/, but sufficient for us
+static std::vector <std::string> get_all_homies()
+{
+ std::vector <std::string> ret;
+
+ for (auto const& entry : fs::directory_iterator("/opt/usr/home")) {
+ if (!fs::is_directory(entry.status()))
+ continue;
+
+ ret.emplace_back(entry.path().filename().native());
+ }
+
+ return ret;
+}
+
+std::vector <std::pair <int, std::string>> OS::get_all_users()
+{
+ std::vector <std::pair <int, std::string>> ret;
+
+ for (auto homies = get_all_homies(); auto &homie : homies) {
+ try {
+ /* This has to be under a try clause because /home/
+ * entries don't necessarily map to an existing UID,
+ * this can happen e.g. when you install debug rpm
+ * packages which leaves some build artifacts under
+ * the `abuild` folder which isn't a user on target. */
+ const int uid = OS::get_uid_from_name(homie);
+ ret.emplace_back(uid, std::move(homie));
+ } catch (const std::exception &ex) {
+ LOGW("Could not get uid of user '%s', skipping", homie.c_str());
+ }
+ }
+
+ return ret;
+}
+
std::string OS::get_home_dir_by_user_id(const int uid)
{
auto buffer = allocate_sysconf_buffer(_SC_GETPW_R_SIZE_MAX);