BuildRequires: pkgconfig(libsmack)
BuildRequires: pkgconfig(dlog)
BuildRequires: pkgconfig(libsyscommon-plugin-api-sessiond)
+
+BuildRequires: pkgconfig(capi-system-info)
+BuildRequires: pkgconfig(libxml-2.0)
+BuildRequires: pkgconfig(pkgmgr-info)
%description
%package -n libsessiond
%{_unitdir}/sessiond.service
%{_datadir}/dbus-1/system-services/org.tizen.system.sessiond.service
/etc/dbus-1/system.d/org.tizen.sessiond.conf
+/etc/package-manager/parserlib/libsessiond-update-skelimg.so
+/usr/share/parser-plugins/sessiond-update-skelimg.info
%files -n libsessiond
%manifest sessiond.manifest
add_subdirectory(common)
add_subdirectory(library)
add_subdirectory(service)
+add_subdirectory(tpkplugin)
sessiond_SRCS
src/main.cpp
src/main_restore.cpp
+ src/main_skel.cpp
src/fs_helpers.cpp
src/os_ops.cpp
src/plugin.cpp
};
struct DirBackendAdd {
- virtual fs::path AddSubsessionPrepare (const fs::path& subsession_path, int uid, int gid) const = 0;
+ virtual fs::path AddSubsessionPrepare (const fs::path& subsession_path, int uid, int gid) const = 0;
+ virtual fs::path AddSubsessionPrepareFromTemplate (const fs::path& subsession_path, const fs::path& main_path, int uid, int gid) const = 0;
virtual void AddSubsessionFinalize (const fs::path& tmpdir_path, const fs::path& subsession_path, int uid, int gid) const = 0;
virtual void AddSubsessionCleanupFailure (const fs::path& tmpdir_path, const fs::path& subsession_path) const = 0;
};
#include <dlog.h>
#include "dir_backend_fixed_size.hpp"
+#include "fs_helpers.hpp"
#include "os_ops.hpp"
#include <sys/mount.h>
return subsession_path;
}
-static void do_mkfs(const fs::path& image_path, int uid, int gid, uint64_t size_kB)
+void do_resize2fs(const fs::path& image_path, uint64_t size_kB)
+{
+ const auto child_pid = OS::throwing_fork();
+ if (child_pid == 0) {
+ const auto cmd = "/usr/sbin/resize2fs"sv;
+
+ std::string size_arg = std::to_string(size_kB);
+
+ execl
+ ( cmd.data(), cmd.data() /* argv[0] convention */
+ , image_path.c_str()
+ , size_arg.c_str()
+ , (char *) NULL
+ );
+
+ _exit(1);
+ } else {
+ OS::throw_if_child_failed(child_pid, "resize2fs failed!");
+ }
+}
+
+void do_mkfs(const fs::path& image_path, int uid, int gid, uint64_t size_kB)
{
const auto child_pid = OS::throwing_fork();
if (child_pid == 0) {
}
}
-static void do_mount(const fs::path& image_path, const fs::path& mount_path)
+void do_mount(const fs::path& image_path, const fs::path& mount_path)
{
/* Don't just call mount() since there's some extra steps involved
* in making it work properly, such as setting up a loop device,
}
}
-static void do_umount(const fs::path& path)
+void do_umount(const fs::path& path)
{
const auto child_pid = OS::throwing_fork();
if (child_pid == 0) {
}
}
+void umount_and_remove (const fs::path& path) try {
+ do_umount(path);
+ fs::remove(path);
+} catch (const std::exception& ex) {
+ LOGE("umount & rmdir (%s) failed!", path.c_str());
+ throw;
+}
+
+fs::path DirBackendAddFixedSize::AddSubsessionPrepareFromTemplate (const fs::path& subsession_path, const fs::path& main_path, int uid, int gid) const
+{
+ fs::path template_path = main_path / ".template";
+
+ auto tmp_subsession_path = subsession_path;
+ tmp_subsession_path.replace_filename(TMP_NEW_PREFIX + subsession_path.filename().native());
+ auto image_template = DirBackendFixedSize::GetImagePathFromSubsessionPath(template_path);
+ auto image_new_tmp = DirBackendFixedSize::GetImagePathFromSubsessionPath(tmp_subsession_path);
+ fs::copy_file (image_template, image_new_tmp);
+ do_resize2fs (image_new_tmp, size_kB);
+
+ try {
+ fs::create_directory(tmp_subsession_path);
+ OS::change_owner_and_group(tmp_subsession_path, uid, gid);
+ } catch (const std::exception& ex) {
+ fs::remove(image_new_tmp);
+ fs::remove(tmp_subsession_path);
+ throw;
+ }
+
+ // We do not really need to mount this image here, so we won't as it will make add_user() slower
+ // Fankly, AddSubsessionPrepare does mount() so it will make switch() faster later on
+ // Thus, this is subject to change
+
+ return tmp_subsession_path;
+}
+
fs::path DirBackendAddFixedSize::AddSubsessionPrepare (const fs::path& subsession_path, int uid, int gid) const
{
/* Work off a temp image first so that the "real" image
try {
fs::create_directory(tmp_subsession_path);
+ OS::change_owner_and_group(tmp_subsession_path, uid, gid);
} catch (const std::exception& ex) {
fs::remove(image_path);
throw;
return tmp_subsession_path;
}
-static void umount_and_remove (const fs::path& path) try {
- do_umount(path);
- fs::remove(path);
-} catch (const std::exception& ex) {
- LOGE("umount & rmdir (%s) failed!", path.c_str());
- throw;
-}
-
void DirBackendAddFixedSize::AddSubsessionCleanupFailure (const fs::path& tmpdir_path, const fs::path& subsession_path) const
{
auto tmp_image_path = DirBackendFixedSize::GetImagePathFromSubsessionPath(subsession_path);
void DirBackendAddFixedSize::AddSubsessionFinalize (const fs::path& tmpdir_path, const fs::path& subsession_path, int uid, int gid) const
{
- umount_and_remove(tmpdir_path);
+ // XXX keep mounts! it should be possible to reuse this dir too!
+ // XXX this is pointless step, need to introduce mount --move
+ // umount_and_remove(tmpdir_path);
+ if (OS::is_mountpoint(tmpdir_path))
+ do_umount(tmpdir_path);
const auto image_path = DirBackendFixedSize::GetImagePathFromSubsessionPath(subsession_path);
- auto temp_image_path = image_path;
- temp_image_path.replace_filename(TMP_NEW_PREFIX + image_path.filename().native());
- fs::rename(temp_image_path, image_path);
+ auto tmp_image_path = image_path;
+ tmp_image_path.replace_filename(TMP_NEW_PREFIX + image_path.filename().native());
/* The image file (as opposed to the FS inside it) doesn't
* really need any rights, and maybe it would even be better
* if it was harder to disrupt. This way all three concepts,
* i.e. the image, the mount dir, and the FS root, are all
* consistent with their rights though. */
- OS::change_owner_and_group(image_path, uid, gid);
+ //LOGI("change_owner_and_group %s %s", tmp_image_path.c_str(), image_path.c_str());
+ OS::change_owner_and_group(tmp_image_path, uid, gid);
/* Order matters - handle .img first and the directory last,
* since all other logic assumes that the existence of the dir
* signifies that a valid subsession exists. */
- fs::create_directory(subsession_path);
+ //fs::create_directory(subsession_path);
+
+ //LOGI("rename %s %s", tmp_image_path.c_str(), image_path.c_str());
+ fs::rename(tmp_image_path, image_path);
+ //LOGI("rename %s %s", tmpdir_path.c_str(), subsession_path.c_str());
+ fs::rename(tmpdir_path, subsession_path);
/* The mountpoint's properties don't actually matter, since
* they are completely replaced with the image filesystem's
* root dir's, but this way they are consistent regardless of
* whether the image is mounted or not. */
- OS::change_owner_and_group(subsession_path, uid, gid);
+ // XXX moved to AddSubsessionPrepare* for dir_backend_fixe - NEED to check dir_regular_dir
+ //OS::change_owner_and_group(subsession_path, uid, gid);
}
void DirBackendFixedSize::RemoveSubsession (const fs::path& subsession_path) const
DirBackendAddFixedSize(uint32_t s) : size_kB(s) { }
fs::path AddSubsessionPrepare (const fs::path& subsession_path, int uid, int gid) const override;
+ fs::path AddSubsessionPrepareFromTemplate (const fs::path& subsession_path, const fs::path& main_path, int uid, int gid) const override;
void AddSubsessionFinalize (const fs::path& tmpdir_path, const fs::path& subsession_path, int uid, int gid) const override;
void AddSubsessionCleanupFailure (const fs::path& tmpdir_path, const fs::path& subsession_path) const override;
};
using namespace std::string_literals;
+fs::path DirBackendAddRegularDir::AddSubsessionPrepareFromTemplate (const fs::path& subsession_path, const fs::path &main_path, int uid, int gid) const
+{
+ throw std::runtime_error("not supported");
+}
+
fs::path DirBackendAddRegularDir::AddSubsessionPrepare (const fs::path& subsession_path, int uid, int gid) const
{
auto tmp_subsession_path = subsession_path;
struct DirBackendAddRegularDir : public DirBackendAdd {
fs::path AddSubsessionPrepare (const fs::path& subsession_path, int uid, int gid) const override;
+ fs::path AddSubsessionPrepareFromTemplate (const fs::path& subsession_path, const fs::path &main_path, int uid, int gid) const override;
void AddSubsessionFinalize (const fs::path& tmpdir_path, const fs::path& subsession_path, int uid, int gid) const override;
void AddSubsessionCleanupFailure (const fs::path& tmpdir_path, const fs::path& subsession_path) const override;
};
namespace fs = std::filesystem;
using namespace std::string_literals;
+using namespace std::string_view_literals;
fs::path get_main_dir_by_user_id(const int uid)
{
throw std::system_error(EEXIST, std::generic_category(),
"Subsession directory already exists");
+ const int system_share_gid = OS::get_gid_from_name(system_share_group);
+ const auto tmp_subsession_path = backend.AddSubsessionPrepareFromTemplate
+ ( subsession_path, main_path, session_uid, system_share_gid );
+ backend.AddSubsessionFinalize(tmp_subsession_path, subsession_path, session_uid, system_share_gid);
+
+ }
+ catch (const std::exception &ex) {
+ LOGE("Logic exception while copying skel from template [session_uid=%d subsession_id=%s]: %s", session_uid, subsession_id.data(), ex.what());
+ return add_user_subsession_inner(session_uid, subsession_id, backend, false);
+ }
+}
+
+void add_user_subsession_inner(const int session_uid, const std::string_view subsession_id, const DirBackendAdd &backend, bool force)
+{
+ try {
+ fs::path main_path = get_main_dir_by_user_id(session_uid);
+
+ create_main_subdirectory(session_uid, main_path);
+
+ fs::path subsession_path = main_path / subsession_id;
+
+ if (fs::exists(subsession_path)) {
+ if (force) {
+ LOGI("Removing old subsession subsession_id=%s in force mode", subsession_id.data());
+ fs::remove_all(subsession_path);
+ } else
+ throw std::system_error(EEXIST, std::generic_category(),
+ "Subsession directory already exists");
+ }
+
const int system_share_gid = OS::get_gid_from_name(system_share_group);
// Work off a temporary dir and then switch it at once so that it appears atomically
LOGE("Exception while enumerating user subsessions [session_uid=%d]: %s", session_uid, ex.what());
throw std::runtime_error("Couldn't enumerate user subsessions");
}
-
std::filesystem::path get_last_subsession_path_by_user_id(const int uid);
bool subsession_exists(const int session_uid, const std::string_view subsession_id);
void add_user_subsession(const int session_uid, const std::string_view subsession_id, const DirBackendAdd& backend);
+void add_user_subsession_inner(const int session_uid, const std::string_view subsession_id, const DirBackendAdd& backend, bool force);
void remove_user_subsession(const int session_uid, const std::string_view subsession_id);
bool switch_user_subsession(const int session_uid, const std::string_view prev_subsession, const std::string_view next_subsession);
std::vector<std::string> get_user_list(const int session_uid);
constexpr static std::string_view main_dir_name = "subsession";
constexpr static std::string_view system_share_group = "system_share";
constexpr static std::string_view main_dir_smack = "User::Home";
+
#include "main_context.hpp"
#include "main_restore.hpp"
+#include "main_skel.hpp"
#include <stdexcept>
std::unique_ptr <sessiond_context> g_sessiond_context;
return std::string_view(argv[1]) == "--restore-only";
}
+
+bool isGenSkel(int argc, char **argv)
+{
+ if (argc < 2)
+ return false;
+
+ return std::string_view(argv[1]) == "--regenerate-skel";
+}
+
+
int main(int argc, char **argv) try {
if (isRestoreOnly(argc, argv)) {
restore_all_user_sessions();
+ } else if (isGenSkel(argc, argv)) {
+ regenerate_skel();
} else {
g_sessiond_context = std::make_unique <sessiond_context> ();
restore_all_user_sessions();
#include <utility>
#undef LOG_TAG
-#define LOG_TAG "SESSIOND"
+#define LOG_TAG "SESSIOND_RESTORE_ONLY"
#include <dlog.h>
using namespace std::string_literals;
--- /dev/null
+#include <filesystem>
+#include <iostream>
+
+#undef LOG_TAG
+#define LOG_TAG "SESSIOND_REGENERATE_SKEL"
+#include <dlog.h>
+
+#include "fs_helpers.hpp"
+#include "os_ops.hpp"
+#include "dir_backend_fixed_size.hpp"
+
+namespace fs = std::filesystem;
+
+using namespace std;
+
+const auto template_img_size_kb = 10240;
+
+int regenerate_skel() {
+
+ int r = 0;
+
+ try {
+ fs::current_path("/opt/usr/home");
+ } catch (std::exception& ex) {
+ std::cerr << "Unable to chdir to HOME. Can not continue" << std::endl;
+ }
+
+ for (auto const& entry : fs::directory_iterator(".")) {
+ if (!fs::is_directory(entry.status()))
+ continue;
+
+ const auto &username = entry.path().filename();
+ const int username_uid = OS::get_uid_from_name(username.string());
+
+ try {
+ add_user_subsession_inner(username_uid, ".template", DirBackendAddFixedSize {template_img_size_kb}, true);
+ } catch (std::exception& ex) {
+ LOGW("Unable to generate skel template for username %s (uid %d): %s", username, username_uid, ex.what());
+ continue;
+ }
+ }
+
+ return r;
+}
--- /dev/null
+/* MIT License
+ *
+ * Copyright (c) 2022 Samsung Electronics Co., Ltd.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is furnished
+ * to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE. */
+
+#pragma once
+
+void regenerate_skel();
--- /dev/null
+FIND_PACKAGE(PkgConfig)
+INCLUDE(GNUInstallDirs)
+
+pkg_check_modules(deps REQUIRED
+ dlog
+ capi-system-info
+ pkgmgr-info
+ )
+
+ADD_LIBRARY(libsessiond-update-skelimg SHARED plugin.c)
+TARGET_COMPILE_OPTIONS(libsessiond-update-skelimg PUBLIC -fPIC ${deps_CFLAGS})
+TARGET_LINK_LIBRARIES(libsessiond-update-skelimg PRIVATE ${deps_LDFLAGS})
+
+INSTALL(TARGETS libsessiond-update-skelimg LIBRARY DESTINATION /etc/package-manager/parserlib/)
+INSTALL(FILES sessiond-update-skelimg.info DESTINATION /usr/share/parser-plugins/)
+
--- /dev/null
+#include <stdio.h>
+#include <dlog.h>
+#include <libxml/parser.h>
+#include <libxml/tree.h>
+#include <pkgmgr-info.h>
+#include <stdlib.h>
+
+#ifndef EXPORT_API
+#define EXPORT_API __attribute__((visibility("default")))
+#endif
+
+#ifdef LOG_TAG
+#undef LOG_TAG
+#endif
+#define LOG_TAG "SESSIOND_GEN_SKEL_IMG"
+
+int gen_skel(void) {
+ // The logic for skel generation is not in plugin to make it possible to call it also manually during image build
+ return system("/usr/sbin/sessiond --regenerate-skel");
+}
+
+EXPORT_API
+int PKGMGR_PARSER_PLUGIN_PRE_INSTALL(const char* packageId)
+{
+ return 0;
+}
+
+EXPORT_API
+int PKGMGR_PARSER_PLUGIN_INSTALL(xmlDocPtr docPtr, const char* packageId)
+{
+ return 0;
+}
+
+EXPORT_API
+int PKGMGR_PARSER_PLUGIN_POST_INSTALL(const char* packageId)
+{
+ SLOGD("Generate sessiond skel image for fast session add - triggered by %s package installation", packageId);
+ return gen_skel();
+}
+
+EXPORT_API
+int PKGMGR_PARSER_PLUGIN_UNINSTALL(xmlDocPtr docPtr, const char* packageId)
+{
+ return 0;
+}
+
+EXPORT_API
+int PKGMGR_PARSER_PLUGIN_PRE_UNINSTALL(const char* packageId)
+{
+ return 0;
+}
+
+EXPORT_API
+int PKGMGR_PARSER_PLUGIN_POST_UNINSTALL(const char* packageId)
+{
+ SLOGD("Generate sessiond skel image for fast session add - triggered by %s package deinstallation", packageId);
+ return gen_skel();
+}
+
+EXPORT_API
+int PKGMGR_PARSER_PLUGIN_PRE_UPGRADE(const char* packageId)
+{
+ return 0;
+}
+
+EXPORT_API
+int PKGMGR_PARSER_PLUGIN_UPGRADE(xmlDocPtr docPtr, const char* packageId)
+{
+ return 0;
+}
+
+EXPORT_API
+int PKGMGR_PARSER_PLUGIN_POST_UPGRADE(const char* packageId)
+{
+ SLOGD("Generate sessiond skel image for fast session add - triggered by %s package upgrade", packageId);
+ return gen_skel();
+}
--- /dev/null
+type="tag";name="sessiond";path="/etc/package-manager/parserlib/libsessiond-update-skelimg.so"