|
Packit |
8ea169 |
#include <gio/gio.h>
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
#include "abrt-polkit.h"
|
|
Packit |
8ea169 |
#include "libabrt.h"
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
#define ABRT_CONF_DBUS_NAME "com.redhat.problems.configuration"
|
|
Packit |
8ea169 |
#define ABRT_CONF_IFACE_PFX ABRT_CONF_DBUS_NAME
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
#ifndef PROBLEMS_CONFIG_INTERFACES_DIR
|
|
Packit |
8ea169 |
# error "Undefined PROBLEMS_CONFIG_INTERFACES_DIR"
|
|
Packit |
8ea169 |
#endif
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
#define ANNOTATION_NAME_CONF_FILE "com.redhat.problems.ConfFile"
|
|
Packit |
8ea169 |
#define ANNOTATION_NAME_DEF_CONF_FILE "com.redhat.problems.DefaultConfFile"
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
#define ABRT_FILE_ACCESS_ERROR abrt_file_access_error_quark()
|
|
Packit |
8ea169 |
#define ABRT_FILE_ACCESS_ERROR_CODE ENOENT
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
static GQuark abrt_file_access_error_quark()
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
return g_quark_from_static_string("abrt-file-access-error");
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
#define ABRT_REFLECTION_UNSUPPORTED_TYPE_ERROR abrt_reflection_unsupported_type_error_quark()
|
|
Packit |
8ea169 |
#define ABRT_REFLECTION_UNSUPPORTED_TYPE_ERROR_CODE (129)
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
static GQuark abrt_reflection_unsupported_type_error_quark()
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
return g_quark_from_static_string("abrt-reflection-unsupported-type-error");
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
#define ABRT_REFLECTION_MISSING_MEMBER_ERROR abrt_reflection_missing_member_error_quark()
|
|
Packit |
8ea169 |
#define ABRT_REFLECTION_MISSING_MEMBER_ERROR_CODE (130)
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
static GQuark abrt_reflection_missing_member_error_quark()
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
return g_quark_from_static_string("abrt-reflection-missing-member-error");
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
#define ABRT_FILE_FORMAT_ERROR abrt_file_fromat_error_quark()
|
|
Packit |
8ea169 |
#define ABRT_FILE_FORMAT_ERROR_CODE (131)
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
static GQuark abrt_file_fromat_error_quark()
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
return g_quark_from_static_string("abrt-file-format-error");
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
#define ABRT_AUTHORIZATION_ERROR abrt_authorization_error_quark()
|
|
Packit |
8ea169 |
#define ABRT_AUTHORIZATION_ERROR_CODE (132)
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
static GQuark abrt_authorization_error_quark()
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
return g_quark_from_static_string("abrt-authorization-error");
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
const char *g_default_xml =
|
|
Packit |
8ea169 |
"<node><interface name=\"com.redhat.problems.configuration\"><method name=\"SetDefault\"><arg name=\"name\" type=\"s\" direction=\"in\" /></method></interface></node>";
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
GDBusNodeInfo *g_default_node;
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
guint g_timeout_source;
|
|
Packit |
8ea169 |
int g_timeout_value = 10;
|
|
Packit |
8ea169 |
GMainLoop *g_loop;
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
static gboolean on_timeout_cb(gpointer user_data)
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
log_info("Inactivity timeout was reached");
|
|
Packit |
8ea169 |
g_main_loop_quit(g_loop);
|
|
Packit |
8ea169 |
return TRUE;
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
static void reset_timeout(void)
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
if (g_timeout_source > 0)
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
log_info("Removing timeout");
|
|
Packit |
8ea169 |
g_source_remove(g_timeout_source);
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
log_info("Setting a new timeout");
|
|
Packit |
8ea169 |
g_timeout_source = g_timeout_add_seconds(g_timeout_value, on_timeout_cb, NULL);
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
/* A configuration entity
|
|
Packit |
8ea169 |
*
|
|
Packit |
8ea169 |
* Each configuration has the working file and the default file. It is
|
|
Packit |
8ea169 |
* expected that the default configuration file remains unchanged while the
|
|
Packit |
8ea169 |
* program is running, so the parsed file can be cached. But the working file
|
|
Packit |
8ea169 |
* can be modified from various source, therefore we must parse the file upon
|
|
Packit |
8ea169 |
* each request.
|
|
Packit |
8ea169 |
*/
|
|
Packit |
8ea169 |
typedef struct _configuration
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
char *file_path; ///< Path to the working file
|
|
Packit |
8ea169 |
char *def_file_path; ///< Path to the default file
|
|
Packit |
8ea169 |
map_string_t *def; ///< The default configuration
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
configuration_t;
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
typedef GVariant *(*configuration_getter_fn)(configuration_t *conf,
|
|
Packit |
8ea169 |
const char *option, GError **error);
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
typedef bool (*configuration_setter_fn)(configuration_t *conf,
|
|
Packit |
8ea169 |
const char *option, GVariant *variant, GError **error);
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
static configuration_t *configuration_new(const char *file_path, const char *def_file_path)
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
configuration_t *self = xmalloc(sizeof(*self));
|
|
Packit |
8ea169 |
self->file_path = xstrdup(file_path);
|
|
Packit |
8ea169 |
self->def_file_path = xstrdup(def_file_path);
|
|
Packit |
8ea169 |
self->def = NULL;
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
return self;
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
/* A helper function for equality comparison.
|
|
Packit |
8ea169 |
*
|
|
Packit |
8ea169 |
* Checks if the configuration files equals to the paths in array
|
|
Packit |
8ea169 |
*/
|
|
Packit |
8ea169 |
static int configuration_compare_paths(configuration_t *self, const char *paths[2])
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
if (strcmp(self->file_path, paths[0]) != 0)
|
|
Packit |
8ea169 |
return -1;
|
|
Packit |
8ea169 |
if (strcmp(self->def_file_path, paths[1]) != 0)
|
|
Packit |
8ea169 |
return 1;
|
|
Packit |
8ea169 |
return 0;
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
static void configuration_free(configuration_t *self)
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
if (self == NULL)
|
|
Packit |
8ea169 |
return;
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
free(self->file_path);
|
|
Packit |
8ea169 |
self->file_path = NULL;
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
free(self->def_file_path);
|
|
Packit |
8ea169 |
self->def_file_path = NULL;
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
free_map_string(self->def);
|
|
Packit |
8ea169 |
self->def = NULL;
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
free(self);
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
static map_string_t *configuration_load_file(const char *file_path,
|
|
Packit |
8ea169 |
map_string_t *preloaded, bool fail_on_noent, GError **error)
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
map_string_t *conf = preloaded;
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
if (conf == NULL)
|
|
Packit |
8ea169 |
conf = new_map_string();
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
if (!load_conf_file(file_path, conf, /*skip w/o values*/false)
|
|
Packit |
8ea169 |
&& (errno != ENOENT || fail_on_noent))
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
if (conf != preloaded)
|
|
Packit |
8ea169 |
free_map_string(conf);
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
conf = NULL;
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
g_set_error(error,
|
|
Packit |
8ea169 |
ABRT_FILE_ACCESS_ERROR, ABRT_FILE_ACCESS_ERROR_CODE,
|
|
Packit |
8ea169 |
"Could not load configuration from '%s'", file_path);
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
return conf;
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
static bool configuration_save_file(const char *file_path, map_string_t *conf, GError **error)
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
const bool retval = save_conf_file(file_path, conf);
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
if (!retval)
|
|
Packit |
8ea169 |
g_set_error(error,
|
|
Packit |
8ea169 |
ABRT_FILE_ACCESS_ERROR, ABRT_FILE_ACCESS_ERROR_CODE,
|
|
Packit |
8ea169 |
"Could not save configuration file '%s'", file_path);
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
return retval;
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
static map_string_t *configuration_get_default(configuration_t *self, GError **error)
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
if (self->def == NULL)
|
|
Packit |
8ea169 |
self->def = configuration_load_file(self->def_file_path,
|
|
Packit |
8ea169 |
/*No preloaded configuration*/NULL,
|
|
Packit |
8ea169 |
/*Fail on ENOENT*/true,
|
|
Packit |
8ea169 |
error);
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
return self->def;
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
/*
|
|
Packit |
8ea169 |
* Default value
|
|
Packit |
8ea169 |
*/
|
|
Packit |
8ea169 |
static bool configuration_set_default(configuration_t *self, const char *option, GError **error)
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
map_string_t *const def_conf = configuration_get_default(self, error);
|
|
Packit |
8ea169 |
if (def_conf == NULL)
|
|
Packit |
8ea169 |
return false;
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
const char *const def_value = get_map_string_item_or_NULL(def_conf, option);
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
map_string_t *const conf = configuration_load_file(self->file_path,
|
|
Packit |
8ea169 |
/*No preloaded configuration*/NULL,
|
|
Packit |
8ea169 |
/*Fail on ENOENT*/true,
|
|
Packit |
8ea169 |
error);
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
if (conf == NULL)
|
|
Packit |
8ea169 |
/* If the configuration file does not exist, the default value is used */
|
|
Packit |
8ea169 |
return errno == ENOENT;
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
const char *const cur_value = get_map_string_item_or_NULL(conf, option);
|
|
Packit |
8ea169 |
bool retval = true;
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
/* Avoid saving the configuration if nothing has changed */
|
|
Packit |
8ea169 |
if (!((def_value == NULL && cur_value == NULL)
|
|
Packit |
8ea169 |
|| (def_value != NULL && cur_value != NULL && strcmp(def_value, cur_value) == 0)))
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
if (def_value != NULL)
|
|
Packit |
8ea169 |
replace_map_string_item(conf, xstrdup(option), xstrdup(def_value));
|
|
Packit |
8ea169 |
else
|
|
Packit |
8ea169 |
remove_map_string_item(conf, option);
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
retval = configuration_save_file(self->file_path, conf, error);
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
free_map_string(conf);
|
|
Packit |
8ea169 |
return retval;
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
/*
|
|
Packit |
8ea169 |
* Setters
|
|
Packit |
8ea169 |
*/
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
/* Stores value of GVariant argument in the configuration under key 'option'.
|
|
Packit |
8ea169 |
*
|
|
Packit |
8ea169 |
* Converts the GVariant to the underlaying type via 'transform' function.
|
|
Packit |
8ea169 |
*/
|
|
Packit |
8ea169 |
static bool configuration_set_gvariant(configuration_t *self, const char *option, GVariant *value,
|
|
Packit |
8ea169 |
void (*transform)(map_string_t *, const char *, GVariant *),
|
|
Packit |
8ea169 |
GError **error)
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
map_string_t *const conf = configuration_load_file(self->file_path,
|
|
Packit |
8ea169 |
/*No preloaded configuration*/NULL,
|
|
Packit |
8ea169 |
/*Fail on ENOENT*/false,
|
|
Packit |
8ea169 |
error);
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
if (conf == NULL)
|
|
Packit |
8ea169 |
return false;
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
transform(conf, option, value);
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
const bool retval = configuration_save_file(self->file_path, conf, error);
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
free_map_string(conf);
|
|
Packit |
8ea169 |
return retval;
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
static void bool_from_gvariant(map_string_t *conf, const char *option, GVariant *value)
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
const bool raw_value = g_variant_get_boolean(value);
|
|
Packit |
8ea169 |
log_debug("Save boolean option '%s':%d", option, raw_value);
|
|
Packit |
8ea169 |
set_map_string_item_from_bool(conf, option, raw_value);
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
static void int32_from_gvariant(map_string_t *conf, const char *option, GVariant *value)
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
const int raw_value = g_variant_get_int32(value);
|
|
Packit |
8ea169 |
log_debug("Save int32 option '%s':%d", option, raw_value);
|
|
Packit |
8ea169 |
set_map_string_item_from_int(conf, option, raw_value);
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
static void string_from_gvariant(map_string_t *conf, const char *option, GVariant *value)
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
const char *const raw_value = g_variant_get_string(value, /*length*/ NULL);
|
|
Packit |
8ea169 |
log_debug("Save string option '%s':%s", option, raw_value);
|
|
Packit |
8ea169 |
set_map_string_item_from_string(conf, option, raw_value);
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
static void string_vector_from_gvariant(map_string_t *conf, const char *option, GVariant *value)
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
const gchar **const raw_value = g_variant_get_strv(value, /*lenght -> request NULL terminated vector*/ NULL);
|
|
Packit |
8ea169 |
log_debug("Save string vector option '%s'", option);
|
|
Packit |
8ea169 |
set_map_string_item_from_string_vector(conf, option, (string_vector_ptr_t)raw_value);
|
|
Packit |
8ea169 |
g_free(raw_value);
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
static bool configuration_set_string(configuration_t *self, const char *option, GVariant *value, GError **error)
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
return configuration_set_gvariant(self, option, value, string_from_gvariant, error);
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
static bool configuration_set_string_vector(configuration_t *self, const char *option, GVariant *value, GError **error)
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
return configuration_set_gvariant(self, option, value, string_vector_from_gvariant, error);
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
static bool configuration_set_bool(configuration_t *self, const char *option, GVariant *value, GError **error)
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
return configuration_set_gvariant(self, option, value, bool_from_gvariant, error);
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
static bool configuration_set_int(configuration_t *self, const char *option, GVariant *value, GError **error)
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
return configuration_set_gvariant(self, option, value, int32_from_gvariant, error);
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
static configuration_setter_fn configuration_setter_factory(GVariantType *type)
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
if (g_variant_type_equal(G_VARIANT_TYPE_BOOLEAN, type))
|
|
Packit |
8ea169 |
return configuration_set_bool;
|
|
Packit |
8ea169 |
else if (g_variant_type_equal(G_VARIANT_TYPE_INT32, type))
|
|
Packit |
8ea169 |
return configuration_set_int;
|
|
Packit |
8ea169 |
else if (g_variant_type_equal(G_VARIANT_TYPE_STRING, type))
|
|
Packit |
8ea169 |
return configuration_set_string;
|
|
Packit |
8ea169 |
else if (g_variant_type_equal(G_VARIANT_TYPE_STRING_ARRAY, type))
|
|
Packit |
8ea169 |
return configuration_set_string_vector;
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
return NULL;
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
/*
|
|
Packit |
8ea169 |
* Getters
|
|
Packit |
8ea169 |
*/
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
/* Gets the configuration option's value as GVariant
|
|
Packit |
8ea169 |
*
|
|
Packit |
8ea169 |
* Converts the GVariant to the underlaying type via 'transform' function.
|
|
Packit |
8ea169 |
*/
|
|
Packit |
8ea169 |
static GVariant *configuration_get_gvariant(configuration_t *self, const char *option,
|
|
Packit |
8ea169 |
GVariant *(*transform)(map_string_t *conf, const char *option),
|
|
Packit |
8ea169 |
GError **error)
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
map_string_t *const def_conf = configuration_get_default(self, error);
|
|
Packit |
8ea169 |
if (def_conf == NULL)
|
|
Packit |
8ea169 |
return false;
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
/* BEGIN: clone_map_string() */
|
|
Packit |
8ea169 |
map_string_t *conf = new_map_string();
|
|
Packit |
8ea169 |
map_string_iter_t iter;
|
|
Packit |
8ea169 |
init_map_string_iter(&iter, def_conf);
|
|
Packit |
8ea169 |
const char *key=NULL;
|
|
Packit |
8ea169 |
const char *value=NULL;
|
|
Packit |
8ea169 |
while(next_map_string_iter(&iter, &key, &value))
|
|
Packit |
8ea169 |
replace_map_string_item(conf, xstrdup(key), xstrdup(value));
|
|
Packit |
8ea169 |
/* END: clone_map_string() */
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
GError *working_error = NULL;
|
|
Packit |
8ea169 |
if (!configuration_load_file(self->file_path, conf, /*Fail on ENOENT*/true, &working_error))
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
log_debug("Error while loading working configuration: %s", working_error->message);
|
|
Packit |
8ea169 |
g_error_free(working_error);
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
GVariant *const retval = transform(conf, option);
|
|
Packit |
8ea169 |
free_map_string(conf);
|
|
Packit |
8ea169 |
if (!retval)
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
g_set_error(error,
|
|
Packit |
8ea169 |
ABRT_FILE_FORMAT_ERROR, ABRT_FILE_FORMAT_ERROR_CODE,
|
|
Packit |
8ea169 |
"Option '%s' has invalid value in file '%s'", option, self->file_path);
|
|
Packit |
8ea169 |
log_warning("Option '%s' has invalid value in file '%s'", option, self->file_path);
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
return retval;
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
static GVariant *int32_to_gvariant(map_string_t *conf, const char *key)
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
int value = 0;
|
|
Packit |
8ea169 |
if (!try_get_map_string_item_as_int(conf, key, &value))
|
|
Packit |
8ea169 |
return NULL;
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
return g_variant_new_int32(value);
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
static GVariant *bool_to_gvariant(map_string_t *conf, const char *key)
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
int value = 0;
|
|
Packit |
8ea169 |
if (!try_get_map_string_item_as_bool(conf, key, &value))
|
|
Packit |
8ea169 |
return NULL;
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
return g_variant_new_boolean(value);
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
static GVariant *string_to_gvariant(map_string_t *conf, const char *key)
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
char *value = NULL;
|
|
Packit |
8ea169 |
if (!try_get_map_string_item_as_string(conf, key, &value))
|
|
Packit |
8ea169 |
return NULL;
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
GVariant *retval = g_variant_new_string(value);
|
|
Packit |
8ea169 |
free(value);
|
|
Packit |
8ea169 |
return retval;
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
static GVariant *string_vector_to_gvariant(map_string_t *conf, const char *key)
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
string_vector_ptr_t value = NULL;
|
|
Packit |
8ea169 |
if (!try_get_map_string_item_as_string_vector(conf, key, &value))
|
|
Packit |
8ea169 |
return NULL;
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
GVariant *retval = g_variant_new_strv((const gchar *const *)value, /*NULL terminated*/-1);
|
|
Packit |
8ea169 |
string_vector_free(value);
|
|
Packit |
8ea169 |
return retval;
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
static GVariant *configuration_get_string(configuration_t *self, const char *option, GError **error)
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
return configuration_get_gvariant(self, option, string_to_gvariant, error);
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
static GVariant *configuration_get_int32(configuration_t *self, const char *option, GError **error)
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
return configuration_get_gvariant(self, option, int32_to_gvariant, error);
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
static GVariant *configuration_get_bool(configuration_t *self, const char *option, GError **error)
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
return configuration_get_gvariant(self, option, bool_to_gvariant, error);
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
static GVariant *configuration_get_string_vector(configuration_t *self, const char *option, GError **error)
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
return configuration_get_gvariant(self, option, string_vector_to_gvariant, error);
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
static configuration_getter_fn configuration_getter_factory(GVariantType *type)
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
if (g_variant_type_equal(G_VARIANT_TYPE_BOOLEAN, type))
|
|
Packit |
8ea169 |
return configuration_get_bool;
|
|
Packit |
8ea169 |
else if (g_variant_type_equal(G_VARIANT_TYPE_INT32, type))
|
|
Packit |
8ea169 |
return configuration_get_int32;
|
|
Packit |
8ea169 |
else if (g_variant_type_equal(G_VARIANT_TYPE_STRING, type))
|
|
Packit |
8ea169 |
return configuration_get_string;
|
|
Packit |
8ea169 |
else if (g_variant_type_equal(G_VARIANT_TYPE_STRING_ARRAY, type))
|
|
Packit |
8ea169 |
return configuration_get_string_vector;
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
return NULL;
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
/* A single property entity
|
|
Packit |
8ea169 |
*
|
|
Packit |
8ea169 |
* This structure provides mapping between a D-Bus property and a configuration option.
|
|
Packit |
8ea169 |
*/
|
|
Packit |
8ea169 |
typedef struct _property
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
char *name; ///< Property Name in the XML file and Option Name in configuration
|
|
Packit |
8ea169 |
GVariantType *type; ///< GLib's type
|
|
Packit |
8ea169 |
char *type_string; ///< GLib's type string
|
|
Packit |
8ea169 |
configuration_t *conf; ///< A configuration which contains this option (Not owned)
|
|
Packit |
8ea169 |
configuration_getter_fn getter; ///< Getter function
|
|
Packit |
8ea169 |
configuration_setter_fn setter; ///< Setter function
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
property_t;
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
static property_t *property_new(const char *name, GVariantType *type, configuration_t *conf,
|
|
Packit |
8ea169 |
configuration_getter_fn getter, configuration_setter_fn setter)
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
property_t *self = xmalloc(sizeof(*self));
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
self->name = xstrdup(name);
|
|
Packit |
8ea169 |
self->type = type;
|
|
Packit |
8ea169 |
self->type_string = NULL;
|
|
Packit |
8ea169 |
self->conf = conf;
|
|
Packit |
8ea169 |
self->getter = getter;
|
|
Packit |
8ea169 |
self->setter = setter;
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
return self;
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
static void property_free(property_t *self)
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
if (self == NULL)
|
|
Packit |
8ea169 |
return;
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
free(self->name);
|
|
Packit |
8ea169 |
self->name = NULL;
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
g_variant_type_free(self->type);
|
|
Packit |
8ea169 |
self->type = NULL;
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
g_free(self->type_string);
|
|
Packit |
8ea169 |
self->type_string = NULL;
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
static const char *property_get_type_string(property_t *self)
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
if (self->type_string == NULL)
|
|
Packit |
8ea169 |
self->type_string = g_variant_type_dup_string(self->type);
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
return self->type_string;
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
static bool property_set(property_t *self, GVariant *args, GError **error)
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
if (self->setter)
|
|
Packit |
8ea169 |
return self->setter(self->conf, self->name, args, error);
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
g_set_error(error,
|
|
Packit |
8ea169 |
ABRT_REFLECTION_UNSUPPORTED_TYPE_ERROR, ABRT_REFLECTION_UNSUPPORTED_TYPE_ERROR_CODE,
|
|
Packit |
8ea169 |
"Type with signature '%s' is not supported", property_get_type_string(self));
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
return false;
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
static GVariant *property_get(property_t *self, GError **error)
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
if (self->getter)
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
GVariant *retval = self->getter(self->conf, self->name, error);
|
|
Packit |
8ea169 |
assert((retval != NULL || *error != NULL) || !"GError must be set if bool option cannot be returned.");
|
|
Packit |
8ea169 |
return retval;
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
g_set_error(error,
|
|
Packit |
8ea169 |
ABRT_REFLECTION_UNSUPPORTED_TYPE_ERROR, ABRT_REFLECTION_UNSUPPORTED_TYPE_ERROR_CODE,
|
|
Packit |
8ea169 |
"Type with signature '%s' is not supported", property_get_type_string(self));
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
return NULL;
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
static bool property_reset(property_t *self, GError **error)
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
return configuration_set_default(self->conf, self->name, error);
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
/* A single D-Bus node
|
|
Packit |
8ea169 |
*/
|
|
Packit |
8ea169 |
typedef struct _dbus_conf_node
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
GDBusNodeInfo *node; ///< Parsed XML file
|
|
Packit |
8ea169 |
GSList *configurations; ///< List of all configurations (configuration_t)
|
|
Packit |
8ea169 |
GHashTable *properties; ///< List of properties (property_t)
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
dbus_conf_node_t;
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
static dbus_conf_node_t *dbus_conf_node_new(GDBusNodeInfo *node, GSList *configurations, GHashTable *properties)
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
if (node->path == NULL)
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
error_msg("Node misses 'name' attribute");
|
|
Packit |
8ea169 |
return NULL;
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
if (node->interfaces[0] == NULL)
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
error_msg("Node has no interface defined");
|
|
Packit |
8ea169 |
return NULL;
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
dbus_conf_node_t *self = xmalloc(sizeof(*self));
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
self->node = node;
|
|
Packit |
8ea169 |
self->configurations = configurations;
|
|
Packit |
8ea169 |
self->properties = properties;
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
return self;
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
static void dbus_conf_node_free(dbus_conf_node_t *self)
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
if (self == NULL)
|
|
Packit |
8ea169 |
return;
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
g_dbus_node_info_unref(self->node);
|
|
Packit |
8ea169 |
self->node = NULL;
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
g_slist_free_full(self->configurations, (GDestroyNotify)configuration_free);
|
|
Packit |
8ea169 |
self->configurations = NULL;
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
g_hash_table_destroy(self->properties);
|
|
Packit |
8ea169 |
self->properties = NULL;
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
static const char* dbus_conf_node_get_path(dbus_conf_node_t *self)
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
return self->node->path;
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
static GDBusInterfaceInfo *dbus_conf_node_get_interface(dbus_conf_node_t *self)
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
return self->node->interfaces[0];
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
static property_t *dbus_conf_node_get_property(dbus_conf_node_t *self, const char *property_name, GError **error)
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
gpointer property = g_hash_table_lookup(self->properties, property_name);
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
if (property == NULL)
|
|
Packit |
8ea169 |
g_set_error(error,
|
|
Packit |
8ea169 |
ABRT_REFLECTION_MISSING_MEMBER_ERROR, ABRT_REFLECTION_MISSING_MEMBER_ERROR_CODE,
|
|
Packit |
8ea169 |
"Could find property '%s'", property_name);
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
return (property_t *)property;
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
/* SetDefault D-Bus method handler
|
|
Packit |
8ea169 |
*/
|
|
Packit |
8ea169 |
static void dbus_conf_node_handle_configuration_method_call(GDBusConnection *connection,
|
|
Packit |
8ea169 |
const gchar *caller,
|
|
Packit |
8ea169 |
const gchar *object_path,
|
|
Packit |
8ea169 |
const gchar *interface_name,
|
|
Packit |
8ea169 |
const gchar *method_name,
|
|
Packit |
8ea169 |
GVariant *parameters,
|
|
Packit |
8ea169 |
GDBusMethodInvocation *invocation,
|
|
Packit |
8ea169 |
gpointer user_data)
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
log_debug("Set Default Property");
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
reset_timeout();
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
if (polkit_check_authorization_dname(caller, "com.redhat.problems.configuration.update") != PolkitYes)
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
log_notice("not authorized");
|
|
Packit |
8ea169 |
g_dbus_method_invocation_return_dbus_error(invocation,
|
|
Packit |
8ea169 |
"com.redhat.problems.configuration.AuthFailure",
|
|
Packit |
8ea169 |
_("Not Authorized"));
|
|
Packit |
8ea169 |
return;
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
const char *property_name = NULL;
|
|
Packit |
8ea169 |
g_variant_get(parameters, "(&s)", &property_name);
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
log_debug("Going to reset value of '%s'", property_name);
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
GError *error = NULL;
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
property_t *prop = dbus_conf_node_get_property((dbus_conf_node_t *)user_data, property_name, &error);
|
|
Packit |
8ea169 |
if (prop == NULL || !property_reset(prop, &error))
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
g_dbus_method_invocation_return_gerror(invocation, error);
|
|
Packit |
8ea169 |
g_error_free(error);
|
|
Packit |
8ea169 |
return;
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
g_dbus_method_invocation_return_value(invocation, NULL);
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
/* Get D-Bus property handler
|
|
Packit |
8ea169 |
*/
|
|
Packit |
8ea169 |
static GVariant *dbus_conf_node_handle_get_property(GDBusConnection *connection,
|
|
Packit |
8ea169 |
const gchar *caller,
|
|
Packit |
8ea169 |
const gchar *object_path,
|
|
Packit |
8ea169 |
const gchar *interface_name,
|
|
Packit |
8ea169 |
const gchar *property_name,
|
|
Packit |
8ea169 |
GError **error,
|
|
Packit |
8ea169 |
gpointer user_data)
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
log_debug("Get Property '%s'", property_name);
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
reset_timeout();
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
property_t *prop = dbus_conf_node_get_property((dbus_conf_node_t *)user_data, property_name, error);
|
|
Packit |
8ea169 |
/* Paranoia: this should never happen*/
|
|
Packit |
8ea169 |
if (prop == NULL)
|
|
Packit |
8ea169 |
return NULL;
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
return property_get(prop, error);
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
/* Set D-Bus property handler
|
|
Packit |
8ea169 |
*/
|
|
Packit |
8ea169 |
static gboolean dbus_conf_node_handle_set_property(GDBusConnection *connection,
|
|
Packit |
8ea169 |
const gchar *caller,
|
|
Packit |
8ea169 |
const gchar *object_path,
|
|
Packit |
8ea169 |
const gchar *interface_name,
|
|
Packit |
8ea169 |
const gchar *property_name,
|
|
Packit |
8ea169 |
GVariant *args,
|
|
Packit |
8ea169 |
GError **error,
|
|
Packit |
8ea169 |
gpointer user_data)
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
log_debug("Set Property '%s'", property_name);
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
reset_timeout();
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
if (polkit_check_authorization_dname(caller, "com.redhat.problems.configuration.update") != PolkitYes)
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
log_notice("not authorized");
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
g_set_error(error,
|
|
Packit |
8ea169 |
ABRT_AUTHORIZATION_ERROR, ABRT_AUTHORIZATION_ERROR_CODE,
|
|
Packit |
8ea169 |
_("Not Authorized"));
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
return FALSE;
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
property_t *prop = dbus_conf_node_get_property((dbus_conf_node_t *)user_data, property_name, error);
|
|
Packit |
8ea169 |
/* Paranoia: this should never happen*/
|
|
Packit |
8ea169 |
if (prop == NULL)
|
|
Packit |
8ea169 |
return false;
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
return property_set(prop, args, error);
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
static GDBusInterfaceVTable *dbus_conf_node_get_vtable(dbus_conf_node_t *node)
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
static GDBusInterfaceVTable default_vtable =
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
.method_call = NULL,
|
|
Packit |
8ea169 |
.get_property = dbus_conf_node_handle_get_property,
|
|
Packit |
8ea169 |
.set_property = dbus_conf_node_handle_set_property,
|
|
Packit |
8ea169 |
};
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
return &default_vtable;
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
static GDBusInterfaceVTable *dbus_conf_node_get_configuration_vtable(dbus_conf_node_t *node)
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
static GDBusInterfaceVTable default_vtable =
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
.method_call = dbus_conf_node_handle_configuration_method_call,
|
|
Packit |
8ea169 |
.get_property = NULL,
|
|
Packit |
8ea169 |
.set_property = NULL,
|
|
Packit |
8ea169 |
};
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
return &default_vtable;
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
/* Helpers for Annotation parsing */
|
|
Packit |
8ea169 |
struct annot
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
const char *name;
|
|
Packit |
8ea169 |
const char *value;
|
|
Packit |
8ea169 |
};
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
static void parse_annotations(GDBusAnnotationInfo **annotations, struct annot annots[], size_t count)
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
GDBusAnnotationInfo **an_iter = annotations;
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
while(*an_iter != NULL)
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
for (size_t i = 0; i < count; ++i)
|
|
Packit |
8ea169 |
if (strcmp(annots[i].name, (*an_iter)->key) == 0)
|
|
Packit |
8ea169 |
annots[i].value = (*an_iter)->value;
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
++an_iter;
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
/* Builds the internal representation of configuration node from a D-Bus XML interface file.
|
|
Packit |
8ea169 |
*/
|
|
Packit |
8ea169 |
static dbus_conf_node_t *dbus_conf_node_from_node(GDBusNodeInfo *node)
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
if (node->interfaces[0] == NULL)
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
error_msg("Node has no interface defined");
|
|
Packit |
8ea169 |
return NULL;
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
struct annot annots[] = {
|
|
Packit |
8ea169 |
{ .name=ANNOTATION_NAME_CONF_FILE, .value=NULL },
|
|
Packit |
8ea169 |
{ .name=ANNOTATION_NAME_DEF_CONF_FILE, .value=NULL },
|
|
Packit |
8ea169 |
};
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
/* Parse the implicit file paths.
|
|
Packit |
8ea169 |
* The implicit paths are stored as child annotation elements of
|
|
Packit |
8ea169 |
* <interface> element. These paths are use when a property does not have
|
|
Packit |
8ea169 |
* its own file paths.
|
|
Packit |
8ea169 |
*
|
|
Packit |
8ea169 |
* Both of them are required. This is simplification because this rule does
|
|
Packit |
8ea169 |
* not make sense if all of the properties have its own file paths.
|
|
Packit |
8ea169 |
*/
|
|
Packit |
8ea169 |
parse_annotations(node->annotations, annots, sizeof(annots)/sizeof(annots[0]));
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
bool misses_annot = false;
|
|
Packit |
8ea169 |
for (size_t i = 0; i < ARRAY_SIZE(annots); ++i)
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
if (annots[i].value == NULL)
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
error_msg("Configuration node '%s' misses annotation '%s'", node->path, annots[i].name);
|
|
Packit |
8ea169 |
misses_annot = true;
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
if (misses_annot)
|
|
Packit |
8ea169 |
return NULL;
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
/* The following two variable can be omitted but the configuraion_new() call */
|
|
Packit |
8ea169 |
/* would be less understandable. */
|
|
Packit |
8ea169 |
const char *const conf_file = annots[0].value;
|
|
Packit |
8ea169 |
const char *const def_conf_file = annots[1].value;
|
|
Packit |
8ea169 |
configuration_t * conf = configuration_new(conf_file, def_conf_file);
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
/* List of known configuration file paths pairs (file, default file) */
|
|
Packit |
8ea169 |
GSList *configurations = g_slist_prepend(NULL, conf);
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
GHashTable *properties = g_hash_table_new_full(g_str_hash, g_str_equal,
|
|
Packit |
8ea169 |
(GDestroyNotify)NULL, (GDestroyNotify)property_free);
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
for(GDBusPropertyInfo **prop_iter = node->interfaces[0]->properties; *prop_iter != NULL; ++prop_iter)
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
/* Use the node's default configuration file pair */
|
|
Packit |
8ea169 |
configuration_t *prop_conf = conf;
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
annots[0].value = NULL;
|
|
Packit |
8ea169 |
annots[1].value = NULL;
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
/* Check whether the current property has configuration paths annotations.
|
|
Packit |
8ea169 |
* It must have either both or none!
|
|
Packit |
8ea169 |
*/
|
|
Packit |
8ea169 |
parse_annotations((*prop_iter)->annotations, annots, ARRAY_SIZE(annots));
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
if (annots[0].value != NULL && annots[1].value != NULL)
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
const char *paths[2] = { annots[0].value, annots[1].value };
|
|
Packit |
8ea169 |
/* Try to find a configuration which equals to this configuration files pair */
|
|
Packit |
8ea169 |
GSList *lst_item = g_slist_find_custom(configurations,
|
|
Packit |
8ea169 |
(gpointer)paths,
|
|
Packit |
8ea169 |
(GCompareFunc)configuration_compare_paths);
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
/* If such configuration object does not exist yet, create a new one. */
|
|
Packit |
8ea169 |
if (lst_item == NULL)
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
/* The following two variable can be omitted but the configuraion_new() */
|
|
Packit |
8ea169 |
/* call would be less understandable. */
|
|
Packit |
8ea169 |
const char *const prop_conf_file = annots[0].value;
|
|
Packit |
8ea169 |
const char *const prop_def_conf_file = annots[1].value;
|
|
Packit |
8ea169 |
prop_conf = configuration_new(prop_conf_file, prop_def_conf_file);
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
configurations = g_slist_prepend(configurations, prop_conf);
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
else
|
|
Packit |
8ea169 |
prop_conf = (configuration_t *)lst_item->data;
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
else if (annots[0].value == NULL && annots[1].value != NULL)
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
error_msg("Property '%s' misses annotation '%s'", (*prop_iter)->name, annots[0].name);
|
|
Packit |
8ea169 |
continue;
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
else if (annots[0].value != NULL && annots[1].value == NULL)
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
error_msg("Property '%s' misses annotation '%s'", (*prop_iter)->name, annots[1].name);
|
|
Packit |
8ea169 |
continue;
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
GVariantType *prop_type = g_variant_type_new((*prop_iter)->signature);
|
|
Packit |
8ea169 |
configuration_getter_fn prop_get = configuration_getter_factory(prop_type);
|
|
Packit |
8ea169 |
configuration_setter_fn prop_set = configuration_setter_factory(prop_type);
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
/* We don't mind if the property's type is not supported. We still want
|
|
Packit |
8ea169 |
* to provide the property, because hiding it would be more confusing.
|
|
Packit |
8ea169 |
*/
|
|
Packit |
8ea169 |
if (prop_get == NULL)
|
|
Packit |
8ea169 |
error_msg("Property '%s' has unsupported getter type", (*prop_iter)->name);
|
|
Packit |
8ea169 |
if (prop_set == NULL)
|
|
Packit |
8ea169 |
error_msg("Property '%s' has unsupported setter type", (*prop_iter)->name);
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
property_t *prop = property_new((*prop_iter)->name, prop_type, prop_conf, prop_get, prop_set);
|
|
Packit |
8ea169 |
g_hash_table_replace(properties, (*prop_iter)->name, prop);
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
return dbus_conf_node_new(node, configurations, properties);
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
static dbus_conf_node_t *dbus_conf_node_from_file(const char *iface_file_path)
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
char *xmldata = xmalloc_open_read_close(iface_file_path, /*maxsize*/NULL);
|
|
Packit |
8ea169 |
if (xmldata == NULL)
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
error_msg("Cannot create configuration node from file '%s'", iface_file_path);
|
|
Packit |
8ea169 |
return NULL;
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
GError *error = NULL;
|
|
Packit |
8ea169 |
GDBusNodeInfo *node = g_dbus_node_info_new_for_xml(xmldata, &error);
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
if (error)
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
free(xmldata);
|
|
Packit |
8ea169 |
error_msg("Could not parse interface file '%s': %s", iface_file_path, error->message);
|
|
Packit |
8ea169 |
g_error_free(error);
|
|
Packit |
8ea169 |
return NULL;
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
dbus_conf_node_t *conf_node = dbus_conf_node_from_node(node);
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
/* Failed to create a configuration node, node is unchanged and must be released */
|
|
Packit |
8ea169 |
if (conf_node == NULL)
|
|
Packit |
8ea169 |
g_dbus_node_info_unref(node);
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
free(xmldata);
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
return conf_node;
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
/* Go through files within the directory and try to convert them to a D-Bus
|
|
Packit |
8ea169 |
* configuration nodes.
|
|
Packit |
8ea169 |
*/
|
|
Packit |
8ea169 |
static GList *load_configurators(const char *file_dir)
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
log_debug("Loading configuration XML interfaces from '%s'", file_dir);
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
GList *conf_files = get_file_list(file_dir, "xml");
|
|
Packit |
8ea169 |
GList *result = NULL;
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
for (GList *iter = conf_files; iter != NULL; iter = g_list_next(iter))
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
file_obj_t *const file = (file_obj_t *)iter->data;
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
const char *const filename = fo_get_filename(file);
|
|
Packit |
8ea169 |
if (prefixcmp(filename, ABRT_CONF_IFACE_PFX) != 0)
|
|
Packit |
8ea169 |
/* Skipping the current file because it is not Problems Configuration iface */
|
|
Packit |
8ea169 |
continue;
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
/* The non-default interfaces has a short string between ABRT_CONF_IFACE_PFX prefix */
|
|
Packit |
8ea169 |
/* and ".xml" suffix (get_file_list() chops the sfx (.xml))*/
|
|
Packit |
8ea169 |
if (filename[strlen(ABRT_CONF_IFACE_PFX)] == '\0')
|
|
Packit |
8ea169 |
/* Skipping the default configuration iface */
|
|
Packit |
8ea169 |
continue;
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
const char *const fullpath = fo_get_fullpath(file);
|
|
Packit |
8ea169 |
log_debug("Processing interface file '%s'", fullpath);
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
dbus_conf_node_t *const conf_node = dbus_conf_node_from_file(fullpath);
|
|
Packit |
8ea169 |
if (conf_node != NULL)
|
|
Packit |
8ea169 |
result = g_list_prepend(result, conf_node);
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
free_file_list(conf_files);
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
return result;
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
static void on_bus_acquired(GDBusConnection *connection,
|
|
Packit |
8ea169 |
const gchar *name,
|
|
Packit |
8ea169 |
gpointer user_data)
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
log_debug("Going to register the configuration objects on bus '%s'", name);
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
for (GList *iter = (GList *)user_data; iter != NULL; iter = g_list_next(iter))
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
dbus_conf_node_t *node = (dbus_conf_node_t *)iter->data;
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
log_debug("Registering dbus object '%s'", dbus_conf_node_get_path(node));
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
GError *error = NULL;
|
|
Packit |
8ea169 |
/* Register the interface parsed from a XML file */
|
|
Packit |
8ea169 |
guint registration_id = g_dbus_connection_register_object(connection,
|
|
Packit |
8ea169 |
dbus_conf_node_get_path(node),
|
|
Packit |
8ea169 |
dbus_conf_node_get_interface(node),
|
|
Packit |
8ea169 |
dbus_conf_node_get_vtable(node),
|
|
Packit |
8ea169 |
node,
|
|
Packit |
8ea169 |
/*destroy notify*/NULL,
|
|
Packit |
8ea169 |
&error);
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
if (registration_id == 0)
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
error_msg("Could not register object '%s': %s", dbus_conf_node_get_path(node), error->message);
|
|
Packit |
8ea169 |
g_error_free(error);
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
/* Register interface for SetDefault() method */
|
|
Packit |
8ea169 |
registration_id = g_dbus_connection_register_object(connection,
|
|
Packit |
8ea169 |
dbus_conf_node_get_path(node),
|
|
Packit |
8ea169 |
g_default_node->interfaces[0],
|
|
Packit |
8ea169 |
dbus_conf_node_get_configuration_vtable(node),
|
|
Packit |
8ea169 |
node,
|
|
Packit |
8ea169 |
/*destroy notify*/NULL,
|
|
Packit |
8ea169 |
&error);
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
if (registration_id == 0)
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
error_msg("Could not register object '%s': %s", dbus_conf_node_get_path(node), error->message);
|
|
Packit |
8ea169 |
g_error_free(error);
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
reset_timeout();
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
static void on_name_acquired (GDBusConnection *connection,
|
|
Packit |
8ea169 |
const gchar *name,
|
|
Packit |
8ea169 |
gpointer user_data)
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
log_debug("Acquired the name '%s' on the system bus", name);
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
static void on_name_lost(GDBusConnection *connection,
|
|
Packit |
8ea169 |
const gchar *name,
|
|
Packit |
8ea169 |
gpointer user_data)
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
log_warning(_("The name '%s' has been lost, please check if other "
|
|
Packit |
8ea169 |
"service owning the name is not running.\n"), name);
|
|
Packit |
8ea169 |
exit(1);
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
int main(int argc, char *argv[])
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
/* I18n */
|
|
Packit |
8ea169 |
setlocale(LC_ALL, "");
|
|
Packit |
8ea169 |
#if ENABLE_NLS
|
|
Packit |
8ea169 |
bindtextdomain(PACKAGE, LOCALEDIR);
|
|
Packit |
8ea169 |
textdomain(PACKAGE);
|
|
Packit |
8ea169 |
#endif
|
|
Packit |
8ea169 |
guint owner_id;
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
glib_init();
|
|
Packit |
8ea169 |
abrt_init(argv);
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
const char *program_usage_string = _(
|
|
Packit |
8ea169 |
"& [options]"
|
|
Packit |
8ea169 |
);
|
|
Packit |
8ea169 |
enum {
|
|
Packit |
8ea169 |
OPT_v = 1 << 0,
|
|
Packit |
8ea169 |
OPT_t = 1 << 1,
|
|
Packit |
8ea169 |
};
|
|
Packit |
8ea169 |
/* Keep enum above and order of options below in sync! */
|
|
Packit |
8ea169 |
struct options program_options[] = {
|
|
Packit |
8ea169 |
OPT__VERBOSE(&g_verbose),
|
|
Packit |
8ea169 |
OPT_INTEGER('t', NULL, &g_timeout_value, _("Exit after NUM seconds of inactivity")),
|
|
Packit |
8ea169 |
OPT_END()
|
|
Packit |
8ea169 |
};
|
|
Packit |
8ea169 |
/*unsigned opts =*/ parse_opts(argc, argv, program_options, program_usage_string);
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
export_abrt_envvars(0);
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
msg_prefix = "abrt-configuration"; /* for log_warning(), error_msg() and such */
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
if (getuid() != 0)
|
|
Packit |
8ea169 |
error_msg_and_die(_("This program must be run as root."));
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
GError *error = NULL;
|
|
Packit |
8ea169 |
g_default_node = g_dbus_node_info_new_for_xml(g_default_xml, &error);
|
|
Packit |
8ea169 |
if (error != NULL)
|
|
Packit |
8ea169 |
error_msg_and_die("Could not parse the default internface: %s", error->message);
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
GList *conf_nodes = load_configurators(PROBLEMS_CONFIG_INTERFACES_DIR);
|
|
Packit |
8ea169 |
if (conf_nodes == NULL)
|
|
Packit |
8ea169 |
error_msg_and_die("No configuration interface file loaded. Exiting");
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
owner_id = g_bus_own_name(G_BUS_TYPE_SYSTEM,
|
|
Packit |
8ea169 |
ABRT_CONF_DBUS_NAME,
|
|
Packit |
8ea169 |
G_BUS_NAME_OWNER_FLAGS_NONE,
|
|
Packit |
8ea169 |
on_bus_acquired,
|
|
Packit |
8ea169 |
on_name_acquired,
|
|
Packit |
8ea169 |
on_name_lost,
|
|
Packit |
8ea169 |
conf_nodes,
|
|
Packit |
8ea169 |
(GDestroyNotify)NULL);
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
g_loop = g_main_loop_new(NULL, FALSE);
|
|
Packit |
8ea169 |
g_main_loop_run(g_loop);
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
log_notice("Cleaning up");
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
g_bus_unown_name(owner_id);
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
g_list_free_full(conf_nodes, (GDestroyNotify)dbus_conf_node_free);
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
g_dbus_node_info_unref(g_default_node);
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
free_abrt_conf_data();
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
return 0;
|
|
Packit |
8ea169 |
}
|