Base code for session manager that supports user authentification via dbus

This commit is contained in:
DanyLE 2025-03-08 00:43:58 +01:00
parent d82845ecf8
commit c75274f3d2
14 changed files with 917 additions and 1 deletions

3
.gitignore vendored
View File

@ -139,4 +139,5 @@ m4/lt~obsolete.m4
# can automatically generate from config.status script
# (which is called by configure script))
Makefile
.vscode
build

View File

@ -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
```

24
conf/daemon.conf Normal file
View File

@ -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

29
conf/diya-dbus.conf Normal file
View File

@ -0,0 +1,29 @@
<!DOCTYPE busconfig PUBLIC
"-//freedesktop//DTD D-BUS Bus Configuration 1.0//EN"
"http://www.freedesktop.org/standards/dbus/1.0/busconfig.dtd">
<busconfig>
<!-- Only root can own the service -->
<policy user="root">
<allow own="dev.iohub.diya.SessionManager"/>
</policy>
<!--deny all access from another user-->
<policy context="default">
<deny send_destination="dev.iohub.diya.SessionManager"/>
<deny receive_sender="dev.iohub.diya.SessionManager"/>
</policy>
<!--
<policy group="xdg">
<allow send_destination="dev.iohub.diya.SessionManager"/>
<allow receive_sender="dev.iohub.diya.SessionManager"/>
</policy>
-->
<policy user="root">
<allow send_destination="dev.iohub.diya.SessionManager"/>
<allow receive_sender="dev.iohub.diya.SessionManager"/>
</policy>
</busconfig>

38
meson.build Normal file
View File

@ -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])

6
resources/gresource.xml Normal file
View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<gresources>
<gresource prefix="/dev/iohub/diya/SessionManager">
<file>resources/introspection.xml</file>
</gresource>
</gresources>

View File

@ -0,0 +1,10 @@
<node name = "/dev/iohub/diya">
<interface name='dev.iohub.diya.SessionManager'>
<method name='login'>
<!--annotation name='org.gtk.GDBus.Annotation' value='OnMethod' /-->
<arg type='s' name='user' direction='in' />
<arg type='s' name='password' direction='in' />
<arg type='b' name='result' direction='out' />
</method>
</interface>
</node>

46
src/base.c Normal file
View File

@ -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";
}

23
src/base.h Normal file
View File

@ -0,0 +1,23 @@
#ifndef BASE_H
#define BASE_H
#include <glib-object.h>
/**
* 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

268
src/configuration.c Normal file
View File

@ -0,0 +1,268 @@
#include "configuration.h"
#include <fcntl.h>
#include <stddef.h>
#include <stdio.h>
#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;
}

10
src/configuration.h Normal file
View File

@ -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

93
src/main.c Normal file
View File

@ -0,0 +1,93 @@
#include <unistd.h>
#include <fcntl.h>
#include <string.h>
#include <errno.h>
#include <stddef.h>
#include <stdlib.h>
#include <stdio.h>
#include <glib-unix.h>
#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;
}

327
src/manager.c Normal file
View File

@ -0,0 +1,327 @@
#include "manager.h"
#include "configuration.h"
#include <gio/gio.h>
#include <pwd.h>
#include <grp.h>
#include <shadow.h>
#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);
}

12
src/manager.h Normal file
View File

@ -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