diff --git a/.gitignore b/.gitignore index e7c2d04..c8550a3 100644 --- a/.gitignore +++ b/.gitignore @@ -139,4 +139,5 @@ m4/lt~obsolete.m4 # can automatically generate from config.status script # (which is called by configure script)) Makefile - +.vscode +build \ No newline at end of file diff --git a/README.md b/README.md index ae5c3d7..cd8672a 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,31 @@ # diya-session-manager +## Running the daemon + +By default, the daemon will look for this file in the following locations `/etc/diya/daemon.conf` +or it can be specified using the -c option: + +``` +diya-session-manager -c /path/to/daemon.conf +``` +Example of configuration file can be found in `conf/daemon.conf` + +As the session manager daemon listens on Dbus system bus,to run the daemon: +- the variable environment `DBUS_SYSTEM_BUS_ADDRESS` shall be set and known by the daemon + e.g. `DBUS_SYSTEM_BUS_ADDRESS=unix:path=/run/dbus/system_bus_socket` +- the bus policy shall be configured correctly in `/etc/dbus-1/system.d/` to allow or deny user + accessing tothe bus. See `conf/diya-dbus.conf` as an example of bus policy configuration + +## test with dbus-send + +```sh +#introspect +dbus-send --system --print-reply --reply-timeout=2000 --type=method_call --dest=dev.iohub.diya.SessionManager /dev/iohub/diya/SessionManager org.freedesktop.DBus.Introspectable.Introspect + +# monitor the bus +dbus-monitor --system "path=/dev/iohub/diya/SessionManager" + + +# request user login +dbus-send --system --type=method_call --print-reply --dest=dev.iohub.diya.SessionManager /dev/iohub/diya/SessionManager dev.iohub.diya.SessionManager.login string:toto string:tata +``` \ No newline at end of file diff --git a/conf/daemon.conf b/conf/daemon.conf new file mode 100644 index 0000000..dcda051 --- /dev/null +++ b/conf/daemon.conf @@ -0,0 +1,24 @@ +# this file is the configuration file for the SessionMaganer daemon +# daemon +# By default, the daemon will look for this file in the following locations +# /etc/diya/daemon.conf +# or it can be specified using the -c option +# example: diya-session-manager -c /path/to/daemon.conf + +# Login session command +# The command to run to start a login session +# this command will handle the user input and send user +# credentials to the daemon via Dbus message +login_session_command = /usr/bin/diya-login-shell + +# login session user +# The user that owns the login session, root by default +# if this setting is not set +login_session_user = xdg + +# User session command +# The command to run to start a user session after the +# login session is successful +# the logged in user will own this session + +user_session_command = /usr/bin/diya-shell \ No newline at end of file diff --git a/conf/diya-dbus.conf b/conf/diya-dbus.conf new file mode 100644 index 0000000..a118ce7 --- /dev/null +++ b/conf/diya-dbus.conf @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/meson.build b/meson.build new file mode 100644 index 0000000..a5d0f08 --- /dev/null +++ b/meson.build @@ -0,0 +1,38 @@ +project('diya-session-manager', + ['c'], + version: '0.1.0', + license: 'MIT', + meson_version: '>=0.58.0', + default_options: ['c_std=gnu11', 'warning_level=3']) + +lib_so_version = '0' + +glib = dependency('glib-2.0') +gobject = dependency('gobject-2.0') +gio = dependency('gio-2.0') +crypt = dependency('libcrypt') +add_project_arguments( + [ + '-Wno-pedantic', + '-Werror=implicit-function-declaration', + '-Werror=return-type', + ], + language: 'c') + + +gnome=import('gnome') +resources = gnome.compile_resources('resources','resources/gresource.xml') + + +src = [ + 'src/main.c', + 'src/configuration.c', + 'src/manager.c', + 'src/base.c', + resources +] + +executable( + 'diya-session-manager', + src, + dependencies: [glib, gobject, gio, crypt]) \ No newline at end of file diff --git a/resources/gresource.xml b/resources/gresource.xml new file mode 100644 index 0000000..e97407b --- /dev/null +++ b/resources/gresource.xml @@ -0,0 +1,6 @@ + + + + resources/introspection.xml + + \ No newline at end of file diff --git a/resources/introspection.xml b/resources/introspection.xml new file mode 100644 index 0000000..977b9be --- /dev/null +++ b/resources/introspection.xml @@ -0,0 +1,10 @@ + + + + + + + + + + \ No newline at end of file diff --git a/src/base.c b/src/base.c new file mode 100644 index 0000000..e92c8f3 --- /dev/null +++ b/src/base.c @@ -0,0 +1,46 @@ +#include "base.h" + +G_DEFINE_ABSTRACT_TYPE(BaseObject, base_object, G_TYPE_OBJECT) + +/** + * @brief Dispose the object + */ +static void base_object_dispose(GObject* object) +{ + g_debug("base_object_dispose"); + G_OBJECT_CLASS (base_object_parent_class)->dispose(object); +} + +/** + * @brief Class initialization + */ +static void base_object_class_init(BaseObjectClass *class) +{ + GObjectClass *gobject_class = G_OBJECT_CLASS(class); + class->to_string = NULL; + gobject_class->dispose = base_object_dispose; +} + +/** + * @brief Object initialization + */ +static void base_object_init(BaseObject *self) +{ + (void) self; +} + +/** + * @brief Get the string representation of the object + */ +const gchar* base_object_to_string(gpointer object) +{ + g_return_val_if_fail(BASE_IS_OBJECT(object), NULL); + BaseObject *self = BASE_OBJECT(object); + BaseObjectClass *class = BASE_OBJECT_GET_CLASS(self); + if (class->to_string) + { + g_debug("calling to_string"); + return class->to_string(self); + } + return "BaseObject"; +} \ No newline at end of file diff --git a/src/base.h b/src/base.h new file mode 100644 index 0000000..7827343 --- /dev/null +++ b/src/base.h @@ -0,0 +1,23 @@ +#ifndef BASE_H +#define BASE_H +#include + +/** + * Base class object + * + */ +#define BASE_TYPE_OBJECT (base_object_get_type()) +G_DECLARE_DERIVABLE_TYPE(BaseObject, base_object, BASE, OBJECT, GObject) + +struct _BaseObjectClass +{ + GObjectClass parent_class; + const gchar *(*to_string)(BaseObject *self); + /** + * @brief reserve for future use to + * define common API for descendants + */ +}; + +const gchar *base_object_to_string(gpointer object); +#endif \ No newline at end of file diff --git a/src/configuration.c b/src/configuration.c new file mode 100644 index 0000000..6a9cca1 --- /dev/null +++ b/src/configuration.c @@ -0,0 +1,268 @@ +#include "configuration.h" +#include +#include +#include + +#define DEFAULT_LOGIN_SESSION_USER "root" + +/** + * @brief Object properties enumeration + */ +enum +{ + NO_PROP, + DAEMON_LOGIN_SESSION_COMMAND, + DAEMON_LOGIN_SESSION_USER, + DAEMON_SESSION_COMMAND, + N_PROPERTIES +}; +static GParamSpec *conf_properties[N_PROPERTIES] = {0}; + +/** + * @brief Object private structure + */ +struct _DaemonConfiguration +{ + BaseObject parent_object; + gchar* login_session_command; + gchar* login_session_user; + gchar* session_command; + gchar* string; +}; + +G_DEFINE_FINAL_TYPE(DaemonConfiguration, daemon_configuration, BASE_TYPE_OBJECT) + +/** + * @brief Dispose the object + */ +static void daemon_configuration_dispose(GObject* object) +{ + DaemonConfiguration * self = DAEMON_CONFIGURATION(object); + g_debug("daemon_configuration_dispose: %s", base_object_to_string(self)); + if(self->login_session_command) + { + g_free(self->login_session_command); + } + if(self->login_session_user) + { + g_free(self->login_session_user); + } + if(self->session_command) + { + g_free(self->session_command); + } + if(self->string) + { + g_free(self->string); + } + self->string = NULL; + G_OBJECT_CLASS(daemon_configuration_parent_class)->dispose(object); +} +/** + * @brief Set the object property + */ +static void daemon_configuration_set_property(GObject *object, guint property_id, const GValue *value, GParamSpec *pspec) +{ + (void)object; + (void)value; + (void)pspec; + // DaemonConfiguration * self = DAEMON_CONFIGURATION(object); + switch (property_id) + { + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + break; + } +} + +/** + * @brief Get the object property + */ +static void daemon_configuration_get_property(GObject *object, guint property_id, GValue *value, GParamSpec *pspec) +{ + DaemonConfiguration * self = DAEMON_CONFIGURATION(object); + switch (property_id) + { + case DAEMON_LOGIN_SESSION_COMMAND: + g_value_set_string(value, self->login_session_command); + break; + case DAEMON_LOGIN_SESSION_USER: + g_value_set_string(value, self->login_session_user); + break; + case DAEMON_SESSION_COMMAND: + g_value_set_string(value, self->session_command); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + break; + } +} + +/** + * @brief Get the string representation of the object + */ +static const gchar* daemon_configuration_to_string(BaseObject* object) +{ + g_debug("Call daemon_configuration_to_string"); + DaemonConfiguration* self = DAEMON_CONFIGURATION(object); + return self->string; +} + +/** + * @brief Class initialization + */ +static void daemon_configuration_class_init(DaemonConfigurationClass *class) +{ + GObjectClass *gobject_class = G_OBJECT_CLASS(class); + BaseObjectClass *base_class = BASE_OBJECT_CLASS(class); + + gobject_class->dispose = daemon_configuration_dispose; + gobject_class->set_property = daemon_configuration_set_property; + gobject_class->get_property = daemon_configuration_get_property; + + base_class->to_string = daemon_configuration_to_string; + + conf_properties[DAEMON_LOGIN_SESSION_COMMAND] = g_param_spec_string("login-session-command", NULL, "Login session command", NULL, G_PARAM_READABLE); + conf_properties[DAEMON_LOGIN_SESSION_USER] = g_param_spec_string("login-session-user", NULL, "Login session user", NULL, G_PARAM_READABLE); + conf_properties[DAEMON_SESSION_COMMAND] = g_param_spec_string("session-command", NULL, "Session command", NULL, G_PARAM_READABLE); + g_object_class_install_properties (gobject_class, N_PROPERTIES, conf_properties); +} + +/** + * @brief Object initialization + */ +static void daemon_configuration_init(DaemonConfiguration *self) +{ + self->login_session_command = NULL; + self->login_session_user = NULL; + self->session_command = NULL; + self->string = NULL; +} +/** + * @brief Create a new DaemonConfiguration object + * + * read and parse the config_file + * The format of the config file is as follows: + * - line starting with # are comments and should be ignored + * - line starting with login_session_command= is the command to start the login session + * - line starting with login_session_user= is the user to start the login session + * - line starting with session_command= is the command to start the session + * + * @param config_file The path to the configuration file + * @return The DaemonConfiguration object + */ +DaemonConfiguration* daemon_configuration_new(const gchar* config_file) +{ + FILE* file = fopen(config_file, "r"); + if(!file) + { + g_critical("Error opening the configuration file %s: %s", config_file, strerror(errno)); + return NULL; + } + /** + * read file line by line + */ + DaemonConfiguration* conf = g_object_new(DAEMON_TYPE_CONFIGURATION, NULL); + char* line = NULL; + ssize_t read; + gchar* ptr = NULL; + int conf_valid = 0; + size_t len = 0; + conf->string = g_strconcat("DaemonConfiguration from ", + config_file, + ":\n", + NULL); + ptr = conf->string; + while ((read = getline(&line, &len, file)) != -1) + { + if (line[0] == '#') + { + free(line); + line = NULL; + continue; + } + /** + * strip newline at the end + */ + if (line[read - 1] == '\n') + { + line[read - 1] = '\0'; + } + /** + * parse line using strok + */ + char* value = NULL; + char* key = strtok_r(line, "=", &value); + if(!key || !value) + { + free(line); + line = NULL; + continue; + } + /** + * strim key and value at the begin and the end + */ + while(*key == ' ') + { + key++; + } + char* end = key + strlen(key) - 1; + while(*end == ' ') + { + *end = '\0'; + end--; + } + while(*value == ' ') + { + value++; + } + end = value + strlen(value) - 1; + while(*end == ' ') + { + *end = '\0'; + end--; + } + conf_valid = 1; + if (strncmp(key, "login_session_command", 22) == 0) + { + conf->login_session_command = g_strdup(value); + } + else if (strncmp(key, "login_session_user", 19) == 0) + { + conf->login_session_user = g_strdup(value); + } + else if (strncmp(key, "user_session_command", 21) == 0) + { + conf->session_command = g_strdup(value); + } + else + { + g_warning("Ignore unknown configuration: [%s]:[%s]", key, value); + conf_valid = 0; + } + if(conf_valid) + { + conf->string = g_strconcat(ptr, " - ", key, ": ", value, "\n", NULL); + g_free(ptr); + ptr = conf->string; + } + free(line); + line = NULL; + } + if(line) + { + free(line); + } + fclose(file); + if(conf->login_session_user == NULL) + { + conf->login_session_user = g_strdup("root"); + } + if(conf->login_session_command == NULL || conf->session_command == NULL) + { + g_critical("login_session_command or session_command is not set in the configuration file"); + g_object_unref(conf); + return NULL; + } + return conf; +} \ No newline at end of file diff --git a/src/configuration.h b/src/configuration.h new file mode 100644 index 0000000..bc27015 --- /dev/null +++ b/src/configuration.h @@ -0,0 +1,10 @@ +#ifndef CONFIGURATION_H +#define CONFIGURATION_H +#include "base.h" + +#define DAEMON_TYPE_CONFIGURATION (daemon_configuration_get_type()) +G_DECLARE_FINAL_TYPE(DaemonConfiguration, daemon_configuration, DAEMON, CONFIGURATION, BaseObject) + +DaemonConfiguration* daemon_configuration_new(const gchar* config_file); + +#endif \ No newline at end of file diff --git a/src/main.c b/src/main.c new file mode 100644 index 0000000..a0aeadc --- /dev/null +++ b/src/main.c @@ -0,0 +1,93 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +#include "manager.h" +#include "configuration.h" + +#define DEFALT_CONF_FILE "/etc/diya/daemon.conf" + +static gchar **g_shell_argv; + +static void help(const char* name) +{ + printf("Usage: %s [-c config_file]\n" ,name); +} + +static gboolean restart(gpointer d) +{ + (void)d; + gint i, fdlimit; + + fdlimit = (int)sysconf(_SC_OPEN_MAX); + g_debug("reload: closing fd's %d to %d", STDERR_FILENO + 1, fdlimit); + for (i = STDERR_FILENO + 1; i < fdlimit; i++) + { + fcntl(i, F_SETFD, FD_CLOEXEC); + } + g_debug("reload: exec: %s", g_shell_argv[0]); + execvp(g_shell_argv[0], g_shell_argv); + exit(1); + return FALSE; +} + +static gboolean quit(gpointer d) +{ + g_debug("Quit the daemon"); + session_manager_event_loop_stop((SessionManager*)d); + return TRUE; +} + +int main(int argc, char* const *argv) +{ + /** + * Read command line arguments using getopt: + * - if the argument is -h or --help print the help message + * - if the argument is -c or --config set the configuration file + */ + const gchar* config_file = DEFALT_CONF_FILE; + int opt; + while ((opt = getopt(argc, argv, "hc:")) != -1) + { + switch (opt) + { + case 'h': + help(argv[0]); + return 0; + case 'c': + config_file = optarg; + break; + default: + help(argv[0]); + return 1; + } + } + g_shell_argv = g_malloc0(sizeof(gchar *) * (argc + 1)); + for (int i = 0; i < argc; i++) + { + g_shell_argv[i] = argv[i]; + } + SessionManager* manager = session_manager_new(config_file); + if (!manager) + { + g_error("Error creating the session manager"); + return -1; + } + g_unix_signal_add(SIGHUP, (GSourceFunc)restart, NULL); + g_unix_signal_add(SIGINT,(GSourceFunc)quit,(void*)manager); + DaemonConfiguration* conf = NULL; + g_object_get(manager, "configuration", &conf, NULL); + if(conf) + { + g_debug("Run daemon with: %s", base_object_to_string(conf)); + } + session_manager_event_loop_start(manager); + g_debug("Release the manager"); + g_object_unref(manager); + return 0; +} diff --git a/src/manager.c b/src/manager.c new file mode 100644 index 0000000..18fd2c8 --- /dev/null +++ b/src/manager.c @@ -0,0 +1,327 @@ +#include "manager.h" +#include "configuration.h" +#include +#include +#include +#include + +#define DBUS_SERVER_NAME "dev.iohub.diya.SessionManager" +#define DBUS_SERVER_PATH "/dev/iohub/diya/SessionManager" +#define DBUS_SERVER_ERROR_NAME "dev.iohub.diya.SessionManager.Error" +/** + * @brief Object properties enumeration + */ +enum +{ + SESSION_MANAGER_NO_PROP, + SESSION_MANAGER_CONFIGURATION, + N_PROPERTIES +}; + +static GParamSpec *manager_properties[N_PROPERTIES] = {0}; + +/** + * @brief Object private structure + */ +struct _SessionManager +{ + BaseObject parent_object; + DaemonConfiguration *configuration; + pid_t session_pid; + pid_t login_session_pid; + GMainLoop *loop; + GDBusNodeInfo *introspection; + guint bus_id; +}; + +G_DEFINE_FINAL_TYPE(SessionManager, session_manager, BASE_TYPE_OBJECT); + +/** + * @brief Dispose the object + */ +static void session_manager_dispose(GObject *object) +{ + SessionManager *self = SESSION_MANAGER(object); + g_debug("session_manager_dispose: %s", base_object_to_string(self)); + if (self->configuration) + { + g_object_unref(self->configuration); + } + if (self->loop) + { + g_main_loop_unref(self->loop); + } + if (self->introspection) + { + g_dbus_node_info_unref(self->introspection); + } + if (self->bus_id > 0) + { + g_bus_unown_name(self->bus_id); + } + G_OBJECT_CLASS(session_manager_parent_class)->dispose(object); +} + +/** + * @brief Get the string representation of the object + */ +static const gchar *session_manager_to_string(BaseObject *object) +{ + (void)object; + // SessionManager* self = SESSION_MANAGER(object); + return "SessionManager"; +} + +/** + * @brief Get the object property + */ +static void session_manager_get_property(GObject *object, guint property_id, GValue *value, GParamSpec *pspec) +{ + SessionManager *self = SESSION_MANAGER(object); + switch (property_id) + { + case SESSION_MANAGER_CONFIGURATION: + g_value_set_pointer(value, self->configuration); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, pspec); + break; + } +} + +/** + * @brief Class initialization + */ +static void session_manager_class_init(SessionManagerClass *class) +{ + GObjectClass *gobject_class = G_OBJECT_CLASS(class); + BaseObjectClass *base_class = BASE_OBJECT_CLASS(class); + gobject_class->dispose = session_manager_dispose; + gobject_class->get_property = session_manager_get_property; + + base_class->to_string = session_manager_to_string; + + manager_properties[SESSION_MANAGER_CONFIGURATION] = g_param_spec_pointer("configuration", NULL, "Configuration", G_PARAM_READABLE); + g_object_class_install_properties(gobject_class, N_PROPERTIES, manager_properties); +} + +/** + * @brief Object initialization + */ +static void session_manager_init(SessionManager *self) +{ + self->configuration = NULL; + self->session_pid = 0; + self->login_session_pid = 0; + self->loop = g_main_loop_new(NULL, FALSE); + self->introspection = NULL; + self->bus_id = 0; +} + +static gboolean session_user_auth(const char *username, const char *password) +{ + char *encrypted; + struct passwd *pwd; + struct spwd *spwd; + /* Look up password and shadow password records for username */ + pwd = getpwnam(username); + if (pwd == NULL) + { + g_critical("getpwnam: %s", strerror(errno)); + return FALSE; + } + spwd = getspnam(username); + /* + if (spwd == NULL) + { + g_critical("getspnam: %s", strerror(errno)); + return FALSE; + } + */ + + if (spwd != NULL) /* If there is a shadow password record */ + { + pwd->pw_passwd = spwd->sp_pwdp; /* Use the shadow password */ + } + /* Encrypt password and erase cleartext version immediately */ + encrypted = crypt(password, pwd->pw_passwd); + if (encrypted == NULL) + { + g_critical("crypt: %s", strerror(errno)); + return FALSE; + } + if (strcmp(encrypted, pwd->pw_passwd) == 0) + { + return TRUE; + } + else + { + return FALSE; + } +} + +/** + * @brief Method call handler on dbus interface + */ +static void session_manager_method_call(GDBusConnection *connection, const gchar *sender, const gchar *object_path, const gchar *interface_name, const gchar *method_name, GVariant *parameters, GDBusMethodInvocation *invocation, gpointer user_data) +{ + (void)connection; + (void)sender; + (void)object_path; + (void)interface_name; + (void)parameters; + (void)user_data; + SessionManager *self = SESSION_MANAGER(user_data); + g_debug("session_manager_method_call: %s", method_name); + if (g_strcmp0(method_name, "login") == 0) + { + const gchar *username; + const gchar *password; + g_variant_get(parameters, "(&s&s)", &username, &password); + g_debug("Login request for user: %s with password %s", username, password); + + if (self->session_pid > 0) + { + g_warning("Cannot process login request for user %s. A session is currently running", username); + g_dbus_method_invocation_return_dbus_error(invocation, DBUS_SERVER_ERROR_NAME, "A session is currently running"); + return; + } + if(session_user_auth(username, password)) + { + g_dbus_method_invocation_return_value(invocation, g_variant_new("(b)", TRUE)); + /** + * TODO: exit login session and start a new user session + */ + } + else + { + g_dbus_method_invocation_return_value(invocation, g_variant_new("(b)", FALSE)); + } + // g_variant_unref(result); + } + else + { + g_dbus_method_invocation_return_dbus_error(invocation, DBUS_SERVER_ERROR_NAME, "Method not found"); + } +} + +/** + * @brief Bus listener callback + */ +static const GDBusInterfaceVTable interface_vtable = + { + .method_call = session_manager_method_call, + .get_property = NULL, + .set_property = NULL, +}; + +/** + * @brief Bus acquired callback + */ +static void on_bus_acquired(GDBusConnection *connection, const gchar *name, gpointer user_data) +{ + SessionManager *self = SESSION_MANAGER(user_data); + g_debug("on_bus_acquired: %s", name); + GError *error = NULL; + if (!g_dbus_connection_register_object( + connection, + DBUS_SERVER_PATH, + self->introspection->interfaces[0], + &interface_vtable, + user_data, + NULL, + &error)) + { + g_critical("Failed to register object: %s", error->message); + g_error_free(error); + session_manager_event_loop_stop(self); + } +} + +/** + * @brief Name acquired callback + */ +static void on_name_acquired(GDBusConnection *connection, const gchar *name, gpointer user_data) +{ + (void)connection; + (void)user_data; + g_debug("on_name_acquired: %s", name); +} + +/** + * @brief Name lost callback + */ +static void on_name_lost(GDBusConnection *connection, const gchar *name, gpointer user_data) +{ + (void)connection; + g_critical("DBus session manager name lost, probably because of user not having access rights on the bus: %s", name); + SessionManager *self = SESSION_MANAGER(user_data); + session_manager_event_loop_stop(self); +} + +/** + * @brief Create a new SessionManager object + */ +SessionManager *session_manager_new(const gchar *config_file) +{ + SessionManager *manager = g_object_new(SESSION_TYPE_MANAGER, NULL); + manager->configuration = daemon_configuration_new(config_file); + if (!manager->configuration) + { + return NULL; + } + // load xml content from gresource + GError *err = NULL; + GBytes *bytes = g_resources_lookup_data("/dev/iohub/diya/SessionManager/resources/introspection.xml", 0, &err); + if (err != NULL) + { + g_critical("Unable to load introspection resource: %s", err->message); + g_error_free(err); + g_object_unref(manager); + return NULL; + } + const char *data = g_bytes_get_data(bytes, NULL); + g_debug("introspection xml: \n %s", data); + manager->introspection = g_dbus_node_info_new_for_xml(data, &err); + g_bytes_unref(bytes); + if (err != NULL) + { + g_critical("Unable to parse introspection xml: %s", err->message); + g_error_free(err); + g_object_unref(manager); + return NULL; + } + manager->bus_id = g_bus_own_name(G_BUS_TYPE_SYSTEM, + DBUS_SERVER_NAME, + G_BUS_NAME_OWNER_FLAGS_NONE, + on_bus_acquired, + on_name_acquired, + on_name_lost, + manager, + NULL); + + return manager; +} + +/** + * @brief Start the session manager event loop + */ +void session_manager_event_loop_start(SessionManager *self) +{ + if (g_main_loop_is_running(self->loop)) + { + g_warning("Session manager already started. do nothing"); + return; + } + g_debug("Session manager event loop"); + + g_main_loop_run(self->loop); +} + +/** + * @brief Stop the session manager event loop + */ +void session_manager_event_loop_stop(SessionManager *self) +{ + g_main_loop_quit(self->loop); +} \ No newline at end of file diff --git a/src/manager.h b/src/manager.h new file mode 100644 index 0000000..b490cec --- /dev/null +++ b/src/manager.h @@ -0,0 +1,12 @@ +#ifndef MANAGER_H +#define MANAGER_H + +#include "base.h" + +#define SESSION_TYPE_MANAGER (session_manager_get_type()) +G_DECLARE_FINAL_TYPE(SessionManager, session_manager, SESSION, MANAGER, BaseObject) + +SessionManager* session_manager_new(const gchar* config_file); +void session_manager_event_loop_start(SessionManager* manager); +void session_manager_event_loop_stop(SessionManager* manager); +#endif \ No newline at end of file