Blame src/dbus/abrt-configuration.c

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
}