-include $(top_builddir)/config.h \
-DSYSCONFDIR=\""$(sysconfdir)"\" \
-DDBDIR=\""$(dbdir)"\" \
- -DFAULTD_SERVICES_CONFIG_PATH=\""${sysconfdir}/faultd/conf.d/"\" \
- -DFAULTD_DEFAULT_CONFIG_FILE=\""${sysconfdir}/faultd/faultd.conf"\" \
+ -DFAULTD_CUSTOM_CONFIG_FILE=\""${sysconfdir}/faultd/faultd.conf"\" \
+ -DFAULTD_CUSTOM_MODULES_CONFIG_PATH=\""${sysconfdir}/faultd/modules.conf.d/"\" \
+ -DFAULTD_CUSTOM_SERVICES_CONFIG_PATH=\""${sysconfdir}/faultd/service.conf.d/"\" \
+ -DFAULTD_DEFAULT_CONFIG_FILE=\""${prefix}/lib/faultd/faultd.conf"\" \
+ -DFAULTD_DEFAULT_MODULES_CONFIG_PATH=\""${prefix}/lib/faultd/modules.conf.d/"\" \
+ -DFAULTD_DEFAULT_SERVICES_CONFIG_PATH=\""${prefix}/lib/faultd/service.conf.d/"\" \
-DFAULTD_MODULES_PATH=\""${sysconfdir}/faultd/enabled-modules"\" \
-I${top_srcdir}/src \
-I${top_srcdir}/src/core \
< $< > $@ || rm $@
unitdir = $(prefix)/lib/systemd/system
-configdir = $(sysconfdir)/faultd
-serviceconfigdir = $(configdir)/conf.d
+configdir = $(prefix)/lib/faultd
+serviceconfigdir = $(configdir)/service.conf.d
+modulesconfigdir = $(configdir)/modules.conf.d
dbdir = $(localstatedir)/db/faultd
nodist_unit_DATA = \
config_DATA = \
faultd.conf
-serviceconfig_DATA = \
- conf.d/dbus.service.conf \
- conf.d/display-manager.service.conf
-
sbin_PROGRAMS = faultd
faultdlib_SOURCES = \
vip_fault_eh_la_SOURCES = src/decision_makers/vip_fault_dm.c
resource_violation_eh_la_SOURCES = src/decision_makers/rv_dm.c
standard_fault_eh_la_SOURCES = src/decision_makers/standard_fault_dm.c
+standard_fault_eh_config_DATA = modules.conf.d/standard_fault_eh.conf.d/50-default.conf
+standard_fault_eh_configdir = $(modulesconfigdir)/standard_fault_eh.conf.d
standard_reboot_eh_la_SOURCES = src/decision_makers/standard_reboot_dm.c
+standard_reboot_eh_config_DATA = modules.conf.d/standard_reboot_eh.conf.d/50-default.conf
+standard_reboot_eh_configdir = $(modulesconfigdir)/standard_reboot_eh.conf.d
service_restart_action_la_SOURCES = src/action/service_restart.c
system_reboot_action_la_SOURCES = src/action/system_reboot.c
system_reboot_to_recovery_action_la_SOURCES = src/action/system_reboot_to_recovery.c
service_recover_action_la_SOURCES = src/action/service_recover.c
+dbus_service_configdir = $(serviceconfigdir)/dbus.service.conf.d
+dbus_service_config_DATA = service.conf.d/dbus.service.conf.d/50-default.conf
+
+display_manager_service_configdir = $(serviceconfigdir)/display-manager.service.conf.d
+display_manager_service_config_DATA = service.conf.d/display-manager.service.conf.d/50-default.conf
+
faultd_LDADD = $(LIBSYSTEMD_LIBS) $(GLIB_LIBS) $(JSON_C_LIBS)
%.pc: %.pc.in Makefile
tests/fail-only-once.sh \
tests/fail-always.sh
-serviceconfig_DATA += \
- tests/services/faultd-failed-service-with-recovery.service.conf \
- tests/services/faultd-failed-vip-service.service.conf
+srv_with_recovery_configdir = $(serviceconfigdir)/faultd-failed-service-with-recovery.service.conf.d
+srv_with_recovery_config_DATA = tests/services/faultd-failed-service-with-recovery.service.conf.d/50-default.conf
+
+vip_srv_configdir = $(serviceconfigdir)/faultd-failed-vip-service.service.conf.d
+vip_srv_config_DATA = tests/services/faultd-failed-vip-service.service.conf.d/50-default.conf
TEST_UNIT_FILES = \
tests/services/faultd-failed-service-always-failed.service \
vip_generator_SOURCES = \
generators/vip-generator.c \
src/util/common.c \
- src/util/systemd_dbus.c \
src/util/json-config.c \
src/util/log.c
+++ /dev/null
-{
- "ServiceType":"org.tizen.faultd.service.VIP"
-}
+++ /dev/null
-{
- "ServiceType":"org.tizen.faultd.service.VIP"
-}
{
- "standard_reboot_eh" : {
- "n_reboots_before_recovery" : 3
- },
- "standard_fault_eh" : {
- "n_fails_before_reboot" : 3
- }
}
#include <string.h>
#include <errno.h>
#include <sys/stat.h>
-#include <dirent.h>
#include "service.h"
#include "json-config.h"
static const char *dest_path = "/tmp/";
-static char *get_next_file(DIR *conf_dir)
-{
- struct dirent *d;
-
- while (1) {
- d = readdir(conf_dir);
- if (d == NULL)
- return NULL;
-
- if (strcmp(d->d_name, ".") == 0 ||
- strcmp(d->d_name, "..") == 0) {
-
- continue;
- }
-
- return d->d_name;
- }
-}
-
static int create_dir(const char *path)
{
if (mkdir(path, 0755) != 0) {
return 0;
}
-static char *get_service_name(char *conf_name)
-{
- const char *suffix = ".conf";
- int suffixlen = strlen(suffix);
-
- int len = strlen(conf_name);
- int prefixlen = len - suffixlen;
-
- if (len > suffixlen && strcmp(&conf_name[prefixlen], suffix) == 0)
- return strndup(conf_name, prefixlen);
- else
- return NULL;
-}
-
static int create_vip_service_override(const char *service_name)
{
FILE *fp;
char *service_override;
int ret;
- ret = asprintf(&location, "%s/%s.d", dest_path, service_name);
+ ret = asprintf(&location, "%s/%s.conf.d", dest_path, service_name);
if (ret == -1)
return -errno;
return 0;
}
-static void init_systemd_service(struct systemd_service *s)
-{
- assert(s);
-
- s->dbus_path = NULL;
- s->service_type = NULL;
- s->recovery_unit = NULL;
-}
-
-static void free_systemd_service(struct systemd_service *s)
-{
- if (s) {
- free(s->dbus_path);
- free(s->service_type);
- free(s->recovery_unit);
- }
-}
-
int main(int argc, char *argv[])
{
- DIR *config_dir;
struct systemd_service s;
- char *service_name;
- char *service_config;
+ struct json_object *services_config = json_object_new_object();
int ret;
/*
if (argc > 1)
dest_path = argv[2];
- config_dir = opendir(FAULTD_SERVICES_CONFIG_PATH);
- if (!config_dir) {
- log_error("Unable to open directory %s: %m", FAULTD_SERVICES_CONFIG_PATH);
- return EXIT_FAILURE;
+ /* load services configuration into json object */
+ ret = load_config(FAULTD_DEFAULT_SERVICES_CONFIG_PATH, CONFIG_TYPE_DIR, 0,
+ services_config);
+ if (ret) {
+ log_error("Unable to load services config %s", FAULTD_DEFAULT_SERVICES_CONFIG_PATH);
+ json_object_put(services_config);
+ return ret;
}
- while ((service_config = get_next_file(config_dir)) != NULL) {
- init_systemd_service(&s);
+ ret = load_config(FAULTD_CUSTOM_SERVICES_CONFIG_PATH, CONFIG_TYPE_DIR, 0,
+ services_config);
+ if (ret) {
+ log_error("Unable to load services config %s", FAULTD_CUSTOM_SERVICES_CONFIG_PATH);
+ json_object_put(services_config);
+ return ret;
+ }
- service_name = get_service_name(service_config);
- if (service_name == NULL) {
- log_error("Unable to get service name from config: %s", service_config);
- goto cleanup;
- }
+ /*
+ * iterate through every config node and create override unit file if
+ * the service is of VIP type
+ */
- ret = asprintf(&service_config, FAULTD_SERVICES_CONFIG_PATH "%s", service_config);
- if (ret == -1) {
- log_error("Unable to allocate string: %s", strerror(errno));
- goto cleanup;
- }
+ json_object_object_foreach(services_config, service_name, node) {
+ s.service_type = NULL;
- ret = parse_service_config(service_config, &s);
- if (ret != 0) {
- log_error("Unable to parse config file: %s", service_config);
- free(service_config);
- goto cleanup;
+ ret = get_config_field(node, "ServiceType", &s.service_type, json_type_string);
+ if (ret) {
+ log_error("Unable to get service type for %s", service_name);
+ continue;
}
- free(service_config);
-
if (systemd_service_is_of_type(&s, FAULTD_SERVICE_TYPE_VIP)) {
ret = create_vip_service_override(service_name);
- if (ret != 0)
+ if (ret)
log_error("Unable to create override for VIP service %s: %s\n",
service_name, strerror(ret));
}
- cleanup:
- free(service_name);
- free_systemd_service(&s);
+ free(s.service_type);
}
- closedir(config_dir);
+ json_object_put(services_config);
return 0;
}
--- /dev/null
+{
+ "n_fails_before_reboot" : 3
+}
--- /dev/null
+{
+ "n_reboots_before_recovery" : 3
+}
%manifest %{name}.manifest
%{_localstatedir}/db/faultd
%{_sbindir}/faultd
-%{_sysconfdir}/faultd/faultd.conf
-%{_sysconfdir}/faultd/conf.d/dbus.service.conf
-%{_sysconfdir}/faultd/conf.d/display-manager.service.conf
+%{_prefix}/lib/faultd/faultd.conf
+%{_prefix}/lib/faultd/service.conf.d/dbus.service.conf.d/50-default.conf
+%{_prefix}/lib/faultd/service.conf.d/display-manager.service.conf.d/50-default.conf
%{_unitdir}/faultd.service
%{_unitdir}/basic.target.wants/faultd.service
%{_prefix}/lib/systemd/system-generators/vip-generator
%files extra -f faultd-extra-files
+%{_prefix}/lib/faultd/modules.conf.d/standard_fault_eh.conf.d/50-default.conf
+%{_prefix}/lib/faultd/modules.conf.d/standard_reboot_eh.conf.d/50-default.conf
%files test-services
%{_bindir}/faultd/leaker
%{_unitdir}/faultd-failed-vip-service.service
%{_unitdir}/faultd-recovery-service.service
%{_unitdir}/faultd-res-leak.service
-%{_sysconfdir}/faultd/conf.d/faultd-failed-service-with-recovery.service.conf
-%{_sysconfdir}/faultd/conf.d/faultd-failed-vip-service.service.conf
+%{_prefix}/lib/faultd/service.conf.d/faultd-failed-service-with-recovery.service.conf.d/50-default.conf
+%{_prefix}/lib/faultd/service.conf.d/faultd-failed-vip-service.service.conf.d/50-default.conf
%docs_package
--- /dev/null
+{
+ "ServiceType":"org.tizen.faultd.service.VIP"
+}
--- /dev/null
+{
+ "ServiceType":"org.tizen.faultd.service.VIP"
+}
#include "common.h"
#include "faultd-config.h"
+#include "json-config.h"
#include "log.h"
#include "module.h"
-static int parse_disable_modules(struct json_object *root)
+static struct faultd_config modules_config;
+static struct faultd_config services_config;
+
+void faultd_get_modules_config(struct faultd_config **c)
{
- struct json_object *node;
+ *c = &modules_config;
+}
+
+void faultd_get_services_config(struct faultd_config **c)
+{
+ *c = &services_config;
+}
+
+static int parse_disable_modules(void)
+{
+ struct json_object *root, *node;
const char *name;
struct faultd_module *module;
- int i;
- int len;
+ int len, ret;
+
+ ret = json_object_object_get_ex(modules_config.root, "disable_modules", &root);
+ if (ret == 0)
+ return 0;
len = json_object_array_length(root);
- for (i = 0; i < len; ++i) {
+ for (int i = 0; i < len; ++i) {
node = json_object_array_get_idx(root, i);
if (!node)
return -EINVAL;
return 0;
}
-int faultd_parse_config(const char *config_path, struct faultd_config *c)
+static int init_config(void)
{
- struct json_object *root;
- struct json_object *node;
- int ret = 0;
- json_bool json_ret;
+ modules_config.root = json_object_new_object();
+ if (!modules_config.root) {
+ log_error("Unable to create new json object");
+ return -ENOMEM;
+ }
- root = json_object_from_file(config_path);
- if (is_error(root)) {
- log_error("Could not create object from json file %s", config_path);
- return -EINVAL;
+ services_config.root = json_object_new_object();
+ if (!services_config.root) {
+ log_error("Unable to create new json object");
+ json_object_put(modules_config.root);
+ return -ENOMEM;
}
- json_ret = json_object_object_get_ex(root, "disable_modules", &node);
- if (json_ret) {
- ret = parse_disable_modules(node);
- if (ret < 0) {
- log_error("Could not parse configuration file %s", config_path);
- goto out;
- }
+ return 0;
+}
+
+static void log_config(void)
+{
+ log_debug("Modules config root:\n\n%s\n",
+ json_object_to_json_string_ext(modules_config.root, JSON_C_TO_STRING_PRETTY));
+
+ log_debug("Services config root:\n\n%s\n",
+ json_object_to_json_string_ext(services_config.root, JSON_C_TO_STRING_PRETTY));
+}
+
+int faultd_load_config(const char *custom_config_file)
+{
+ int ret;
+
+ ret = init_config();
+ if (ret)
+ return ret;
+
+ ret = load_config(FAULTD_DEFAULT_CONFIG_FILE, CONFIG_TYPE_FILE, 1,
+ modules_config.root);
+ if (ret)
+ goto cleanup;
+
+ ret = load_config(FAULTD_DEFAULT_MODULES_CONFIG_PATH, CONFIG_TYPE_DIR, 0,
+ modules_config.root);
+ if (ret)
+ goto cleanup;
+
+ ret = load_config(FAULTD_DEFAULT_SERVICES_CONFIG_PATH, CONFIG_TYPE_DIR, 0,
+ services_config.root);
+ if (ret)
+ goto cleanup;
+
+ ret = load_config(custom_config_file, CONFIG_TYPE_FILE, 1,
+ modules_config.root);
+ if (ret)
+ goto cleanup;
+
+ ret = load_config(FAULTD_CUSTOM_MODULES_CONFIG_PATH, CONFIG_TYPE_DIR, 1,
+ modules_config.root);
+ if (ret)
+ goto cleanup;
+
+ ret = load_config(FAULTD_CUSTOM_SERVICES_CONFIG_PATH, CONFIG_TYPE_DIR, 1,
+ services_config.root);
+ if (ret)
+ goto cleanup;
+
+ log_config();
+
+ ret = parse_disable_modules();
+ if (ret) {
+ log_error("Could not parse disable_modules section");
+ goto cleanup;
}
- c->root = root;
return 0;
-out:
- json_object_put(root);
+cleanup:
+ json_object_put(modules_config.root);
+ json_object_put(services_config.root);
return ret;
}
json_object_put(c->root);
}
+void faultd_config_cleanup_global(void)
+{
+ faultd_config_cleanup(&modules_config);
+ faultd_config_cleanup(&services_config);
+}
+
int faultd_config_get_subconf(struct faultd_config *conf, const char *key, struct faultd_config **sub)
{
struct faultd_config *config_node;
struct json_object *root;
};
-int faultd_parse_config(const char *config_path, struct faultd_config *c);
+void faultd_get_modules_config(struct faultd_config **c);
+void faultd_get_services_config(struct faultd_config **c);
+int faultd_load_config(const char *custom_config_file);
void faultd_config_cleanup(struct faultd_config *c);
+void faultd_config_cleanup_global(void);
int faultd_config_get_subconf(struct faultd_config *conf, const char *key, struct faultd_config **sub);
#endif /* FAULTD_CONFIG_H */
#include "common.h"
#include "systemd_dbus.h"
#include "json-config.h"
+#include "faultd-config.h"
int systemd_service_init_by_pid(pid_t pid, struct systemd_service *s)
{
return systemd_service_init(n, s);
}
-static int get_service_config_path(const char *dbus_path, char **config_path)
+static int get_service_name(const char *dbus_path, char **service_name)
{
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
_cleanup_(sd_bus_unrefp) sd_bus *bus = NULL;
log_debug("Service Id: %s", name);
- ret = asprintf(config_path, FAULTD_SERVICES_CONFIG_PATH "/%s.conf", name);
- if (ret < 0) {
- log_error("Could not allocate service configuration path: %m");
+ *service_name = strdup(name);
+ if (*service_name == NULL) {
+ log_error("Unable to allocate string");
return -ENOMEM;
}
int systemd_service_init(const char *dbus_path, struct systemd_service *s)
{
- _cleanup_free_ char *config_path = NULL;
+ _cleanup_free_ char *service_name = NULL;
+ struct faultd_config *services_config = NULL;
+ struct json_object *node;
int ret;
assert(s);
if (!s->dbus_path)
return -ENOMEM;
- ret = get_service_config_path(dbus_path, &config_path);
- if (ret)
+ ret = get_service_name(dbus_path, &service_name);
+ if (ret < 0) {
+ log_error("Unable to get service name: %s", dbus_path);
goto cleanup_service;
+ }
- ret = access(config_path, F_OK | R_OK);
- /* if there is no config file then we are done */
- if (ret && errno == ENOENT)
+ faultd_get_services_config(&services_config);
+
+ if (!json_object_object_get_ex(services_config->root, service_name, &node)) {
+ log_debug("Service config does not contain %s node.", service_name);
return 0;
+ }
- if (ret) {
- log_error("Failed to access service configuration path: %m");
- ret = -errno;
+ ret = get_config_field(node, "RecoveryUnit", &s->recovery_unit, json_type_string);
+ if (ret < 0)
goto cleanup_service;
- }
- /* file exist so we need to parse it */
- ret = parse_service_config(config_path, s);
- if (ret) {
- log_error_errno(ret, "Failed to parse service configuration");
+ ret = get_config_field(node, "ServiceType", &s->service_type, json_type_string);
+ if (ret < 0)
goto cleanup_service;
- }
return 0;
#include "faultd-config.h"
#include "common.h"
#include "faultd-glib.h"
+#include "json-config.h"
static int terminate = 0;
-static struct faultd_config config;
static int signal_handler(sd_event_source *s,
const struct signalfd_siginfo *si,
};
struct faultd_module *module;
- const char *config_file = FAULTD_DEFAULT_CONFIG_FILE;
- bool using_default_config = 1;
+ const char *custom_config_file = FAULTD_CUSTOM_CONFIG_FILE;
while ((c = getopt_long(ac, av, "Dc:d:h", options, NULL)) >= 0) {
switch (c) {
break;
case 'c':
- config_file = optarg;
- using_default_config = 0;
-
+ custom_config_file = optarg;
break;
case 'h':
}
}
- r = access(config_file, F_OK | R_OK);
- if (r) {
- if (!using_default_config || errno != ENOENT) {
- log_error("Could not access config file %s", config_file);
- return -errno;
- }
-
- log_debug("No config file");
- config.root = json_object_new_object();
- if (!config.root)
- return -ENOMEM;
- } else {
- log_debug("Using config file: %s", config_file);
- r = faultd_parse_config(config_file, &config);
- if (r < 0)
- return r;
- }
-
- return 0;
+ return faultd_load_config(custom_config_file);
}
int main(int ac, char *av[])
sd_bus *bus = NULL;
sd_event *loop;
sigset_t ss;
+ struct faultd_config *modules_config = NULL;
rc = faultd_modules_load();
if (rc < 0) {
return -1;
}
- rc = faultd_modules_init(loop, &config);
+ faultd_get_modules_config(&modules_config);
+
+ rc = faultd_modules_init(loop, modules_config);
if (rc < 0) {
log_error("Failed to initialize modules %d.", rc);
return -1;
log_error_errno(rc, "Failed to run main loop: %m");
faultd_modules_cleanup();
- faultd_config_cleanup(&config);
+ faultd_config_cleanup_global();
sd_bus_close(bus);
#include <string.h>
#include <stdio.h>
#include <json-c/json.h>
+#include <dirent.h>
+#include <sys/stat.h>
#include "json-config.h"
#include "log.h"
+static int is_directory(const char *path)
+{
+ struct stat st;
+ int ret;
+
+ ret = stat(path, &st);
+ if (ret == -1) {
+ log_error("Unable to stat %s: %m", path);
+ return 0;
+ }
+ return st.st_mode & S_IFDIR;
+}
+
+static int check_suffix(const char *path, const char *suffix)
+{
+ int suffix_len = strlen(suffix);
+ int total_len = strlen(path);
+
+ if (total_len <= suffix_len)
+ return 0;
+
+ return strcmp(&path[total_len - suffix_len], suffix) == 0;
+}
+
+static int remove_last_n_chars(const char *src, size_t n,
+ char *dest, size_t dest_size)
+{
+ size_t len = strlen(src) - n;
+
+ if (len + 1 > dest_size) {
+ log_error("Destination buffer is too small");
+ return -EOVERFLOW;
+ }
+
+ strncpy(dest, src, len);
+ dest[len] = 0;
+
+ return 0;
+}
+
+static int config_filter(const struct dirent *d, const char *suffix)
+{
+ if (d->d_name[0] == '.')
+ return 0;
+
+ if (check_suffix(d->d_name, suffix))
+ return 1;
+
+ return 0;
+}
+
+static int config_dir_filter(const struct dirent *d)
+{
+ return config_filter(d, ".conf.d");
+}
+
+static int config_file_filter(const struct dirent *d)
+{
+ return config_filter(d, ".conf");
+}
+
+static int json_object_object_merge(json_object *obj1, char *key, json_object *obj2_node)
+{
+ json_object *obj1_node = NULL;
+ int ret;
+
+ ret = json_object_object_get_ex(obj1, key, &obj1_node);
+
+ /* if there is no such object in obj1 - add it */
+ if (ret == 0)
+ goto json_add;
+
+ if (obj1_node == NULL) {
+ log_error("Unable to get json object");
+ return -ENOMEM;
+ }
+
+ /* if there is, but obj1 or obj2 is not json_type_object - replace it */
+ if (!json_object_is_type(obj1_node, json_type_object) ||
+ !json_object_is_type(obj2_node, json_type_object)) {
+
+ json_object_object_del(obj1, key);
+ goto json_add;
+ }
+
+ /* if obj1 and obj2 is json_object_type */
+ json_object_object_foreach(obj2_node, k, v) {
+ ret = json_object_object_merge(obj1_node, k, v);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+
+json_add:
+ json_object_get(obj2_node);
+ json_object_object_add(obj1, key, obj2_node);
+ return 0;
+}
+
+static int json_object_merge_with_file(json_object *existing_node, const char *file)
+{
+ struct json_object *new_node;
+ int ret;
+
+ new_node = json_object_from_file(file);
+ if (new_node == NULL) {
+ log_error("Could not create object from json file %s", file);
+ return -EINVAL;
+ }
+
+ json_object_object_foreach(new_node, key, val) {
+ ret = json_object_object_merge(existing_node, key, val);
+ if (ret)
+ goto cleanup;
+ }
+
+cleanup:
+ json_object_put(new_node);
+ return ret;
+}
+
+static int assemble_config_from_dir(const char *path, json_object *config)
+{
+ int num;
+ struct dirent **list;
+ char filename[PATH_MAX];
+ int ret;
+
+ /* search for *.conf files for this module */
+ num = scandir(path, &list, config_file_filter, alphasort);
+ if (num < 0)
+ return num;
+
+ while (num--) {
+ /* get full path of the config file */
+ ret = snprintf(filename, sizeof(filename), "%s/%s", path, list[num]->d_name);
+ free(list[num]);
+ if (ret >= (int) sizeof(filename)) {
+ log_error("Unable to copy string");
+ goto error;
+ }
+
+ log_debug("Using config file: %s", filename);
+
+ /* merge config into existing json object */
+ ret = json_object_merge_with_file(config, filename);
+ if (ret < 0)
+ goto error;
+ }
+
+ free(list);
+ return 0;
+
+error:
+ while (num--)
+ free(list[num]);
+ free(list);
+ return ret;
+}
+
+static int load_multidir_config(const char *path, struct json_object *c)
+{
+ int num;
+ struct dirent **list;
+ char dir_path[PATH_MAX], obj_name[PATH_MAX];
+ struct json_object *obj_config = NULL;
+ int ret;
+
+ /* search for *.conf.d directories */
+ num = scandir(path, &list, config_dir_filter, alphasort);
+ if (num < 0) {
+ /* dir doesn't exist */
+ if (errno == ENOENT) {
+ log_debug("Config dir doesn't exist %s", path);
+ return -ENOENT;
+ }
+
+ /* dir exists but we are unable to access it*/
+ log_error("Could not access config dir %s", path);
+ return -errno;
+ }
+
+ while (num--) {
+ /* get full path of the config dir */
+ ret = snprintf(dir_path, sizeof(dir_path), "%s/%s", path, list[num]->d_name);
+ free(list[num]);
+ if (ret >= (int) sizeof(dir_path)) {
+ log_error("Unable to copy string");
+ goto error;
+ }
+
+ if (!is_directory(dir_path))
+ continue;
+
+ /* get object name out of directory path */
+ ret = remove_last_n_chars(basename(dir_path), strlen(".conf.d"),
+ obj_name, sizeof(obj_name));
+ if (ret)
+ goto error;
+
+ /* get existing config for present object */
+ ret = json_object_object_get_ex(c, obj_name, &obj_config);
+ if (ret == 0) {
+ obj_config = json_object_new_object();
+ json_object_object_add(c, obj_name, obj_config);
+ }
+
+ if (obj_config == NULL) {
+ log_error("Unable to create new json object");
+ ret = -ENOMEM;
+ goto error;
+ }
+
+ /* merge another config with existing one */
+ ret = assemble_config_from_dir(dir_path, obj_config);
+ if (ret < 0) {
+ log_error("Unable to assemble config for object %s", obj_name);
+ json_object_put(obj_config);
+ goto error;
+ }
+ }
+
+ free(list);
+ return 0;
+
+error:
+ while (num--)
+ free(list[num]);
+ free(list);
+ return ret;
+}
+
+static int load_single_config(const char *config_path, struct json_object *c)
+{
+ int ret = 0;
+
+ ret = access(config_path, F_OK | R_OK);
+ if (ret) {
+ /* file doesn't exist */
+ if (errno == ENOENT) {
+ log_debug("Config file doesn't exist %s", config_path);
+ return -ENOENT;
+ }
+
+ /* file exists but we are unable to access it*/
+ log_error("Could not access config file %s", config_path);
+ return -errno;
+ }
+
+ /* file exists and we are able to access it*/
+ log_debug("Using config file: %s", config_path);
+
+ ret = json_object_merge_with_file(c, config_path);
+ if (ret) {
+ log_error("Unable to load config %s", config_path);
+ return ret;
+ }
+
+ return 0;
+}
+
+int load_config(const char *src, int type, int optional, struct json_object *c)
+{
+ int ret;
+
+ switch (type) {
+ case CONFIG_TYPE_FILE:
+ ret = load_single_config(src, c);
+ break;
+
+ case CONFIG_TYPE_DIR:
+ ret = load_multidir_config(src, c);
+ break;
+
+ default:
+ log_error("Wrong config type");
+ return -EINVAL;
+ }
+
+ if ((ret < 0 && ret != -ENOENT) || (ret == -ENOENT && !optional))
+ return ret;
+
+ return 0;
+}
+
int get_config_field(struct json_object *root, const char *key, void *value, int type)
{
struct json_object *node = NULL;
return 0;
}
-
-int parse_service_config(const char *config_path,
- struct systemd_service *s)
-{
- struct json_object *root;
- int ret;
-
- root = json_object_from_file(config_path);
- if (is_error(root)) {
- log_error("Could not create json object from file %s", config_path);
- return -1;
- }
-
- ret = get_config_field(root, "RecoveryUnit", &s->recovery_unit, json_type_string);
- if (ret < 0)
- goto out;
-
- ret = get_config_field(root, "ServiceType", &s->service_type, json_type_string);
-
-out:
- json_object_put(root);
- return ret;
-}
#include "service.h"
+enum config_type {
+ CONFIG_TYPE_FILE,
+ CONFIG_TYPE_DIR
+};
+
+int load_config(const char *src, int type, int optional, struct json_object *c);
int get_config_field(struct json_object *root, const char *key, void *value, int type);
-int parse_service_config(const char *config_path, struct systemd_service *s);
#endif /* FAULTD_JSON_CONFIG_H */
+++ /dev/null
-{
- "RecoveryUnit": "faultd-recovery-service.service"
-}
--- /dev/null
+{
+ "RecoveryUnit": "faultd-recovery-service.service"
+}
+++ /dev/null
-{
- "ServiceType": "org.tizen.faultd.service.VIP"
-}
--- /dev/null
+{
+ "ServiceType": "org.tizen.faultd.service.VIP"
+}