set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -fPIE -Wno-error=shadow -Werror=missing-field-initializers")
set(CMAKE_EXE_LINKER_FLAGS "-Wl,--as-needed -pie")
+add_subdirectory(common)
add_subdirectory(libsessiond)
add_subdirectory(sessiond)
--- /dev/null
+set(
+ sessiond_common_SRCS
+)
+
+add_library(sessiond_common INTERFACE)
+target_include_directories(sessiond_common INTERFACE include/ ${CMAKE_SOURCE_DIR}/libsessiond/include/)
+
+install(TARGETS sessiond_common)
--- /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
+
+#include "sessiond.h"
+
+#ifdef __cplusplus
+
+/* Our toolchain doesn't support `std::span` for some reason, so to make it
+ * easier to work with this array in C++ we make it into a proper container
+ * instead of wrapping over the oldschool C-style array.
+ *
+ * The price is that the C and C++ versions cannot be used alongside each other
+ * for linker reasons, but since this is an internal file it's acceptable.
+ *
+ * Ideally the messages would be `std::string_view`, but I couldn't get it
+ * to work with the macro. This is fine since the main use case so far wants
+ * C style strings anyway. */
+
+#include <array>
+#include <utility>
+
+#define MP(x, y) std::make_pair(x, y)
+
+static constexpr std::array error_mappings =
+
+#else
+typedef struct {
+ const char *dbus_error_msg;
+ int code;
+} error_mapping_t;
+
+#define MP(x, y) {x, y}
+
+static error_mapping_t error_mappings [] =
+
+#endif
+ { MP("org.tizen.sessiond.Error.InvalidParameter" , SUBSESSION_ERROR_INVALID_PARAMETER)
+ , MP("org.tizen.sessiond.Error.IOError" , SUBSESSION_ERROR_IO_ERROR )
+ , MP("org.tizen.sessiond.Error.SubsessionAlreadyExists", SUBSESSION_ERROR_ALREADY_EXISTS )
+ , MP("org.tizen.sessiond.Error.SubsessionDoesNotExist" , SUBSESSION_ERROR_NOT_AVAILABLE )
+ , MP("org.tizen.sessiond.Error.UserIsActive" , SUBSESSION_ERROR_RESOURCE_BUSY )
+};
+
+#undef MP
src/lib.c
)
add_library(libsessiond SHARED ${libsessiond_SRCS})
-target_link_libraries(libsessiond PRIVATE PkgConfig::DEPS)
+target_link_libraries(libsessiond PRIVATE PkgConfig::DEPS sessiond_common)
target_include_directories(libsessiond PUBLIC include)
set_target_properties(
libsessiond PROPERTIES
+++ /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
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-typedef struct {
- const char *dbus_error_msg;
- int code;
-} error_mapping_t;
-
-static error_mapping_t error_mappings[] = {
- { "org.tizen.sessiond.Error.InvalidParameter", SUBSESSION_ERROR_INVALID_PARAMETER },
- { "org.tizen.sessiond.Error.IOError", SUBSESSION_ERROR_IO_ERROR },
- { "org.tizen.sessiond.Error.SubsessionAlreadyExists", SUBSESSION_ERROR_ALREADY_EXISTS },
- { "org.tizen.sessiond.Error.SubsessionDoesNotExist", SUBSESSION_ERROR_NOT_AVAILABLE },
- { "org.tizen.sessiond.Error.UserIsActive", SUBSESSION_ERROR_RESOURCE_BUSY },
-};
-
-#ifdef __cplusplus
-}
-#endif
* @since_tizen 7.0
*/
typedef enum {
- SUBSESSION_ERROR_NONE = TIZEN_ERROR_NONE, /**< Successful */
- SUBSESSION_ERROR_INVALID_PARAMETER = TIZEN_ERROR_INVALID_PARAMETER, /**< Invalid parameter */
- SUBSESSION_ERROR_IO_ERROR = TIZEN_ERROR_IO_ERROR, /**< I/O error */
- SUBSESSION_ERROR_OUT_OF_MEMORY = TIZEN_ERROR_OUT_OF_MEMORY, /**< Out of memory */
- SUBSESSION_ERROR_ALREADY_EXISTS = TIZEN_ERROR_FILE_EXISTS, /**< Resource already registered */
- SUBSESSION_ERROR_NOT_AVAILABLE = TIZEN_ERROR_NO_SUCH_DEVICE, /**< Resource unavailable */
- SUBSESSION_ERROR_RESOURCE_BUSY = TIZEN_ERROR_RESOURCE_BUSY, /**< Resource busy */
- SUBSESSION_ERROR_PERMISSION_DENIED = TIZEN_ERROR_PERMISSION_DENIED, /**< Permission denied */
- SUBSESSION_ERROR_NOT_SUPPORTED = TIZEN_ERROR_NOT_SUPPORTED, /**< Not supported */
+ SUBSESSION_ERROR_NONE = TIZEN_ERROR_NONE, /**< Successful */
+ SUBSESSION_ERROR_INVALID_PARAMETER = TIZEN_ERROR_INVALID_PARAMETER, /**< Invalid parameter */
+ SUBSESSION_ERROR_IO_ERROR = TIZEN_ERROR_IO_ERROR, /**< I/O error */
+ SUBSESSION_ERROR_OUT_OF_MEMORY = TIZEN_ERROR_OUT_OF_MEMORY, /**< Out of memory */
+ SUBSESSION_ERROR_ALREADY_EXISTS = TIZEN_ERROR_FILE_EXISTS, /**< Resource already registered */
+ SUBSESSION_ERROR_NOT_AVAILABLE = TIZEN_ERROR_NO_SUCH_DEVICE, /**< Resource unavailable */
+ SUBSESSION_ERROR_RESOURCE_BUSY = TIZEN_ERROR_RESOURCE_BUSY, /**< Resource busy */
+ SUBSESSION_ERROR_PERMISSION_DENIED = TIZEN_ERROR_PERMISSION_DENIED, /**< Permission denied */
+ SUBSESSION_ERROR_NOT_SUPPORTED = TIZEN_ERROR_NOT_SUPPORTED, /**< Not supported */
} subsession_error_e;
typedef enum {
)
add_executable(sessiond ${sessiond_SRCS})
target_compile_features(sessiond PUBLIC cxx_std_20)
-target_link_libraries(sessiond PRIVATE PkgConfig::DEPS)
+target_link_libraries(sessiond PRIVATE PkgConfig::DEPS sessiond_common)
install(TARGETS sessiond)
INSTALL(FILES sessiond.service DESTINATION /usr/lib/systemd/system)
#include "tuple_hash.hpp"
#include "wait_manager.hpp"
+#include "sessiond-internal.h"
+
+static constexpr const char * get_dbus_error_mapping (subsession_error_e subsession_error)
+{
+ /* I want this function to be evaluated at compile time
+ * and `std::find_if` is not constexpr/consteval-friendly,
+ * so caveman style iteration it is. */
+
+ const char *ret = nullptr;
+ for (const auto & x : error_mappings)
+ if (x.second == subsession_error)
+ ret = x.first;
+
+ return ret ?: throw std::logic_error("Compile time get_dbus_error_mapping error");
+}
+
using namespace std::string_view_literals;
struct introspection_data {
{
if (session_uid <= 0) {
g_dbus_method_invocation_return_dbus_error(invocation,
- sessiond_errors[DBUS_ERROR_INVALID_PARAMETER].second.data(), "Negative UID passed");
+ get_dbus_error_mapping(SUBSESSION_ERROR_INVALID_PARAMETER), "Negative UID passed");
return true;
}
if (subsession_id <= 0) {
g_dbus_method_invocation_return_dbus_error(invocation,
- sessiond_errors[DBUS_ERROR_INVALID_PARAMETER].second.data(), "Negative subsession_id passed");
+ get_dbus_error_mapping(SUBSESSION_ERROR_INVALID_PARAMETER), "Negative subsession_id passed");
return true;
}
current_subsession_id = last_subsession_per_session.at(session_uid);
if (subsession_id == current_subsession_id) {
g_dbus_method_invocation_return_dbus_error(invocation,
- sessiond_errors[DBUS_ERROR_RESOURCE_BUSY].second.data(), "Cannot remove currently active user");
+ get_dbus_error_mapping(SUBSESSION_ERROR_RESOURCE_BUSY), "Cannot remove currently active user");
return;
}
if (session_uid <= 0) {
g_dbus_method_invocation_return_dbus_error(invocation,
- sessiond_errors[DBUS_ERROR_INVALID_PARAMETER].second.data(), "Negative UID passed");
+ get_dbus_error_mapping(SUBSESSION_ERROR_INVALID_PARAMETER), "Negative UID passed");
return;
}
// N.B. Switch to user '0' is possible and it means no subsession is currently active
if (next_subsession_id < 0) {
g_dbus_method_invocation_return_dbus_error(invocation,
- sessiond_errors[DBUS_ERROR_INVALID_PARAMETER].second.data(), "Negative subsession_id passed");
+ get_dbus_error_mapping(SUBSESSION_ERROR_INVALID_PARAMETER), "Negative subsession_id passed");
return;
}
if (next_subsession_id > 0 && !fs_helpers::subsession_exists(session_uid, next_subsession_id)) {
g_dbus_method_invocation_return_dbus_error(invocation,
- sessiond_errors[DBUS_ERROR_NOT_AVAILABLE].second.data(), "Subsession does not exist");
+ get_dbus_error_mapping(SUBSESSION_ERROR_NOT_AVAILABLE), "Subsession does not exist");
return;
}
if (session_uid <= 0) {
g_dbus_method_invocation_return_dbus_error(invocation,
- sessiond_errors[DBUS_ERROR_INVALID_PARAMETER].second.data(), "Negative UID passed");
+ get_dbus_error_mapping(SUBSESSION_ERROR_INVALID_PARAMETER), "Negative UID passed");
return;
}
if (session_uid <= 0) {
g_dbus_method_invocation_return_dbus_error(invocation,
- sessiond_errors[DBUS_ERROR_INVALID_PARAMETER].second.data(), "Negative UID passed");
+ get_dbus_error_mapping(SUBSESSION_ERROR_INVALID_PARAMETER), "Negative UID passed");
return;
}
if (session_uid <= 0) {
g_dbus_method_invocation_return_dbus_error(invocation,
- sessiond_errors[DBUS_ERROR_INVALID_PARAMETER].second.data(), "Negative UID passed");
+ get_dbus_error_mapping(SUBSESSION_ERROR_INVALID_PARAMETER), "Negative UID passed");
return;
}
if (session_uid <= 0) {
g_dbus_method_invocation_return_dbus_error(invocation,
- sessiond_errors[DBUS_ERROR_INVALID_PARAMETER].second.data(), "Negative UID passed");
+ get_dbus_error_mapping(SUBSESSION_ERROR_INVALID_PARAMETER), "Negative UID passed");
return;
}
if (session_uid <= 0) {
g_dbus_method_invocation_return_dbus_error(invocation,
- sessiond_errors[DBUS_ERROR_INVALID_PARAMETER].second.data(), "Negative UID passed");
+ get_dbus_error_mapping(SUBSESSION_ERROR_INVALID_PARAMETER), "Negative UID passed");
return;
}
if (session_uid <= 0) {
g_dbus_method_invocation_return_dbus_error(invocation,
- sessiond_errors[DBUS_ERROR_INVALID_PARAMETER].second.data(), "Negative UID passed");
+ get_dbus_error_mapping(SUBSESSION_ERROR_INVALID_PARAMETER), "Negative UID passed");
return;
}
(self->*(to_call->second))(invocation, std::string_view(sender), parameters);
} catch (const std::invalid_argument &ex) {
g_dbus_method_invocation_return_dbus_error(invocation,
- sessiond_errors[DBUS_ERROR_INVALID_PARAMETER].second.data(), ex.what());
+ get_dbus_error_mapping(SUBSESSION_ERROR_INVALID_PARAMETER), ex.what());
log_exception(ex, sender, method_name);
} catch (const std::system_error &ex) {
switch (ex.code().value()) {
case EEXIST:
g_dbus_method_invocation_return_dbus_error(invocation,
- sessiond_errors[DBUS_ERROR_ALREADY_EXISTS].second.data(), ex.what());
+ get_dbus_error_mapping(SUBSESSION_ERROR_ALREADY_EXISTS), ex.what());
break;
case ENOENT:
g_dbus_method_invocation_return_dbus_error(invocation,
- sessiond_errors[DBUS_ERROR_NOT_AVAILABLE].second.data(), ex.what());
+ get_dbus_error_mapping(SUBSESSION_ERROR_NOT_AVAILABLE), ex.what());
break;
default:
g_dbus_method_invocation_return_dbus_error(invocation,
- sessiond_errors[DBUS_ERROR_IO_ERROR].second.data(),
+ get_dbus_error_mapping(SUBSESSION_ERROR_IO_ERROR),
(std::string("Unable to complete requested operation: ") + ex.what()).c_str());
break;
}
log_exception(ex, sender, method_name);
} catch (const std::runtime_error &ex) {
g_dbus_method_invocation_return_dbus_error(invocation,
- sessiond_errors[DBUS_ERROR_IO_ERROR].second.data(),
+ get_dbus_error_mapping(SUBSESSION_ERROR_IO_ERROR),
(std::string("Unable to complete requested operation: ") + ex.what()).c_str());
log_exception(ex, sender, method_name);
// Swallow the exception; the show must go on
DBUS_ERROR_RESOURCE_BUSY,
};
- constexpr static std::array sessiond_errors = {
- std::make_pair(DBUS_ERROR_INVALID_PARAMETER, "org.tizen.sessiond.Error.InvalidParameter"sv),
- std::make_pair(DBUS_ERROR_IO_ERROR, "org.tizen.sessiond.Error.IOError"sv),
- std::make_pair(DBUS_ERROR_ALREADY_EXISTS, "org.tizen.sessiond.Error.SubsessionAlreadyExists"sv),
- std::make_pair(DBUS_ERROR_NOT_AVAILABLE, "org.tizen.sessiond.Error.SubsessionDoesNotExist"sv),
- std::make_pair(DBUS_ERROR_RESOURCE_BUSY, "org.tizen.sessiond.Error.UserIsActive"sv),
- };
-
// TODO: Currently, the first parameter is always a single-element tuple.
// Consider simplifying wait_manager.
// N.B. Although GLib is multi-threaded, the following data structures do not need