Rework packaging 97/201797/14
authorPaweł Szewczyk <p.szewczyk@samsung.com>
Fri, 15 Mar 2019 12:40:03 +0000 (13:40 +0100)
committerPaweł Szewczyk <p.szewczyk@samsung.com>
Tue, 26 Mar 2019 12:06:34 +0000 (13:06 +0100)
Change-Id: I2992ba6a8e928c9763eaeb1c55dd614fb12848d9
Signed-off-by: Paweł Szewczyk <p.szewczyk@samsung.com>
20 files changed:
Makefile.am
activationd/Makefile.am [deleted file]
activationd/configs/activationd-acceptance-test.service [deleted file]
activationd/decision_makers/activation_dm.c [deleted file]
activationd/event_types/vconf_key_changed_event.c [deleted file]
activationd/include/vconf_key_changed_event.h [deleted file]
activationd/listeners/vconf.c [deleted file]
activationd/tests/activationd_acceptance_checker.c [deleted file]
activationd/tests/activationd_acceptance_service.c [deleted file]
activationd/tests/activationd_acceptance_test [deleted file]
configure.ac
include/vconf_key_changed_event.h [new file with mode: 0644]
packaging/activationd.spec
src/decision_makers/activation_dm.c [new file with mode: 0644]
src/event_types/vconf_key_changed_event.c [new file with mode: 0644]
src/listeners/vconf.c [new file with mode: 0644]
tests/activationd-acceptance-test.service [new file with mode: 0644]
tests/activationd_acceptance_checker.c [new file with mode: 0644]
tests/activationd_acceptance_service.c [new file with mode: 0644]
tests/activationd_acceptance_test [new file with mode: 0755]

index aa0f0cb9eeda46668b5f2f31841fa2f19434ac9d..3848b358405bfe1ac662062dabf7f5bb8744ec39 100644 (file)
@@ -44,9 +44,11 @@ AM_CFLAGS = \
        -fPIE \
        -rdynamic \
        $(GLIB_CFLAGS) \
+       $(VCONF_CFLAGS) \
        -D"EPC_MODNAME_T=$(call name_fix,$(modname))"
 
 AM_LDFLAGS = \
+       $(VCONF_LIBS) \
        -Wl,--gc-sections \
        -Wl,--as-needed \
        -avoid-version \
@@ -122,10 +124,22 @@ pkgconfig_DATA = src/epc.pc
 modulesdir = $(pkglibdir)/available-modules
 modules_LTLIBRARIES = \
                  service_restart_action.la \
-                 unit_start_action.la
+                 unit_start_action.la \
+                 vconf_key_changed_event.la \
+                 activation_dm.la \
+                 vconf_listener.la
 
 service_restart_action_la_SOURCES = src/action/service_restart.c
 unit_start_action_la_SOURCES = src/action/unit_start.c
+vconf_key_changed_event_la_SOURCES = src/event_types/vconf_key_changed_event.c
+activation_dm_la_SOURCES = src/decision_makers/activation_dm.c
+activation_dm_config_DATA = modules.conf.d/activation_eh.conf.d/activation_eh.conf
+activation_dm_config_DATA += modules.conf.d/activation_eh.conf.d/99-acceptance-test.conf
+activation_dm_configdir = $(modulesconfigdir)/activation_eh.conf.d
+vconf_listener_la_SOURCES = src/listeners/vconf.c
+vconf_listener_config_DATA = modules.conf.d/vconf_listener.conf.d/50-default.conf
+vconf_listener_config_DATA += modules.conf.d/vconf_listener.conf.d/99-acceptance-test.conf
+vconf_listener_configdir = $(modulesconfigdir)/vconf_listener.conf.d
 
 epcd_LDADD = $(LIBSYSTEMD_LIBS) $(GLIB_LIBS) $(JSON_C_LIBS)
 
@@ -166,4 +180,31 @@ install-data-local:
        $(MKDIR_P) $(DESTDIR)$(sysconfdir)/epc/available-modules
        $(MKDIR_P) $(DESTDIR)$(sysconfdir)/epc/enabled-modules
 
-SUBDIRS = activationd
+
+bin_PROGRAMS = activationd_acceptance_checker
+
+activationd_acceptance_checker_SOURCES = \
+       tests/activationd_acceptance_checker.c
+
+activationd_acceptance_checker_CFLAGS = $(AM_CFLAGS)
+activationd_acceptance_checker_LDFLAGS = $(VCONF_LIBS) $(LIBSYSTEMD_LIBS)
+
+bin_PROGRAMS += activationd_acceptance_service
+
+activationd_acceptance_service_SOURCES = \
+       tests/activationd_acceptance_service.c
+
+activationd_acceptance_service_CFLAGS = $(AM_CFLAGS)
+activationd_acceptance_service_LDFLAGS =
+
+bin_SCRIPTS = tests/activationd_acceptance_test
+
+unitdir = $(prefix)/lib/systemd/system
+unit_DATA = \
+                       tests/activationd-acceptance-test.service
+
+configdir = $(prefix)/lib/epc
+modulesconfigdir = $(configdir)/modules.conf.d
+
+install-data-local:
+       $(MKDIR_P) $(DESTDIR)${vconf_listener_configdir}
diff --git a/activationd/Makefile.am b/activationd/Makefile.am
deleted file mode 100644 (file)
index 46e0135..0000000
+++ /dev/null
@@ -1,78 +0,0 @@
-AM_LDFLAGS = $(VCONF_LIBS) \
-       -Wl,--gc-sections \
-       -Wl,--as-needed \
-       -avoid-version \
-       -module \
-       -shared \
-       -pie
-
-AM_CPPFLAGS = -I${top_srcdir}/include \
-             -I${top_srcdir}/activationd/include
-
-basetarget = $(basename $(notdir $@))
-modname = $(basetarget)
-name_fix = $(subst $(comma),_,$(subst -,_,$1))
-
-AM_CFLAGS = \
-       -Wall \
-       -Wchar-subscripts \
-       -Wformat-security \
-       -Wmissing-declarations \
-       -Wmissing-prototypes \
-       -Wnested-externs \
-       -Wpointer-arith \
-       -Wshadow \
-       -Wsign-compare \
-       -Wstrict-prototypes \
-       -Wtype-limits \
-       -D_GNU_SOURCE=1 \
-       -fPIE \
-       -rdynamic \
-       $(GLIB_CFLAGS) \
-       $(VCONF_CFLAGS) \
-       $(LIBSYSTEMD_CFLAGS) \
-       -D"EPC_MODNAME_T=$(call name_fix,$(modname))"
-
-modulesdir = $(pkglibdir)/available-modules
-modules_LTLIBRARIES = \
-                 vconf_key_changed_event.la \
-                 activation_dm.la \
-                 vconf_listener.la
-
-vconf_key_changed_event_la_SOURCES = event_types/vconf_key_changed_event.c
-activation_dm_la_SOURCES = decision_makers/activation_dm.c
-activation_dm_config_DATA = ../modules.conf.d/activation_eh.conf.d/activation_eh.conf
-activation_dm_config_DATA += ../modules.conf.d/activation_eh.conf.d/99-acceptance-test.conf
-activation_dm_configdir = $(modulesconfigdir)/activation_eh.conf.d
-vconf_listener_la_SOURCES = listeners/vconf.c
-vconf_listener_config_DATA = ../modules.conf.d/vconf_listener.conf.d/50-default.conf
-vconf_listener_config_DATA += ../modules.conf.d/vconf_listener.conf.d/99-acceptance-test.conf
-vconf_listener_configdir = $(modulesconfigdir)/vconf_listener.conf.d
-
-bin_PROGRAMS = activationd_acceptance_checker
-
-activationd_acceptance_checker_SOURCES = \
-       tests/activationd_acceptance_checker.c
-
-activationd_acceptance_checker_CFLAGS = $(AM_CFLAGS)
-activationd_acceptance_checker_LDFLAGS = $(VCONF_LIBS) $(LIBSYSTEMD_LIBS)
-
-bin_PROGRAMS += activationd_acceptance_service
-
-activationd_acceptance_service_SOURCES = \
-       tests/activationd_acceptance_service.c
-
-activationd_acceptance_service_CFLAGS = $(AM_CFLAGS)
-activationd_acceptance_service_LDFLAGS =
-
-bin_SCRIPTS = tests/activationd_acceptance_test
-
-unitdir = $(prefix)/lib/systemd/system
-unit_DATA = \
-                       configs/activationd-acceptance-test.service
-
-configdir = $(prefix)/lib/epc
-modulesconfigdir = $(configdir)/modules.conf.d
-
-install-data-local:
-       $(MKDIR_P) $(DESTDIR)${vconf_listener_configdir}
diff --git a/activationd/configs/activationd-acceptance-test.service b/activationd/configs/activationd-acceptance-test.service
deleted file mode 100644 (file)
index 8d905ba..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-[Unit]
-Description=activationd acceptance tests service
-
-[Service]
-Type=simple
-ExecStart=/usr/bin/activationd_acceptance_service
diff --git a/activationd/decision_makers/activation_dm.c b/activationd/decision_makers/activation_dm.c
deleted file mode 100644 (file)
index fccceca..0000000
+++ /dev/null
@@ -1,350 +0,0 @@
-/*
- * This file is part of activationd.
- *
- * Copyright © 2019 Samsung Electronics
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-#include <malloc.h>
-#include <errno.h>
-
-#include "decision_made_event.h"
-#include "action.h"
-#include "event_processor.h"
-#include "log.h"
-#include "service.h"
-#include "common.h"
-#include "database.h"
-#include "json-config.h"
-
-#include "vconf_key_changed_event.h"
-
-#define MODULE_NAME "activation_decision_maker"
-
-struct activation_decision_maker {
-       struct epc_event_handler eh;
-       struct list_head rules;
-};
-
-struct rule {
-       const char *event;
-       void *ev_data;
-       bool match_oldval;
-       bool match_newval;
-       const char *action;
-       const char *target;
-
-       struct list_head node;
-};
-
-static int activation_event_match(struct epc_event_handler *handler,
-               struct epc_event *ev)
-{
-       if (strcmp(ev->type->name, VCONF_KEY_CHANGED_EVENT_ID) == 0)
-                       return 1;
-
-       return 0;
-}
-
-static int vconf_field_cmp(struct vkc_value *a, struct vkc_value *b)
-{
-       if (a->type != b->type)
-               return 0;
-
-       switch (a->type){
-       case VKC_BOOL:
-               return a->value.b == b->value.b;
-       case VKC_INT:
-               return a->value.i == b->value.i;
-       case VKC_DOUBLE:
-               return a->value.d == b->value.d;
-       case VKC_STRING:
-               return strcmp(a->value.s, b->value.s) == 0;
-       }
-}
-
-static int vconf_rule_match(struct rule *r, struct epc_event *event)
-{
-       struct vconf_key_changed_event *ev = to_vconf_key_changed_event(event);
-       struct vconf_key_changed_event_data *ev_data = r->ev_data;
-
-       if (ev_data->key_name && strcmp(ev_data->key_name, ev->key_name))
-               return 0;
-
-       if (r->match_oldval && !vconf_field_cmp(&ev_data->oldval, &ev->oldval))
-               return 0;
-
-       if (r->match_newval && !vconf_field_cmp(&ev_data->newval, &ev->newval))
-               return 0;
-
-       return 1;
-}
-
-static int execute_rule(struct rule *r, struct epc_event *ev)
-{
-       struct dm_event_data ev_data = {
-               .reason = ev,
-               .who_made = MODULE_NAME,
-       };
-       struct epc_event *new_ev;
-       int ret;
-
-       ev_data.action = EPC_ACTION_UNIT_START_ID;
-       ret = epc_object_new(&ev_data.action_data);
-       if (ret < 0) {
-               log_error("Could not create data object for action");
-               goto out;
-       }
-
-       ret = epc_fill_for_unit_start(ev_data.action_data, r->target);
-       if (ret) {
-               log_error("Unable to create event data");
-               goto out;
-       }
-       epc_fill_for_unit_action(ev_data.action_data, r->action);
-
-       ret = epc_event_create(DECISION_MADE_EVENT_ID, &ev_data, &new_ev);
-       if (ret) {
-               log_error("Unable to create event");
-               goto out;
-       }
-
-       ret = event_processor_report_event(new_ev);
-       epc_event_unref(new_ev);
-       if (ret) {
-               log_error("Unable to report event");
-               goto out;
-       }
-
-out:
-       epc_object_unref(ev_data.action_data);
-       return ret;
-}
-
-static int activation_make_decision(struct epc_event_handler *handler)
-{
-       struct epc_event *ev = pop_epc_event(&handler->event_queue);
-       struct activation_decision_maker *dm = container_of(handler,
-                       struct activation_decision_maker, eh);
-       int ret;
-       struct rule *r;
-
-       list_for_each_entry(r, &dm->rules, node) {
-               if (strcmp(r->event, ev->type->name))
-                       continue;
-
-               if (!strcmp(ev->type->name, VCONF_KEY_CHANGED_EVENT_ID) == 0 ||
-                               !vconf_rule_match(r, ev))
-                       continue;
-
-               ret = execute_rule(r, ev);
-               if (ret < 0)
-                       break;
-       }
-
-       epc_object_unref(ev);
-       return 0;
-}
-
-static int parse_vconf_field(json_object *root, const char *key, struct vkc_value *value)
-{
-       struct json_object *node = NULL;
-       enum json_type type;
-       char *str;
-
-       if (!json_object_object_get_ex(root, key, &node)) {
-               log_debug("Config does not contain %s parameter", key);
-               return -1;
-       }
-
-       type = json_object_get_type(node);
-
-       switch (type) {
-       case json_type_boolean:
-               value->type = VKC_BOOL;
-               value->value.b = json_object_get_boolean(node);
-               break;
-       case json_type_double:
-               value->type = VKC_DOUBLE;
-               value->value.d = json_object_get_double(node);
-               break;
-       case json_type_int:
-               value->type = VKC_INT;
-               value->value.i = json_object_get_int(node);
-               break;
-       case json_type_string:
-               value->type = VKC_STRING;
-               str = json_object_get_string(node);
-               if (!str)
-                       goto err;
-
-               value->value.s = strdup(str);
-               break;
-       case json_type_array:
-       case json_type_object:
-               log_error("Field %s must have simple type", key);
-               return -EINVAL;
-               break;
-       case json_type_null:
-               return -EINVAL;
-               break;
-       }
-
-       return 0;
-
-err:
-       return -1;
-}
-
-static int parse_vconf_data(json_object *root, struct rule *r)
-{
-       struct vconf_key_changed_event_data *evd;
-       int ret;
-
-       evd = calloc(1, sizeof(*evd));
-       if (!evd)
-               return -ENOMEM;
-
-       (void) get_config_field(root, "key_name", &evd->key_name, json_type_string);
-       ret = parse_vconf_field(root, "oldval", &evd->oldval);
-       r->match_oldval = ret >= 0;
-       ret = parse_vconf_field(root, "newval", &evd->newval);
-       r->match_newval = ret >= 0;
-
-       r->ev_data = evd;
-
-       return 0;
-}
-
-static void rule_cleanup(struct rule *r)
-{
-       free(r->ev_data);
-}
-
-static void clean_rules(struct activation_decision_maker *dm)
-{
-       struct rule *r, *next;
-
-       list_for_each_entry_safe(r, next, &dm->rules, node) {
-               list_del_init(&r->node);
-               rule_cleanup(r);
-               free(r);
-       }
-}
-
-static int add_rule(struct activation_decision_maker *dm, json_object *root)
-{
-       int ret;
-       struct rule *r;
-       char *str;
-
-       r = calloc(1, sizeof(*r));
-       if (!r) {
-               log_error("Could not allocate rule object");
-               return -ENOMEM;
-       }
-
-       ret = get_config_field(root, "event", &r->event, json_type_string);
-       if (ret < 0)
-               goto out;
-
-       log_debug("Adding rule for event %s", r->event);
-
-       if (strcmp(r->event, VCONF_KEY_CHANGED_EVENT_ID) == 0) {
-               parse_vconf_data(root, r);
-       } else {
-               log_warning("Event type %s is not supported by activationd module\n", r->event);
-               goto out;
-       }
-
-       ret = get_config_field(root, "action", &r->action, json_type_string);
-       if (ret < 0)
-               goto out;
-
-       ret = get_config_field(root, "target", &r->target, json_type_string);
-       if (ret < 0)
-               goto out;
-
-       list_add_tail(&r->node, &dm->rules);
-
-       return 0;
-
-out:
-       rule_cleanup(r);
-       free(r);
-       return ret;
-}
-
-static int activation_init(struct epc_event_handler *handler, struct epc_config *config)
-{
-       struct activation_decision_maker *dm = container_of(handler,
-                       struct activation_decision_maker, eh);
-       int len;
-       int i;
-       int ret;
-       json_object *array, *obj;
-
-       INIT_LIST_HEAD(&dm->rules);
-
-       if (config == NULL)
-               return 0;
-
-       if (!json_object_object_get_ex(config->root, "rules", &array)) {
-               log_error("There are no 'rules' array");
-               return -EINVAL;
-       }
-
-       if (!json_object_is_type(array, json_type_array)) {
-               log_error("Config value is not an array");
-               return -EINVAL;
-       }
-
-       len = json_object_array_length(array);
-       for (i = 0; i < len; ++i) {
-               obj = json_object_array_get_idx(array, i);
-               ret = add_rule(dm, obj);
-               if (ret < 0) {
-                       log_error("Could not add rule");
-                       goto cleanup;
-               }
-       }
-
-       return 0;
-
-cleanup:
-       clean_rules(dm);
-       return ret;
-};
-
-static int activation_cleanup(struct epc_event_handler *handler)
-{
-       struct activation_decision_maker *dm = container_of(handler,
-                       struct activation_decision_maker, eh);
-
-       clean_rules(dm);
-}
-
-static struct activation_decision_maker activation_dm = {
-       .eh = {
-               .name = MODULE_NAME,
-               .init = activation_init,
-               .cleanup = activation_cleanup,
-               .event_match = activation_event_match,
-               .handle_event = activation_make_decision,
-
-               .node = LIST_HEAD_INIT(activation_dm.eh.node),
-       },
-};
-
-EPC_EVENT_HANDLER_REGISTER(activation_dm.eh, activation_eh,
-               EPC_MODULE_TYPE_DECISION_MAKER)
diff --git a/activationd/event_types/vconf_key_changed_event.c b/activationd/event_types/vconf_key_changed_event.c
deleted file mode 100644 (file)
index be87016..0000000
+++ /dev/null
@@ -1,193 +0,0 @@
-/*
- * This file is part of epc.
- *
- * Copyright © 2019 Samsung Electronics
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <stdio.h>
-#include <errno.h>
-#include <malloc.h>
-
-#include "vconf_key_changed_event.h"
-
-static int allocate_vkc_event(struct epc_event_type *type,
-                                                        void *data, struct epc_event **ev)
-{
-       struct vconf_key_changed_event *vkc_ev;
-       struct vconf_key_changed_event_data *vkc_ev_data = data;
-       int ret;
-
-       vkc_ev = calloc(1, sizeof(*vkc_ev));
-       if (!vkc_ev)
-               return -ENOMEM;
-
-       ret = epc_event_init_internal(type, &vkc_ev->event);
-       if (ret)
-               goto cleanup;
-
-       vkc_ev->event_time = vkc_ev_data->event_time;
-       vkc_ev->key_name = vkc_ev_data->key_name;
-       vkc_ev->oldval = vkc_ev_data->oldval;
-       vkc_ev->newval = vkc_ev_data->newval;
-
-       *ev = &vkc_ev->event;
-       return 0;
-cleanup:
-       free(vkc_ev);
-
-       return ret;
-}
-
-static int deserialize_vkc_event(struct epc_event_type *type,
-                                                               struct epc_object *data, struct epc_event **ev)
-{
-       int ret = -EINVAL;
-       struct vconf_key_changed_event_data vkc_ev_data;
-       struct epc_object *obj;
-       memset(&vkc_ev_data, 0, sizeof(vkc_ev_data));
-
-       list_for_each_entry(obj, &data->val.children, node) {
-               const bool oldval_match = !strcmp(VKC_EV_OLDVAL, obj->key);
-               const bool newval_match = !strcmp(VKC_EV_NEWVAL, obj->key);
-
-               switch (obj->type) {
-               case TYPE_TIME_T:
-                       if (!strcmp(VKC_EV_TIME, obj->key))
-                               vkc_ev_data.event_time = obj->val.time;
-                       break;
-               case TYPE_BOOL:
-                       if (oldval_match) {
-                               vkc_ev_data.oldval.value.b = obj->val.b;
-                               vkc_ev_data.oldval.type = VKC_BOOL;
-                       } else if (newval_match) {
-                               vkc_ev_data.newval.value.b = obj->val.b;
-                               vkc_ev_data.newval.type = VKC_BOOL;
-                       }
-                       break;
-               case TYPE_INT:
-                       if (oldval_match) {
-                               vkc_ev_data.oldval.value.i = obj->val.i;
-                               vkc_ev_data.oldval.type = VKC_INT;
-                       } else if (newval_match) {
-                               vkc_ev_data.newval.value.i = obj->val.i;
-                               vkc_ev_data.newval.type = VKC_INT;
-                       }
-                       break;
-               case TYPE_DOUBLE:
-                       if (oldval_match) {
-                               vkc_ev_data.oldval.value.d = obj->val.d;
-                               vkc_ev_data.oldval.type = VKC_DOUBLE;
-                       } else if (newval_match) {
-                               vkc_ev_data.newval.value.d = obj->val.d;
-                               vkc_ev_data.newval.type = VKC_DOUBLE;
-                       }
-                       break;
-               case TYPE_STRING:
-                       if (!strcmp(VKC_EV_NAME, obj->key)) {
-                               vkc_ev_data.key_name = obj->val.s;
-                       } else if (oldval_match) {
-                               vkc_ev_data.oldval.value.s = obj->val.s;
-                               vkc_ev_data.oldval.type = VKC_STRING;
-                       } else if (newval_match) {
-                               vkc_ev_data.newval.value.s = obj->val.s;
-                               vkc_ev_data.newval.type = VKC_STRING;
-                       }
-                       break;
-               }
-       }
-
-       ret = allocate_vkc_event(type, &vkc_ev_data, ev);
-       if (ret < 0)
-               goto finish;
-
-       ret = epc_event_deserialize_internal(data, type, *ev);
-       if (ret < 0) {
-               struct vconf_key_changed_event *vkc_ev =
-                       to_vconf_key_changed_event(*ev);
-               free(vkc_ev);
-               goto finish;
-       }
-       ret = 0;
-finish:
-       return ret;
-}
-
-static void vkc_event_release(struct epc_event *ev)
-{
-       struct vconf_key_changed_event *vkc_ev =
-               to_vconf_key_changed_event(ev);
-
-       if (vkc_ev->key_name)
-               free(vkc_ev->key_name);
-       if (vkc_ev->oldval.type == VKC_STRING)
-               free(vkc_ev->oldval.value.s);
-       if (vkc_ev->newval.type == VKC_STRING)
-               free(vkc_ev->newval.value.s);
-
-       epc_event_cleanup_internal(&vkc_ev->event);
-       free(vkc_ev);
-}
-
-static void vkc_event_serialize(struct epc_event *ev, struct epc_object *out)
-{
-       struct vconf_key_changed_event *vkc_ev =
-               to_vconf_key_changed_event(ev);
-       epc_event_serialize_internal(ev, out);
-       epc_object_append_string(out, VKC_EV_NAME, vkc_ev->key_name);
-
-       switch (vkc_ev->oldval.type) {
-       case VKC_BOOL:
-               epc_object_append_bool(out, VKC_EV_OLDVAL, vkc_ev->oldval.value.b);
-               break;
-       case VKC_INT:
-               epc_object_append_int(out, VKC_EV_OLDVAL, vkc_ev->oldval.value.i);
-               break;
-       case VKC_DOUBLE:
-               epc_object_append_double(out, VKC_EV_OLDVAL, vkc_ev->oldval.value.d);
-               break;
-       case VKC_STRING:
-               epc_object_append_string(out, VKC_EV_OLDVAL, vkc_ev->oldval.value.s);
-               break;
-       }
-
-       switch (vkc_ev->newval.type) {
-       case VKC_BOOL:
-               epc_object_append_bool(out, VKC_EV_NEWVAL, vkc_ev->newval.value.b);
-               break;
-       case VKC_INT:
-               epc_object_append_int(out, VKC_EV_NEWVAL, vkc_ev->newval.value.i);
-               break;
-       case VKC_DOUBLE:
-               epc_object_append_double(out, VKC_EV_NEWVAL, vkc_ev->newval.value.d);
-               break;
-       case VKC_STRING:
-               epc_object_append_string(out, VKC_EV_NEWVAL, vkc_ev->newval.value.s);
-               break;
-       }
-       epc_object_append_time_t(out, VKC_EV_TIME, vkc_ev->event_time);
-}
-
-static struct epc_event_type vconf_key_changed_event_type = {
-       .name = VCONF_KEY_CHANGED_EVENT_ID,
-       .default_ops = {
-               .release = vkc_event_release,
-               .serialize = vkc_event_serialize,
-       },
-       .allocate_event = allocate_vkc_event,
-       .deserialize_event = deserialize_vkc_event,
-       .node = LIST_HEAD_INIT(vconf_key_changed_event_type.node),
-};
-
-EPC_EVENT_TYPE_REGISTER(vconf_key_changed_event_type, vconf_key_changed_et)
diff --git a/activationd/include/vconf_key_changed_event.h b/activationd/include/vconf_key_changed_event.h
deleted file mode 100644 (file)
index 62f1708..0000000
+++ /dev/null
@@ -1,66 +0,0 @@
-/*
- * This file is a part of epc.
- *
- * Copyright © 2019 Samsung Electronics
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef _EPC_VCONF_KEY_CHANGED_EVENT_H
-#define _EPC_VCONF_KEY_CHANGED_EVENT_H
-
-#include <time.h>
-#include "event.h"
-
-#define VCONF_KEY_CHANGED_EVENT_ID "vconf_key_changed"
-#define VKC_EV_TIME "et"
-#define VKC_EV_NAME "name"
-#define VKC_EV_OLDVAL "oldval"
-#define VKC_EV_NEWVAL "newval"
-
-enum vkc_type {
-       VKC_BOOL,
-       VKC_INT,
-       VKC_DOUBLE,
-       VKC_STRING
-};
-
-struct vkc_value {
-       enum vkc_type type;
-       union {
-               bool b;
-               int i;
-               double d;
-               char *s;
-       } value;
-};
-
-struct vconf_key_changed_event {
-       struct epc_event event;
-       char *key_name;
-       struct vkc_value oldval;
-       struct vkc_value newval;
-       time_t event_time;
-};
-
-struct vconf_key_changed_event_data {
-       char *key_name;
-       struct vkc_value oldval;
-       struct vkc_value newval;
-       time_t event_time;
-};
-
-#define to_vconf_key_changed_event(EVENT)                                              \
-       container_of(EVENT, struct vconf_key_changed_event, event)
-
-#endif /* _EPC_VCONF_KEY_CHANGED_EVENT_H */
diff --git a/activationd/listeners/vconf.c b/activationd/listeners/vconf.c
deleted file mode 100644 (file)
index df639f7..0000000
+++ /dev/null
@@ -1,324 +0,0 @@
-/*
- * This file is part of epc.
- *
- * Copyright © 2019 Samsung Electronics
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <vconf.h>
-#include <glib.h>
-#include <time.h>
-
-#include "log.h"
-#include "module.h"
-#include "common.h"
-#include "list.h"
-#include "json-config.h"
-#include "event_processor.h"
-#include "vconf_key_changed_event.h"
-
-struct vconf_kv {
-       char *name;
-       struct vkc_value val;
-       struct list_head node;
-};
-
-struct vconf_listener {
-       struct epc_module module;
-       struct list_head keys;
-};
-
-#define to_vconf_listener(MOD)                                         \
-       container_of(MOD, struct vconf_listener, module)
-
-static struct vconf_kv *find_vconf_kv(struct vconf_listener *l, const char *name)
-{
-       struct vconf_kv *k = NULL;
-
-       list_for_each_entry(k, &l->keys, node) {
-               if (!strcmp(k->name, name))
-                       return k;
-       }
-       return NULL;
-}
-
-static int copy_vkc_value(struct vkc_value *from, struct vkc_value *to)
-{
-       to->type = from->type;
-       switch (from->type){
-       case VKC_BOOL:
-               to->value.b = from->value.b;
-               break;
-       case VKC_INT:
-               to->value.i = from->value.i;
-               break;
-       case VKC_DOUBLE:
-               to->value.d = from->value.d;
-               break;
-       case VKC_STRING:
-               to->value.s = strdup(from->value.s);
-               if (!to->value.s)
-                       return -ENOMEM;
-               break;
-       }
-       return 0;
-}
-
-static int set_object_value(struct vconf_kv *k, keynode_t *node)
-{
-       assert (k);
-       assert (node);
-       int ret = 0;
-
-       switch(vconf_keynode_get_type(node)) {
-       case VCONF_TYPE_INT:{
-               int value = vconf_keynode_get_int(node);
-               k->val.value.i = value;
-               k->val.type = VKC_INT;
-               }break;
-       case VCONF_TYPE_BOOL:{
-               int value = vconf_keynode_get_bool(node);
-               if (value ==  -1) {
-                       ret = -1;
-                       break;
-               }
-               k->val.value.b = value;
-               k->val.type = VKC_BOOL;
-               }break;
-       case VCONF_TYPE_DOUBLE:{
-               double value = vconf_keynode_get_dbl(node);
-               k->val.value.d = value;
-               k->val.type = VKC_DOUBLE;
-               }break;
-       case VCONF_TYPE_STRING:{
-               char *value = vconf_keynode_get_str(node);
-               if (!value) {
-                       ret = -1;
-                       break;
-               }
-               k->val.value.s = strdup(value);
-               if (!k->val.value.s)
-                       return -1;
-               k->val.type = VKC_STRING;
-               }break;
-       default:
-               ret = -1;
-               break;
-       }
-
-       return ret;
-}
-
-static void on_vconf_key_changed(keynode_t *key, void *data)
-{
-       struct vconf_listener *l = (struct vconf_listener *)data;
-       char *name = NULL;
-       struct vconf_key_changed_event_data vkc_ev_data = {};
-       struct epc_event *ev;
-       struct timespec ts;
-       int ret = 0;
-
-       if (clock_gettime(CLOCK_MONOTONIC, &ts) < 0) {
-               log_error_errno(errno, "Unable to get timestamp : %m");
-               return;
-       }
-
-       name = vconf_keynode_get_name(key);
-       if (!name) {
-               log_debug("vconf:  key name not found (key=%s)", name);
-               return;
-       }
-
-       struct vconf_kv *k = find_vconf_kv(l, name);
-       if (!k) {
-               log_debug("vconf: key-value pair not found (key=%s)", name);
-               return;
-       }
-
-       vkc_ev_data.event_time = ts.tv_sec;
-       vkc_ev_data.key_name = strdup(name);
-       if (vkc_ev_data.key_name == NULL)
-               goto finish;
-
-       if (copy_vkc_value(&k->val, &vkc_ev_data.oldval) < 0)
-               goto finish;
-
-       if (k->val.type == VKC_STRING) {
-               free(k->val.value.s);
-               k->val.value.s = NULL;
-       }
-
-       if (set_object_value(k, key) < 0)
-               goto finish;
-
-       if (copy_vkc_value(&k->val, &vkc_ev_data.newval) < 0)
-               goto finish;
-
-       ret = epc_event_create(VCONF_KEY_CHANGED_EVENT_ID, &vkc_ev_data, &ev);
-       if (ret) {
-               log_error_errno(ret, "Unable to allocate an event: %m.");
-               goto finish;
-       }
-
-       ret = event_processor_report_event(ev);
-       epc_event_unref(ev);
-       if (ret)
-               log_error_errno(ret, "Unable to report event: %m");
-       return;
-finish:
-       free(vkc_ev_data.key_name);
-       if (vkc_ev_data.oldval.type == VKC_STRING)
-               free(vkc_ev_data.oldval.value.s);
-       if (vkc_ev_data.newval.type == VKC_STRING)
-               free(vkc_ev_data.newval.value.s);
-
-       return;
-}
-
-static int add_key(struct vconf_listener *l, const char *key, keynode_t *node)
-{
-       int ret = 0;
-       struct vconf_kv *k;
-
-       assert (l);
-       assert (key);
-       //assert (node); /* it's ok to be null */
-
-       k = (struct vconf_kv*)malloc(sizeof(struct vconf_kv));
-       if (k == NULL) {
-               ret = -ENOMEM;
-               goto cleanup;
-       }
-
-       k->name = strdup(key);
-       if (k->name == NULL) {
-               ret = -ENOMEM;
-               goto cleanup;
-       }
-
-       if (node != NULL && set_object_value(k, node) < 0) {
-               ret = -EINVAL;
-               goto cleanup;
-       }
-
-       list_add_tail(&k->node, &l->keys);
-       if (vconf_notify_key_changed(key, on_vconf_key_changed, l) < 0)
-               log_error("vconf_notify_key_changed() failed (%s)", key);
-
-       return 0;
-
-cleanup:
-       if (k) {
-               free(k->name);
-               free(k);
-       }
-       return ret;
-}
-
-static void cleanup(struct vconf_listener *l)
-{
-       struct vconf_kv *k, *next;
-
-       list_for_each_entry_safe(k, next, &l->keys, node) {
-               list_del(&k->node);
-               free(k->name);
-               if (k->val.type == VKC_STRING)
-                       free(k->val.value.s);
-               free(k);
-       }
-}
-
-static int vconf_listener_init(struct epc_module *module,
-                                                                struct epc_config *config,
-                                                                sd_event* event)
-{
-       struct vconf_listener *listener = to_vconf_listener(module);
-       int ret = 0;
-       json_object *arr, *val;
-       keylist_t *klist;
-       keynode_t *knode;
-
-       INIT_LIST_HEAD(&listener->keys);
-
-       if (!json_object_object_get_ex(config->root, "keys", &arr)) {
-               log_error("Config does not contain 'keys' parameter.");
-               ret = -EINVAL;
-               goto cleanup;
-       }
-
-       if (!json_object_is_type(arr, json_type_array)) {
-               log_error("Config value is not an array");
-               ret = -EINVAL;
-               goto cleanup;
-       }
-
-       for (size_t i = 0; i < json_object_array_length(arr); i++) {
-               knode = NULL;
-               val = json_object_array_get_idx(arr, i);
-               if (val == NULL) {
-                       log_error("vconf: no specified key (%zu)\n", i);
-                       ret = -EINVAL;
-                       goto cleanup;
-               }
-
-               klist = vconf_keylist_new();
-               if (!klist) {
-                       log_error("vconf: could not create keylist for %s\n", json_object_get_string(val));
-                       continue;
-               }
-
-               ret = vconf_get(klist, json_object_get_string(val), VCONF_GET_ALL);
-               if (ret < 0) {
-                       log_debug("vconf: keylist does not contain key %s\n", json_object_get_string(val));
-                       goto free_list;
-               }
-
-               ret = vconf_keylist_lookup(klist, json_object_get_string(val), &knode);
-               if (ret <= 0) {
-                       log_debug("vconf_keylist_lookup failed for %s\n", json_object_get_string(val));
-                       //goto free_list;
-               }
-
-               ret = add_key(listener, json_object_get_string(val), knode);
-               if (ret < 0)
-                       log_error("vconf: could not add key\n");
-
-               free_list:
-                       vconf_keylist_free(klist);
-       }
-       return 0;
-
-cleanup:
-       cleanup(listener);
-       return ret;
-}
-
-static void vconf_listener_cleanup(struct epc_module *module)
-{
-       struct vconf_listener *listener = to_vconf_listener(module);
-       cleanup(listener);
-}
-
-struct vconf_listener vconf_listener = {
-       .module = {
-               .name = "vconf_listener",
-               .type = EPC_MODULE_TYPE_LISTENER,
-
-               .init = vconf_listener_init,
-               .cleanup = vconf_listener_cleanup,
-               .node = LIST_HEAD_INIT(vconf_listener.module.node),
-       },
-};
-
-EPC_MODULE_REGISTER(&vconf_listener.module)
diff --git a/activationd/tests/activationd_acceptance_checker.c b/activationd/tests/activationd_acceptance_checker.c
deleted file mode 100644 (file)
index 5d6295f..0000000
+++ /dev/null
@@ -1,434 +0,0 @@
-/*
- * This file is part of epc.
- *
- * Copyright © 2019 Samsung Electronics
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <systemd/sd-bus.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/timerfd.h>
-#include <vconf.h>
-
-#include "common.h"
-#include "systemd_dbus.h"
-
-#define DBUS_PROPERTIES_INTERFACE "org.freedesktop.DBus.Properties"
-#define SERVICE_NAME "activationd-acceptance-test.service"
-#define VCONF_ACTIVATION_KEY "file/activationd/acceptance"
-
-enum unit_state {
-       UNKNOWN,
-       ACTIVE,
-       INACTIVE
-};
-
-struct action {
-       const char *action;
-       enum unit_state expected_states[2];
-       int state_count;
-       int current_state;
-};
-
-struct test_sequence {
-       struct action actions[3];
-       int current_action;
-       int ok;
-};
-
-
-struct test_data {
-       sd_bus *bus;
-       sd_event *loop;
-       struct test_sequence test;
-       enum unit_state state;
-       enum unit_state prev_state;
-       char *path;
-};
-
-static const char *from_unit_state(enum unit_state state)
-{
-       switch (state) {
-       case UNKNOWN:
-               return "unknown";
-       case ACTIVE:
-               return "active";
-       default:
-               return "inactive";
-       }
-}
-
-static enum unit_state to_unit_state(const char *state)
-{
-       if (!strncmp (state, "active", 6))
-               return ACTIVE;
-       else if (!strncmp (state, "inactive", 8) || !strncmp (state, "deactivating", 12))
-               return INACTIVE;
-       else
-               return UNKNOWN;
-}
-
-static int set_vconf_key(const char *val)
-{
-       keylist_t *kl = NULL;
-       kl = vconf_keylist_new();
-       if (!kl) {
-               fprintf(stderr, "error creating vconf keylists\n");
-               return -1;
-       }
-
-       vconf_keylist_add_str(kl, VCONF_ACTIVATION_KEY, val);
-       if (vconf_set(kl) < 0) {
-               fprintf(stderr, "error saving vconf key\n");
-               vconf_keylist_free(kl);
-               return -1;
-       }
-
-       vconf_keylist_free(kl);
-       return 0;
-}
-
-static int test_step(struct test_data *data)
-{
-       struct test_sequence *test = &data->test;
-       if (test->current_action == ARRAY_SIZE(test->actions)) {
-               sd_event_exit(data->loop, EXIT_SUCCESS);
-               test->ok = 1;
-               return 0;
-       }
-
-       if (set_vconf_key(test->actions[test->current_action].action))
-               return -1;
-       return 0;
-}
-
-static int check_test_result(struct test_data *data)
-{
-       struct action *a = &data->test.actions[data->test.current_action];
-       enum unit_state exp_state = a->expected_states[a->current_state];
-
-       if (data->test.ok == 1)
-               return 0;
-
-       if (data->state != exp_state) {
-               data->test.ok = 1;
-               fprintf(stderr, "test failed (%s instead of %s at step %d of %s)\n",
-                               from_unit_state(data->state),
-                               from_unit_state(exp_state),
-                               a->current_state,
-                               a->action);
-
-               sd_event_exit(data->loop, EXIT_FAILURE);
-               return -1;
-       }
-       a->current_state++;
-       if (a->current_state == a->state_count) {
-               data->test.current_action++;
-               if (test_step(data) < 0)
-                       return -1;
-       }
-       return 0;
-}
-
-
-static int check_unit_state(struct test_data *data, const char *state)
-{
-       enum unit_state new_state;
-
-       new_state = to_unit_state(state);
-       if (data->state != new_state) {
-               data->prev_state = data->state;
-               data->state = new_state;
-               check_test_result(data);
-       }
-       return 0;
-}
-
-
-static int on_properties_changed(sd_bus_message *m, void *userdata, sd_bus_error *ret_error) {
-       int r;
-       struct test_data *data = (struct test_data*)userdata;
-       const char *iface;
-       const char *member;
-       const char *value = NULL;
-       const char *contents;
-
-       r = sd_bus_message_read(m, "s", &iface);
-       if (r < 0) {
-               fprintf(stderr, "Failed to parse PropertiesChanged\n");
-               return r;
-       }
-
-       r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "{sv}");
-       if (r < 0)
-               return r;
-
-       while ((r = sd_bus_message_enter_container(m, SD_BUS_TYPE_DICT_ENTRY, "sv")) > 0) {
-               char type;
-
-               r = sd_bus_message_read(m, "s", &member);
-               if (r < 0)
-                       return r;
-
-               r = sd_bus_message_peek_type(m, &type, &contents);
-               if (r < 0)
-                       return r;
-
-               r = sd_bus_message_enter_container(m, SD_BUS_TYPE_VARIANT, contents);
-               if (r < 0)
-                       return r;
-
-               if (strcmp(member, "ActiveState") == 0) {
-                       r = sd_bus_message_read(m, "s", &value);
-                       if (r < 0)
-                               return r;
-               } else {
-                       r = sd_bus_message_skip(m, contents);
-                       if (r < 0)
-                               return r;
-               }
-
-               r = sd_bus_message_exit_container(m);
-               if (r < 0)
-                       return r;
-
-               r = sd_bus_message_exit_container(m);
-               if (r < 0)
-                       return r;
-       }
-
-       r = sd_bus_message_exit_container(m);
-       if (r < 0)
-               return r;
-
-       if (value)
-               check_unit_state(data, value);
-       return 0;
-}
-
-static void cleanup(struct test_data *data)
-{
-       free(data->path);
-       if (!data->bus)
-               return;
-       sd_bus_flush(data->bus);
-       sd_bus_unref(data->bus);
-}
-
-static int signal_handler(sd_event_source *s,
-               const struct signalfd_siginfo *si,
-               void *userdata)
-{
-       sd_event *loop = userdata;
-       sd_event_exit(loop, EXIT_FAILURE);
-       return 0;
-}
-
-static int start_test(sd_event_source *s, uint64_t usec, void *userdata)
-{
-       struct test_data *data = (struct test_data*)userdata;
-       return test_step(data);
-}
-
-static int timeout_handler(sd_event_source *s, uint64_t usec, void *userdata)
-{
-       struct test_data *data = (struct test_data*)userdata;
-       fprintf(stderr, "test timed out\n");
-       sd_event_exit(data->loop, EXIT_FAILURE);
-       return 0;
-}
-
-static int call_subscribe(struct test_data *data)
-{
-       __attribute__((cleanup(sd_bus_message_unrefp))) sd_bus_message *reply = NULL;
-       __attribute__((cleanup(sd_bus_error_free))) sd_bus_error error = SD_BUS_ERROR_NULL;
-       int ret;
-
-       ret = sd_bus_call_method(data->bus,
-                       SYSTEMD_SERVICE,
-                       SYSTEMD_OBJ,
-                       SYSTEMD_MANAGER_INTERFACE,
-                       "Subscribe",
-                       &error,
-                       &reply,
-                       "");
-
-       if (ret < 0) {
-               fprintf(stderr, "Failed to issue Subscribe() call: %s\n", error.message);
-               return -1;
-       }
-       return 0;
-}
-
-static int call_load_unit(struct test_data *data)
-{
-       __attribute__((cleanup(sd_bus_message_unrefp))) sd_bus_message *reply = NULL;
-       __attribute__((cleanup(sd_bus_error_free))) sd_bus_error error = SD_BUS_ERROR_NULL;
-       int ret;
-       const char *path = NULL;
-       char err[512];
-
-       ret = sd_bus_call_method(data->bus,
-                       SYSTEMD_SERVICE,
-                       SYSTEMD_OBJ,
-                       SYSTEMD_MANAGER_INTERFACE,
-                       "LoadUnit",
-                       &error,
-                       &reply,
-                       "s",
-                       SERVICE_NAME);
-
-       if (ret < 0) {
-               fprintf(stderr, "Failed to issue LoadUnit() call: %s\n", error.message);
-               return -1;
-       }
-
-       ret = sd_bus_message_read(reply, "o", &path);
-       if (ret < 0) {
-               if (strerror_r(-ret, err, sizeof err))
-                       fprintf(stderr, "Failed to read reply: %s\n", err);
-               return -1;
-       }
-
-       if (!path) {
-               fprintf(stderr, "ould not get object path\n");
-               return -1;
-       }
-       data->path = strdup(path);
-       return 0;
-}
-int main(int argc, char *argv[])
-{
-       struct test_data data = {
-               .bus = NULL,
-               .loop = NULL,
-               .state = UNKNOWN,
-               .prev_state = UNKNOWN,
-               .path = NULL,
-               .test = {
-                       .actions = {
-                               {"START", {ACTIVE, UNKNOWN}, 1, 0},
-                               {"RELOAD", {INACTIVE, ACTIVE}, 2, 0},
-                               {"STOP", {INACTIVE, UNKNOWN}, 1, 0}
-                       },
-                       .current_action = 0,
-                       .ok = 0
-               }
-       };
-
-       int r;
-       uint64_t now;
-       sigset_t ss;
-       char buf[512];
-       char err[512];
-
-       r = sd_bus_open_system(&data.bus);
-       if (r < 0) {
-               if (strerror_r(-r, err, sizeof err))
-                       fprintf(stderr, "Failed to read reply: %s\n", err);
-               goto fail;
-       }
-
-       r = call_subscribe(&data);
-       if (r < 0)
-               goto fail;
-
-       r = call_load_unit(&data);
-       if (r < 0)
-               goto fail;
-
-       r = snprintf(buf, sizeof buf, "type='signal',interface='org.freedesktop.DBus.Properties',member='PropertiesChanged', path='%s'", data.path);
-       if (r < 0) {
-               if (strerror_r(-r, err, sizeof err))
-                       fprintf(stderr, "Failed to create match rule: %s\n", err);
-               goto fail;
-       }
-
-       r = sd_bus_add_match(data.bus, NULL, buf, on_properties_changed, &data);
-       if (r < 0) {
-               if (strerror_r(-r, err, sizeof err))
-                       fprintf(stderr, "Failed to add PropertiesChanged match: %s\n", err);
-               goto fail;
-       }
-
-       r = sd_event_new(&data.loop);
-       if (r < 0) {
-               if (strerror_r(-r, err, sizeof err))
-                       fprintf(stderr, "Failed to create main loop: %s\n", err);
-               goto fail;
-       }
-
-       sigemptyset(&ss);
-       sigaddset(&ss, SIGINT);
-       sigaddset(&ss, SIGTERM);
-       r = sigprocmask(SIG_BLOCK, &ss, NULL);
-       if (r < 0) {
-               if (strerror_r(-r, err, sizeof err))
-                       fprintf(stderr, "Failed to change signal mask: %s\n", err);
-               goto fail;
-       }
-
-       r = sd_event_add_signal(data.loop, NULL, SIGINT, signal_handler, data.loop);
-       if (r < 0) {
-               if (strerror_r(-r, err, sizeof err))
-                       fprintf(stderr, "Failed to register SIGINT handler: %s\n", err);
-               goto fail;
-       }
-
-       r = sd_event_add_signal(data.loop, NULL, SIGTERM, signal_handler, data.loop);
-       if (r < 0) {
-               if (strerror_r(-r, err, sizeof err))
-                       fprintf(stderr, "Failed to register SIGTERM handler: %s\n", err);
-               goto fail;
-       }
-
-       r = sd_bus_attach_event(data.bus, data.loop, 0);
-       if (r < 0) {
-               if (strerror_r(-r, err, sizeof err))
-                       fprintf(stderr, "Failed to attach bus to event loop: %s\n", err);
-               goto fail;
-       }
-
-       r = sd_event_add_time(data.loop, NULL, CLOCK_REALTIME, 0, 0, start_test, &data);
-       if (r < 0) {
-               if (strerror_r(-r, err, sizeof err))
-                       fprintf(stderr, "Failed to attach timer to event loop: %s\n", err);
-               goto fail;
-       }
-
-       sd_event_now(data.loop, CLOCK_REALTIME, &now);
-
-       r = sd_event_add_time(data.loop, NULL, CLOCK_REALTIME, now+10000000, 0, timeout_handler, &data);
-       if (r < 0) {
-               if (strerror_r(-r, err, sizeof err))
-                       fprintf(stderr, "Failed to attach timer to event loop: %s\n", err);
-               goto fail;
-       }
-
-       r = sd_event_loop(data.loop);
-       if (r < 0) {
-               if (strerror_r(-r, err, sizeof err))
-                       fprintf(stderr, "Failed to run main loop: %s\n", err);
-               goto fail;
-       }
-
-       cleanup(&data);
-       return r;
-
-fail:
-       cleanup(&data);
-       return EXIT_FAILURE;
-}
diff --git a/activationd/tests/activationd_acceptance_service.c b/activationd/tests/activationd_acceptance_service.c
deleted file mode 100644 (file)
index 5a4b946..0000000
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * This file is part of epc.
- *
- * Copyright © 2019 Samsung Electronics
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <unistd.h>
-#include <stdlib.h>
-#include <stdio.h>
-#include <signal.h>
-
-static void exit_handler(int signo)
-{
-       exit(EXIT_SUCCESS);
-}
-
-int main(int argc, char *argv[])
-{
-       if (signal(SIGINT, exit_handler) == SIG_ERR ||
-                       signal(SIGQUIT, exit_handler) == SIG_ERR ||
-                       signal(SIGTERM, exit_handler) == SIG_ERR) {
-               perror("catching SIGNAL");
-               exit(EXIT_FAILURE);
-       }
-
-       printf("service started, do nothing...\n");
-       while (1)
-               sleep(10);
-
-       exit_handler(0);
-}
-
diff --git a/activationd/tests/activationd_acceptance_test b/activationd/tests/activationd_acceptance_test
deleted file mode 100755 (executable)
index 88fe1af..0000000
+++ /dev/null
@@ -1,28 +0,0 @@
-#!/bin/sh
-
-EPCD_PID=-1
-
-cleanup() {
-       systemctl stop activationd-acceptance-test
-       [ $EPCD_PID -ne -1 ] && kill $EPCD_PID > /dev/null 2>&1
-       vconftool unset  file/activationd/acceptance
-       exit 0
-}
-
-trap cleanup 0
-
-vconftool -f set -t string file/activationd/acceptance foo
-
-# assumes there's no epcd service running
-epcd > /dev/null 2>&1 &
-EPCD_PID=$!
-sleep 2
-
-/usr/bin/activationd_acceptance_checker
-
-if [ "$?" -eq "0" ]; then
-       echo "ok"
-else
-       echo "fail"
-fi
-
index 70a5b56b13f5b95242419921f40feb5e6d8a15ef..c115146ae4c6149c8f965f31b2cc24056453e941 100644 (file)
@@ -138,7 +138,7 @@ AC_CHECK_FUNCS([ \
 
 AC_CONFIG_HEADERS(config.h)
 AC_CONFIG_FILES([
-        Makefile activationd/Makefile
+        Makefile
 ])
 
 LT_INIT
diff --git a/include/vconf_key_changed_event.h b/include/vconf_key_changed_event.h
new file mode 100644 (file)
index 0000000..62f1708
--- /dev/null
@@ -0,0 +1,66 @@
+/*
+ * This file is a part of epc.
+ *
+ * Copyright © 2019 Samsung Electronics
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _EPC_VCONF_KEY_CHANGED_EVENT_H
+#define _EPC_VCONF_KEY_CHANGED_EVENT_H
+
+#include <time.h>
+#include "event.h"
+
+#define VCONF_KEY_CHANGED_EVENT_ID "vconf_key_changed"
+#define VKC_EV_TIME "et"
+#define VKC_EV_NAME "name"
+#define VKC_EV_OLDVAL "oldval"
+#define VKC_EV_NEWVAL "newval"
+
+enum vkc_type {
+       VKC_BOOL,
+       VKC_INT,
+       VKC_DOUBLE,
+       VKC_STRING
+};
+
+struct vkc_value {
+       enum vkc_type type;
+       union {
+               bool b;
+               int i;
+               double d;
+               char *s;
+       } value;
+};
+
+struct vconf_key_changed_event {
+       struct epc_event event;
+       char *key_name;
+       struct vkc_value oldval;
+       struct vkc_value newval;
+       time_t event_time;
+};
+
+struct vconf_key_changed_event_data {
+       char *key_name;
+       struct vkc_value oldval;
+       struct vkc_value newval;
+       time_t event_time;
+};
+
+#define to_vconf_key_changed_event(EVENT)                                              \
+       container_of(EVENT, struct vconf_key_changed_event, event)
+
+#endif /* _EPC_VCONF_KEY_CHANGED_EVENT_H */
index e41d6384935743f6af95a5d452a2bb4905b10c82..9224c6fa108c5e85ee6fe1d794ff1b872b5623d7 100644 (file)
@@ -6,11 +6,13 @@ Source0:    %{name}-%{version}.tar.xz
 Source1001: %{name}.manifest
 Summary:    Event-based activation daemon
 Group:      System/Monitoring
+Requires:   event-processing-core
+Requires:   event-processing-vconf
+Requires:   event-processing-activation-dm
+BuildRequires: pkgconfig(vconf)
 
 %define with_activationd_glib_support 1
 
-BuildRequires: pkgconfig(vconf)
-
 %description
 Activationd allows starting systemd units based on various system events.
 
@@ -33,9 +35,28 @@ Group:      System/Monitoring
 %description -n event-processing-extra
 Event processing extra modules
 
+%package -n event-processing-vconf
+Summary:    vconf listener module for epc
+Group:      System/Monitoring
+BuildRequires: pkgconfig(vconf)
+Requires:   event-processing-core
+
+%description -n event-processing-vconf
+This package provides a listener for vconf events
+
+%package -n event-processing-activation-dm
+Summary:    Activation decision maker
+Group:      System/Monitoring
+Requires:   event-processing-core
+
+%description -n event-processing-activation-dm
+This package provides a decision maker for activating systemd units based on various system events
+
 %package -n activationd-test-services
 Summary:    activationd test services
 Group:      System/Monitoring
+BuildRequires: pkgconfig(vconf)
+Requires:   event-processing-core
 
 %description -n activationd-test-services
 Services used to test activationd functionality
@@ -69,7 +90,7 @@ make check
 %make_install
 
 mkdir -p %{buildroot}/%{_unitdir}/basic.target.wants
-ln -s ../epc.service %{buildroot}/%{_unitdir}/basic.target.wants
+ln -s epc.service %{buildroot}/%{_unitdir}/basic.target.wants
 
 ln -s %{_sbindir}/epcd %{buildroot}/%{_sbindir}/epcctl
 
@@ -77,49 +98,39 @@ ln -s %{_sbindir}/epcd %{buildroot}/%{_sbindir}/epcctl
 %define moduleconfdir %{_sysconfdir}/epc/available-modules/
 %define enabled_moduledir %{_sysconfdir}/epc/enabled-modules/
 
-touch epc-files
-#for mod in <core_modules>
-#do
-#      ln -s %{moduledir}/${mod}.so %{buildroot}/%{moduleconfdir}/${mod}.so;
-#      ln -s ../available-modules/${mod}.so %{buildroot}/%{enabled_moduledir}/${mod}.so;
-#      echo %{moduledir}/${mod}.so >> activationd-files;
-#      echo %{moduleconfdir}/${mod}.so >> activationd-files;
-#      echo %{enabled_moduledir}/${mod}.so >> activationd-files;
-#done
-
-for mod in service_restart_action \
-       unit_start_action
-do
-       ln -s %{moduledir}/${mod}.so %{buildroot}/%{moduleconfdir}/${mod}.so;
-       ln -s ../available-modules/${mod}.so %{buildroot}/%{enabled_moduledir}/${mod}.so;
-       echo %{moduledir}/${mod}.so >> extra-files;
-       echo %{moduleconfdir}/${mod}.so >> extra-files;
-       echo %{enabled_moduledir}/${mod}.so >> extra-files;
-done
-
-echo /usr/lib/epc/service.conf.d/ >> activationd-files;
-
-for mod in vconf_listener \
-       vconf_key_changed_event \
-       activation_dm
-do
-       ln -s %{moduledir}/${mod}.so %{buildroot}/%{moduleconfdir}/${mod}.so;
-       ln -s ../available-modules/${mod}.so %{buildroot}/%{enabled_moduledir}/${mod}.so;
-       echo %{moduledir}/${mod}.so >> activationd-files;
-       echo %{moduleconfdir}/${mod}.so >> activationd-files;
-       echo %{enabled_moduledir}/${mod}.so >> activationd-files;
-done
+mkdir -p %{buildroot}/%{moduledir}
+mkdir -p %{buildroot}/%{moduleconfdir}
+mkdir -p %{buildroot}/%{enabled_moduledir}
+mkdir -p %{buildroot}/%{_libdir}/epc/service.conf.d
+
+# install_module <module> <package>
+%define install_module() \
+       ln -s %{moduledir}/%1.so %{buildroot}/%{moduleconfdir}/%1.so; \
+       ln -s ../available-modules/%1.so %{buildroot}/%{enabled_moduledir}/%1.so; \
+       echo %{moduledir}/%1.so >> %2-files; \
+       echo %{moduleconfdir}/%1.so >> %2-files; \
+       echo %{enabled_moduledir}/%1.so >> %2-files;
+
+%install_module service_restart_action extra
+%install_module unit_start_action extra
+%install_module vconf_key_changed_event vconf
+%install_module vconf_listener vconf
+%install_module activation_dm activation-dm
+
+%files
 
 %files -n event-processing-devel
 %license COPYING
 %{_includedir}/*
 %{_libdir}/pkgconfig/*
 
-%files -f activationd-files
+%files -n event-processing-activation-dm -f activation-dm-files
 %license COPYING
-%{_prefix}/lib/epc/modules.conf.d/vconf_listener.conf.d/50-default.conf
 %{_prefix}/lib/epc/modules.conf.d/activation_eh.conf.d/activation_eh.conf
 
+%files -n event-processing-vconf -f vconf-files
+%{_prefix}/lib/epc/modules.conf.d/vconf_listener.conf.d/50-default.conf
+
 %files -n activationd-test-services
 %license COPYING
 %manifest %{name}.manifest
@@ -130,16 +141,16 @@ done
 %{_prefix}/lib/epc/modules.conf.d/vconf_listener.conf.d/99-acceptance-test.conf
 %{_prefix}/lib/epc/modules.conf.d/activation_eh.conf.d/99-acceptance-test.conf
 
-%files -n event-processing-core -f epc-files
+%files -n event-processing-core
 %license COPYING
 %manifest %{name}.manifest
-%{_localstatedir}/db/epc
 %{_sbindir}/epcd
 %{_sbindir}/epcctl
 %{_prefix}/lib/epc/epc.conf
 %{_unitdir}/epc.service
 %{_unitdir}/basic.target.wants/epc.service
 %{_prefix}/lib/epc/modules.conf.d
+%{_prefix}/lib/epc/service.conf.d
 
 %files -n event-processing-extra -f extra-files
 
diff --git a/src/decision_makers/activation_dm.c b/src/decision_makers/activation_dm.c
new file mode 100644 (file)
index 0000000..fccceca
--- /dev/null
@@ -0,0 +1,350 @@
+/*
+ * This file is part of activationd.
+ *
+ * Copyright © 2019 Samsung Electronics
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include <malloc.h>
+#include <errno.h>
+
+#include "decision_made_event.h"
+#include "action.h"
+#include "event_processor.h"
+#include "log.h"
+#include "service.h"
+#include "common.h"
+#include "database.h"
+#include "json-config.h"
+
+#include "vconf_key_changed_event.h"
+
+#define MODULE_NAME "activation_decision_maker"
+
+struct activation_decision_maker {
+       struct epc_event_handler eh;
+       struct list_head rules;
+};
+
+struct rule {
+       const char *event;
+       void *ev_data;
+       bool match_oldval;
+       bool match_newval;
+       const char *action;
+       const char *target;
+
+       struct list_head node;
+};
+
+static int activation_event_match(struct epc_event_handler *handler,
+               struct epc_event *ev)
+{
+       if (strcmp(ev->type->name, VCONF_KEY_CHANGED_EVENT_ID) == 0)
+                       return 1;
+
+       return 0;
+}
+
+static int vconf_field_cmp(struct vkc_value *a, struct vkc_value *b)
+{
+       if (a->type != b->type)
+               return 0;
+
+       switch (a->type){
+       case VKC_BOOL:
+               return a->value.b == b->value.b;
+       case VKC_INT:
+               return a->value.i == b->value.i;
+       case VKC_DOUBLE:
+               return a->value.d == b->value.d;
+       case VKC_STRING:
+               return strcmp(a->value.s, b->value.s) == 0;
+       }
+}
+
+static int vconf_rule_match(struct rule *r, struct epc_event *event)
+{
+       struct vconf_key_changed_event *ev = to_vconf_key_changed_event(event);
+       struct vconf_key_changed_event_data *ev_data = r->ev_data;
+
+       if (ev_data->key_name && strcmp(ev_data->key_name, ev->key_name))
+               return 0;
+
+       if (r->match_oldval && !vconf_field_cmp(&ev_data->oldval, &ev->oldval))
+               return 0;
+
+       if (r->match_newval && !vconf_field_cmp(&ev_data->newval, &ev->newval))
+               return 0;
+
+       return 1;
+}
+
+static int execute_rule(struct rule *r, struct epc_event *ev)
+{
+       struct dm_event_data ev_data = {
+               .reason = ev,
+               .who_made = MODULE_NAME,
+       };
+       struct epc_event *new_ev;
+       int ret;
+
+       ev_data.action = EPC_ACTION_UNIT_START_ID;
+       ret = epc_object_new(&ev_data.action_data);
+       if (ret < 0) {
+               log_error("Could not create data object for action");
+               goto out;
+       }
+
+       ret = epc_fill_for_unit_start(ev_data.action_data, r->target);
+       if (ret) {
+               log_error("Unable to create event data");
+               goto out;
+       }
+       epc_fill_for_unit_action(ev_data.action_data, r->action);
+
+       ret = epc_event_create(DECISION_MADE_EVENT_ID, &ev_data, &new_ev);
+       if (ret) {
+               log_error("Unable to create event");
+               goto out;
+       }
+
+       ret = event_processor_report_event(new_ev);
+       epc_event_unref(new_ev);
+       if (ret) {
+               log_error("Unable to report event");
+               goto out;
+       }
+
+out:
+       epc_object_unref(ev_data.action_data);
+       return ret;
+}
+
+static int activation_make_decision(struct epc_event_handler *handler)
+{
+       struct epc_event *ev = pop_epc_event(&handler->event_queue);
+       struct activation_decision_maker *dm = container_of(handler,
+                       struct activation_decision_maker, eh);
+       int ret;
+       struct rule *r;
+
+       list_for_each_entry(r, &dm->rules, node) {
+               if (strcmp(r->event, ev->type->name))
+                       continue;
+
+               if (!strcmp(ev->type->name, VCONF_KEY_CHANGED_EVENT_ID) == 0 ||
+                               !vconf_rule_match(r, ev))
+                       continue;
+
+               ret = execute_rule(r, ev);
+               if (ret < 0)
+                       break;
+       }
+
+       epc_object_unref(ev);
+       return 0;
+}
+
+static int parse_vconf_field(json_object *root, const char *key, struct vkc_value *value)
+{
+       struct json_object *node = NULL;
+       enum json_type type;
+       char *str;
+
+       if (!json_object_object_get_ex(root, key, &node)) {
+               log_debug("Config does not contain %s parameter", key);
+               return -1;
+       }
+
+       type = json_object_get_type(node);
+
+       switch (type) {
+       case json_type_boolean:
+               value->type = VKC_BOOL;
+               value->value.b = json_object_get_boolean(node);
+               break;
+       case json_type_double:
+               value->type = VKC_DOUBLE;
+               value->value.d = json_object_get_double(node);
+               break;
+       case json_type_int:
+               value->type = VKC_INT;
+               value->value.i = json_object_get_int(node);
+               break;
+       case json_type_string:
+               value->type = VKC_STRING;
+               str = json_object_get_string(node);
+               if (!str)
+                       goto err;
+
+               value->value.s = strdup(str);
+               break;
+       case json_type_array:
+       case json_type_object:
+               log_error("Field %s must have simple type", key);
+               return -EINVAL;
+               break;
+       case json_type_null:
+               return -EINVAL;
+               break;
+       }
+
+       return 0;
+
+err:
+       return -1;
+}
+
+static int parse_vconf_data(json_object *root, struct rule *r)
+{
+       struct vconf_key_changed_event_data *evd;
+       int ret;
+
+       evd = calloc(1, sizeof(*evd));
+       if (!evd)
+               return -ENOMEM;
+
+       (void) get_config_field(root, "key_name", &evd->key_name, json_type_string);
+       ret = parse_vconf_field(root, "oldval", &evd->oldval);
+       r->match_oldval = ret >= 0;
+       ret = parse_vconf_field(root, "newval", &evd->newval);
+       r->match_newval = ret >= 0;
+
+       r->ev_data = evd;
+
+       return 0;
+}
+
+static void rule_cleanup(struct rule *r)
+{
+       free(r->ev_data);
+}
+
+static void clean_rules(struct activation_decision_maker *dm)
+{
+       struct rule *r, *next;
+
+       list_for_each_entry_safe(r, next, &dm->rules, node) {
+               list_del_init(&r->node);
+               rule_cleanup(r);
+               free(r);
+       }
+}
+
+static int add_rule(struct activation_decision_maker *dm, json_object *root)
+{
+       int ret;
+       struct rule *r;
+       char *str;
+
+       r = calloc(1, sizeof(*r));
+       if (!r) {
+               log_error("Could not allocate rule object");
+               return -ENOMEM;
+       }
+
+       ret = get_config_field(root, "event", &r->event, json_type_string);
+       if (ret < 0)
+               goto out;
+
+       log_debug("Adding rule for event %s", r->event);
+
+       if (strcmp(r->event, VCONF_KEY_CHANGED_EVENT_ID) == 0) {
+               parse_vconf_data(root, r);
+       } else {
+               log_warning("Event type %s is not supported by activationd module\n", r->event);
+               goto out;
+       }
+
+       ret = get_config_field(root, "action", &r->action, json_type_string);
+       if (ret < 0)
+               goto out;
+
+       ret = get_config_field(root, "target", &r->target, json_type_string);
+       if (ret < 0)
+               goto out;
+
+       list_add_tail(&r->node, &dm->rules);
+
+       return 0;
+
+out:
+       rule_cleanup(r);
+       free(r);
+       return ret;
+}
+
+static int activation_init(struct epc_event_handler *handler, struct epc_config *config)
+{
+       struct activation_decision_maker *dm = container_of(handler,
+                       struct activation_decision_maker, eh);
+       int len;
+       int i;
+       int ret;
+       json_object *array, *obj;
+
+       INIT_LIST_HEAD(&dm->rules);
+
+       if (config == NULL)
+               return 0;
+
+       if (!json_object_object_get_ex(config->root, "rules", &array)) {
+               log_error("There are no 'rules' array");
+               return -EINVAL;
+       }
+
+       if (!json_object_is_type(array, json_type_array)) {
+               log_error("Config value is not an array");
+               return -EINVAL;
+       }
+
+       len = json_object_array_length(array);
+       for (i = 0; i < len; ++i) {
+               obj = json_object_array_get_idx(array, i);
+               ret = add_rule(dm, obj);
+               if (ret < 0) {
+                       log_error("Could not add rule");
+                       goto cleanup;
+               }
+       }
+
+       return 0;
+
+cleanup:
+       clean_rules(dm);
+       return ret;
+};
+
+static int activation_cleanup(struct epc_event_handler *handler)
+{
+       struct activation_decision_maker *dm = container_of(handler,
+                       struct activation_decision_maker, eh);
+
+       clean_rules(dm);
+}
+
+static struct activation_decision_maker activation_dm = {
+       .eh = {
+               .name = MODULE_NAME,
+               .init = activation_init,
+               .cleanup = activation_cleanup,
+               .event_match = activation_event_match,
+               .handle_event = activation_make_decision,
+
+               .node = LIST_HEAD_INIT(activation_dm.eh.node),
+       },
+};
+
+EPC_EVENT_HANDLER_REGISTER(activation_dm.eh, activation_eh,
+               EPC_MODULE_TYPE_DECISION_MAKER)
diff --git a/src/event_types/vconf_key_changed_event.c b/src/event_types/vconf_key_changed_event.c
new file mode 100644 (file)
index 0000000..be87016
--- /dev/null
@@ -0,0 +1,193 @@
+/*
+ * This file is part of epc.
+ *
+ * Copyright © 2019 Samsung Electronics
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdio.h>
+#include <errno.h>
+#include <malloc.h>
+
+#include "vconf_key_changed_event.h"
+
+static int allocate_vkc_event(struct epc_event_type *type,
+                                                        void *data, struct epc_event **ev)
+{
+       struct vconf_key_changed_event *vkc_ev;
+       struct vconf_key_changed_event_data *vkc_ev_data = data;
+       int ret;
+
+       vkc_ev = calloc(1, sizeof(*vkc_ev));
+       if (!vkc_ev)
+               return -ENOMEM;
+
+       ret = epc_event_init_internal(type, &vkc_ev->event);
+       if (ret)
+               goto cleanup;
+
+       vkc_ev->event_time = vkc_ev_data->event_time;
+       vkc_ev->key_name = vkc_ev_data->key_name;
+       vkc_ev->oldval = vkc_ev_data->oldval;
+       vkc_ev->newval = vkc_ev_data->newval;
+
+       *ev = &vkc_ev->event;
+       return 0;
+cleanup:
+       free(vkc_ev);
+
+       return ret;
+}
+
+static int deserialize_vkc_event(struct epc_event_type *type,
+                                                               struct epc_object *data, struct epc_event **ev)
+{
+       int ret = -EINVAL;
+       struct vconf_key_changed_event_data vkc_ev_data;
+       struct epc_object *obj;
+       memset(&vkc_ev_data, 0, sizeof(vkc_ev_data));
+
+       list_for_each_entry(obj, &data->val.children, node) {
+               const bool oldval_match = !strcmp(VKC_EV_OLDVAL, obj->key);
+               const bool newval_match = !strcmp(VKC_EV_NEWVAL, obj->key);
+
+               switch (obj->type) {
+               case TYPE_TIME_T:
+                       if (!strcmp(VKC_EV_TIME, obj->key))
+                               vkc_ev_data.event_time = obj->val.time;
+                       break;
+               case TYPE_BOOL:
+                       if (oldval_match) {
+                               vkc_ev_data.oldval.value.b = obj->val.b;
+                               vkc_ev_data.oldval.type = VKC_BOOL;
+                       } else if (newval_match) {
+                               vkc_ev_data.newval.value.b = obj->val.b;
+                               vkc_ev_data.newval.type = VKC_BOOL;
+                       }
+                       break;
+               case TYPE_INT:
+                       if (oldval_match) {
+                               vkc_ev_data.oldval.value.i = obj->val.i;
+                               vkc_ev_data.oldval.type = VKC_INT;
+                       } else if (newval_match) {
+                               vkc_ev_data.newval.value.i = obj->val.i;
+                               vkc_ev_data.newval.type = VKC_INT;
+                       }
+                       break;
+               case TYPE_DOUBLE:
+                       if (oldval_match) {
+                               vkc_ev_data.oldval.value.d = obj->val.d;
+                               vkc_ev_data.oldval.type = VKC_DOUBLE;
+                       } else if (newval_match) {
+                               vkc_ev_data.newval.value.d = obj->val.d;
+                               vkc_ev_data.newval.type = VKC_DOUBLE;
+                       }
+                       break;
+               case TYPE_STRING:
+                       if (!strcmp(VKC_EV_NAME, obj->key)) {
+                               vkc_ev_data.key_name = obj->val.s;
+                       } else if (oldval_match) {
+                               vkc_ev_data.oldval.value.s = obj->val.s;
+                               vkc_ev_data.oldval.type = VKC_STRING;
+                       } else if (newval_match) {
+                               vkc_ev_data.newval.value.s = obj->val.s;
+                               vkc_ev_data.newval.type = VKC_STRING;
+                       }
+                       break;
+               }
+       }
+
+       ret = allocate_vkc_event(type, &vkc_ev_data, ev);
+       if (ret < 0)
+               goto finish;
+
+       ret = epc_event_deserialize_internal(data, type, *ev);
+       if (ret < 0) {
+               struct vconf_key_changed_event *vkc_ev =
+                       to_vconf_key_changed_event(*ev);
+               free(vkc_ev);
+               goto finish;
+       }
+       ret = 0;
+finish:
+       return ret;
+}
+
+static void vkc_event_release(struct epc_event *ev)
+{
+       struct vconf_key_changed_event *vkc_ev =
+               to_vconf_key_changed_event(ev);
+
+       if (vkc_ev->key_name)
+               free(vkc_ev->key_name);
+       if (vkc_ev->oldval.type == VKC_STRING)
+               free(vkc_ev->oldval.value.s);
+       if (vkc_ev->newval.type == VKC_STRING)
+               free(vkc_ev->newval.value.s);
+
+       epc_event_cleanup_internal(&vkc_ev->event);
+       free(vkc_ev);
+}
+
+static void vkc_event_serialize(struct epc_event *ev, struct epc_object *out)
+{
+       struct vconf_key_changed_event *vkc_ev =
+               to_vconf_key_changed_event(ev);
+       epc_event_serialize_internal(ev, out);
+       epc_object_append_string(out, VKC_EV_NAME, vkc_ev->key_name);
+
+       switch (vkc_ev->oldval.type) {
+       case VKC_BOOL:
+               epc_object_append_bool(out, VKC_EV_OLDVAL, vkc_ev->oldval.value.b);
+               break;
+       case VKC_INT:
+               epc_object_append_int(out, VKC_EV_OLDVAL, vkc_ev->oldval.value.i);
+               break;
+       case VKC_DOUBLE:
+               epc_object_append_double(out, VKC_EV_OLDVAL, vkc_ev->oldval.value.d);
+               break;
+       case VKC_STRING:
+               epc_object_append_string(out, VKC_EV_OLDVAL, vkc_ev->oldval.value.s);
+               break;
+       }
+
+       switch (vkc_ev->newval.type) {
+       case VKC_BOOL:
+               epc_object_append_bool(out, VKC_EV_NEWVAL, vkc_ev->newval.value.b);
+               break;
+       case VKC_INT:
+               epc_object_append_int(out, VKC_EV_NEWVAL, vkc_ev->newval.value.i);
+               break;
+       case VKC_DOUBLE:
+               epc_object_append_double(out, VKC_EV_NEWVAL, vkc_ev->newval.value.d);
+               break;
+       case VKC_STRING:
+               epc_object_append_string(out, VKC_EV_NEWVAL, vkc_ev->newval.value.s);
+               break;
+       }
+       epc_object_append_time_t(out, VKC_EV_TIME, vkc_ev->event_time);
+}
+
+static struct epc_event_type vconf_key_changed_event_type = {
+       .name = VCONF_KEY_CHANGED_EVENT_ID,
+       .default_ops = {
+               .release = vkc_event_release,
+               .serialize = vkc_event_serialize,
+       },
+       .allocate_event = allocate_vkc_event,
+       .deserialize_event = deserialize_vkc_event,
+       .node = LIST_HEAD_INIT(vconf_key_changed_event_type.node),
+};
+
+EPC_EVENT_TYPE_REGISTER(vconf_key_changed_event_type, vconf_key_changed_et)
diff --git a/src/listeners/vconf.c b/src/listeners/vconf.c
new file mode 100644 (file)
index 0000000..df639f7
--- /dev/null
@@ -0,0 +1,324 @@
+/*
+ * This file is part of epc.
+ *
+ * Copyright © 2019 Samsung Electronics
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <vconf.h>
+#include <glib.h>
+#include <time.h>
+
+#include "log.h"
+#include "module.h"
+#include "common.h"
+#include "list.h"
+#include "json-config.h"
+#include "event_processor.h"
+#include "vconf_key_changed_event.h"
+
+struct vconf_kv {
+       char *name;
+       struct vkc_value val;
+       struct list_head node;
+};
+
+struct vconf_listener {
+       struct epc_module module;
+       struct list_head keys;
+};
+
+#define to_vconf_listener(MOD)                                         \
+       container_of(MOD, struct vconf_listener, module)
+
+static struct vconf_kv *find_vconf_kv(struct vconf_listener *l, const char *name)
+{
+       struct vconf_kv *k = NULL;
+
+       list_for_each_entry(k, &l->keys, node) {
+               if (!strcmp(k->name, name))
+                       return k;
+       }
+       return NULL;
+}
+
+static int copy_vkc_value(struct vkc_value *from, struct vkc_value *to)
+{
+       to->type = from->type;
+       switch (from->type){
+       case VKC_BOOL:
+               to->value.b = from->value.b;
+               break;
+       case VKC_INT:
+               to->value.i = from->value.i;
+               break;
+       case VKC_DOUBLE:
+               to->value.d = from->value.d;
+               break;
+       case VKC_STRING:
+               to->value.s = strdup(from->value.s);
+               if (!to->value.s)
+                       return -ENOMEM;
+               break;
+       }
+       return 0;
+}
+
+static int set_object_value(struct vconf_kv *k, keynode_t *node)
+{
+       assert (k);
+       assert (node);
+       int ret = 0;
+
+       switch(vconf_keynode_get_type(node)) {
+       case VCONF_TYPE_INT:{
+               int value = vconf_keynode_get_int(node);
+               k->val.value.i = value;
+               k->val.type = VKC_INT;
+               }break;
+       case VCONF_TYPE_BOOL:{
+               int value = vconf_keynode_get_bool(node);
+               if (value ==  -1) {
+                       ret = -1;
+                       break;
+               }
+               k->val.value.b = value;
+               k->val.type = VKC_BOOL;
+               }break;
+       case VCONF_TYPE_DOUBLE:{
+               double value = vconf_keynode_get_dbl(node);
+               k->val.value.d = value;
+               k->val.type = VKC_DOUBLE;
+               }break;
+       case VCONF_TYPE_STRING:{
+               char *value = vconf_keynode_get_str(node);
+               if (!value) {
+                       ret = -1;
+                       break;
+               }
+               k->val.value.s = strdup(value);
+               if (!k->val.value.s)
+                       return -1;
+               k->val.type = VKC_STRING;
+               }break;
+       default:
+               ret = -1;
+               break;
+       }
+
+       return ret;
+}
+
+static void on_vconf_key_changed(keynode_t *key, void *data)
+{
+       struct vconf_listener *l = (struct vconf_listener *)data;
+       char *name = NULL;
+       struct vconf_key_changed_event_data vkc_ev_data = {};
+       struct epc_event *ev;
+       struct timespec ts;
+       int ret = 0;
+
+       if (clock_gettime(CLOCK_MONOTONIC, &ts) < 0) {
+               log_error_errno(errno, "Unable to get timestamp : %m");
+               return;
+       }
+
+       name = vconf_keynode_get_name(key);
+       if (!name) {
+               log_debug("vconf:  key name not found (key=%s)", name);
+               return;
+       }
+
+       struct vconf_kv *k = find_vconf_kv(l, name);
+       if (!k) {
+               log_debug("vconf: key-value pair not found (key=%s)", name);
+               return;
+       }
+
+       vkc_ev_data.event_time = ts.tv_sec;
+       vkc_ev_data.key_name = strdup(name);
+       if (vkc_ev_data.key_name == NULL)
+               goto finish;
+
+       if (copy_vkc_value(&k->val, &vkc_ev_data.oldval) < 0)
+               goto finish;
+
+       if (k->val.type == VKC_STRING) {
+               free(k->val.value.s);
+               k->val.value.s = NULL;
+       }
+
+       if (set_object_value(k, key) < 0)
+               goto finish;
+
+       if (copy_vkc_value(&k->val, &vkc_ev_data.newval) < 0)
+               goto finish;
+
+       ret = epc_event_create(VCONF_KEY_CHANGED_EVENT_ID, &vkc_ev_data, &ev);
+       if (ret) {
+               log_error_errno(ret, "Unable to allocate an event: %m.");
+               goto finish;
+       }
+
+       ret = event_processor_report_event(ev);
+       epc_event_unref(ev);
+       if (ret)
+               log_error_errno(ret, "Unable to report event: %m");
+       return;
+finish:
+       free(vkc_ev_data.key_name);
+       if (vkc_ev_data.oldval.type == VKC_STRING)
+               free(vkc_ev_data.oldval.value.s);
+       if (vkc_ev_data.newval.type == VKC_STRING)
+               free(vkc_ev_data.newval.value.s);
+
+       return;
+}
+
+static int add_key(struct vconf_listener *l, const char *key, keynode_t *node)
+{
+       int ret = 0;
+       struct vconf_kv *k;
+
+       assert (l);
+       assert (key);
+       //assert (node); /* it's ok to be null */
+
+       k = (struct vconf_kv*)malloc(sizeof(struct vconf_kv));
+       if (k == NULL) {
+               ret = -ENOMEM;
+               goto cleanup;
+       }
+
+       k->name = strdup(key);
+       if (k->name == NULL) {
+               ret = -ENOMEM;
+               goto cleanup;
+       }
+
+       if (node != NULL && set_object_value(k, node) < 0) {
+               ret = -EINVAL;
+               goto cleanup;
+       }
+
+       list_add_tail(&k->node, &l->keys);
+       if (vconf_notify_key_changed(key, on_vconf_key_changed, l) < 0)
+               log_error("vconf_notify_key_changed() failed (%s)", key);
+
+       return 0;
+
+cleanup:
+       if (k) {
+               free(k->name);
+               free(k);
+       }
+       return ret;
+}
+
+static void cleanup(struct vconf_listener *l)
+{
+       struct vconf_kv *k, *next;
+
+       list_for_each_entry_safe(k, next, &l->keys, node) {
+               list_del(&k->node);
+               free(k->name);
+               if (k->val.type == VKC_STRING)
+                       free(k->val.value.s);
+               free(k);
+       }
+}
+
+static int vconf_listener_init(struct epc_module *module,
+                                                                struct epc_config *config,
+                                                                sd_event* event)
+{
+       struct vconf_listener *listener = to_vconf_listener(module);
+       int ret = 0;
+       json_object *arr, *val;
+       keylist_t *klist;
+       keynode_t *knode;
+
+       INIT_LIST_HEAD(&listener->keys);
+
+       if (!json_object_object_get_ex(config->root, "keys", &arr)) {
+               log_error("Config does not contain 'keys' parameter.");
+               ret = -EINVAL;
+               goto cleanup;
+       }
+
+       if (!json_object_is_type(arr, json_type_array)) {
+               log_error("Config value is not an array");
+               ret = -EINVAL;
+               goto cleanup;
+       }
+
+       for (size_t i = 0; i < json_object_array_length(arr); i++) {
+               knode = NULL;
+               val = json_object_array_get_idx(arr, i);
+               if (val == NULL) {
+                       log_error("vconf: no specified key (%zu)\n", i);
+                       ret = -EINVAL;
+                       goto cleanup;
+               }
+
+               klist = vconf_keylist_new();
+               if (!klist) {
+                       log_error("vconf: could not create keylist for %s\n", json_object_get_string(val));
+                       continue;
+               }
+
+               ret = vconf_get(klist, json_object_get_string(val), VCONF_GET_ALL);
+               if (ret < 0) {
+                       log_debug("vconf: keylist does not contain key %s\n", json_object_get_string(val));
+                       goto free_list;
+               }
+
+               ret = vconf_keylist_lookup(klist, json_object_get_string(val), &knode);
+               if (ret <= 0) {
+                       log_debug("vconf_keylist_lookup failed for %s\n", json_object_get_string(val));
+                       //goto free_list;
+               }
+
+               ret = add_key(listener, json_object_get_string(val), knode);
+               if (ret < 0)
+                       log_error("vconf: could not add key\n");
+
+               free_list:
+                       vconf_keylist_free(klist);
+       }
+       return 0;
+
+cleanup:
+       cleanup(listener);
+       return ret;
+}
+
+static void vconf_listener_cleanup(struct epc_module *module)
+{
+       struct vconf_listener *listener = to_vconf_listener(module);
+       cleanup(listener);
+}
+
+struct vconf_listener vconf_listener = {
+       .module = {
+               .name = "vconf_listener",
+               .type = EPC_MODULE_TYPE_LISTENER,
+
+               .init = vconf_listener_init,
+               .cleanup = vconf_listener_cleanup,
+               .node = LIST_HEAD_INIT(vconf_listener.module.node),
+       },
+};
+
+EPC_MODULE_REGISTER(&vconf_listener.module)
diff --git a/tests/activationd-acceptance-test.service b/tests/activationd-acceptance-test.service
new file mode 100644 (file)
index 0000000..8d905ba
--- /dev/null
@@ -0,0 +1,6 @@
+[Unit]
+Description=activationd acceptance tests service
+
+[Service]
+Type=simple
+ExecStart=/usr/bin/activationd_acceptance_service
diff --git a/tests/activationd_acceptance_checker.c b/tests/activationd_acceptance_checker.c
new file mode 100644 (file)
index 0000000..5d6295f
--- /dev/null
@@ -0,0 +1,434 @@
+/*
+ * This file is part of epc.
+ *
+ * Copyright © 2019 Samsung Electronics
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <systemd/sd-bus.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/timerfd.h>
+#include <vconf.h>
+
+#include "common.h"
+#include "systemd_dbus.h"
+
+#define DBUS_PROPERTIES_INTERFACE "org.freedesktop.DBus.Properties"
+#define SERVICE_NAME "activationd-acceptance-test.service"
+#define VCONF_ACTIVATION_KEY "file/activationd/acceptance"
+
+enum unit_state {
+       UNKNOWN,
+       ACTIVE,
+       INACTIVE
+};
+
+struct action {
+       const char *action;
+       enum unit_state expected_states[2];
+       int state_count;
+       int current_state;
+};
+
+struct test_sequence {
+       struct action actions[3];
+       int current_action;
+       int ok;
+};
+
+
+struct test_data {
+       sd_bus *bus;
+       sd_event *loop;
+       struct test_sequence test;
+       enum unit_state state;
+       enum unit_state prev_state;
+       char *path;
+};
+
+static const char *from_unit_state(enum unit_state state)
+{
+       switch (state) {
+       case UNKNOWN:
+               return "unknown";
+       case ACTIVE:
+               return "active";
+       default:
+               return "inactive";
+       }
+}
+
+static enum unit_state to_unit_state(const char *state)
+{
+       if (!strncmp (state, "active", 6))
+               return ACTIVE;
+       else if (!strncmp (state, "inactive", 8) || !strncmp (state, "deactivating", 12))
+               return INACTIVE;
+       else
+               return UNKNOWN;
+}
+
+static int set_vconf_key(const char *val)
+{
+       keylist_t *kl = NULL;
+       kl = vconf_keylist_new();
+       if (!kl) {
+               fprintf(stderr, "error creating vconf keylists\n");
+               return -1;
+       }
+
+       vconf_keylist_add_str(kl, VCONF_ACTIVATION_KEY, val);
+       if (vconf_set(kl) < 0) {
+               fprintf(stderr, "error saving vconf key\n");
+               vconf_keylist_free(kl);
+               return -1;
+       }
+
+       vconf_keylist_free(kl);
+       return 0;
+}
+
+static int test_step(struct test_data *data)
+{
+       struct test_sequence *test = &data->test;
+       if (test->current_action == ARRAY_SIZE(test->actions)) {
+               sd_event_exit(data->loop, EXIT_SUCCESS);
+               test->ok = 1;
+               return 0;
+       }
+
+       if (set_vconf_key(test->actions[test->current_action].action))
+               return -1;
+       return 0;
+}
+
+static int check_test_result(struct test_data *data)
+{
+       struct action *a = &data->test.actions[data->test.current_action];
+       enum unit_state exp_state = a->expected_states[a->current_state];
+
+       if (data->test.ok == 1)
+               return 0;
+
+       if (data->state != exp_state) {
+               data->test.ok = 1;
+               fprintf(stderr, "test failed (%s instead of %s at step %d of %s)\n",
+                               from_unit_state(data->state),
+                               from_unit_state(exp_state),
+                               a->current_state,
+                               a->action);
+
+               sd_event_exit(data->loop, EXIT_FAILURE);
+               return -1;
+       }
+       a->current_state++;
+       if (a->current_state == a->state_count) {
+               data->test.current_action++;
+               if (test_step(data) < 0)
+                       return -1;
+       }
+       return 0;
+}
+
+
+static int check_unit_state(struct test_data *data, const char *state)
+{
+       enum unit_state new_state;
+
+       new_state = to_unit_state(state);
+       if (data->state != new_state) {
+               data->prev_state = data->state;
+               data->state = new_state;
+               check_test_result(data);
+       }
+       return 0;
+}
+
+
+static int on_properties_changed(sd_bus_message *m, void *userdata, sd_bus_error *ret_error) {
+       int r;
+       struct test_data *data = (struct test_data*)userdata;
+       const char *iface;
+       const char *member;
+       const char *value = NULL;
+       const char *contents;
+
+       r = sd_bus_message_read(m, "s", &iface);
+       if (r < 0) {
+               fprintf(stderr, "Failed to parse PropertiesChanged\n");
+               return r;
+       }
+
+       r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "{sv}");
+       if (r < 0)
+               return r;
+
+       while ((r = sd_bus_message_enter_container(m, SD_BUS_TYPE_DICT_ENTRY, "sv")) > 0) {
+               char type;
+
+               r = sd_bus_message_read(m, "s", &member);
+               if (r < 0)
+                       return r;
+
+               r = sd_bus_message_peek_type(m, &type, &contents);
+               if (r < 0)
+                       return r;
+
+               r = sd_bus_message_enter_container(m, SD_BUS_TYPE_VARIANT, contents);
+               if (r < 0)
+                       return r;
+
+               if (strcmp(member, "ActiveState") == 0) {
+                       r = sd_bus_message_read(m, "s", &value);
+                       if (r < 0)
+                               return r;
+               } else {
+                       r = sd_bus_message_skip(m, contents);
+                       if (r < 0)
+                               return r;
+               }
+
+               r = sd_bus_message_exit_container(m);
+               if (r < 0)
+                       return r;
+
+               r = sd_bus_message_exit_container(m);
+               if (r < 0)
+                       return r;
+       }
+
+       r = sd_bus_message_exit_container(m);
+       if (r < 0)
+               return r;
+
+       if (value)
+               check_unit_state(data, value);
+       return 0;
+}
+
+static void cleanup(struct test_data *data)
+{
+       free(data->path);
+       if (!data->bus)
+               return;
+       sd_bus_flush(data->bus);
+       sd_bus_unref(data->bus);
+}
+
+static int signal_handler(sd_event_source *s,
+               const struct signalfd_siginfo *si,
+               void *userdata)
+{
+       sd_event *loop = userdata;
+       sd_event_exit(loop, EXIT_FAILURE);
+       return 0;
+}
+
+static int start_test(sd_event_source *s, uint64_t usec, void *userdata)
+{
+       struct test_data *data = (struct test_data*)userdata;
+       return test_step(data);
+}
+
+static int timeout_handler(sd_event_source *s, uint64_t usec, void *userdata)
+{
+       struct test_data *data = (struct test_data*)userdata;
+       fprintf(stderr, "test timed out\n");
+       sd_event_exit(data->loop, EXIT_FAILURE);
+       return 0;
+}
+
+static int call_subscribe(struct test_data *data)
+{
+       __attribute__((cleanup(sd_bus_message_unrefp))) sd_bus_message *reply = NULL;
+       __attribute__((cleanup(sd_bus_error_free))) sd_bus_error error = SD_BUS_ERROR_NULL;
+       int ret;
+
+       ret = sd_bus_call_method(data->bus,
+                       SYSTEMD_SERVICE,
+                       SYSTEMD_OBJ,
+                       SYSTEMD_MANAGER_INTERFACE,
+                       "Subscribe",
+                       &error,
+                       &reply,
+                       "");
+
+       if (ret < 0) {
+               fprintf(stderr, "Failed to issue Subscribe() call: %s\n", error.message);
+               return -1;
+       }
+       return 0;
+}
+
+static int call_load_unit(struct test_data *data)
+{
+       __attribute__((cleanup(sd_bus_message_unrefp))) sd_bus_message *reply = NULL;
+       __attribute__((cleanup(sd_bus_error_free))) sd_bus_error error = SD_BUS_ERROR_NULL;
+       int ret;
+       const char *path = NULL;
+       char err[512];
+
+       ret = sd_bus_call_method(data->bus,
+                       SYSTEMD_SERVICE,
+                       SYSTEMD_OBJ,
+                       SYSTEMD_MANAGER_INTERFACE,
+                       "LoadUnit",
+                       &error,
+                       &reply,
+                       "s",
+                       SERVICE_NAME);
+
+       if (ret < 0) {
+               fprintf(stderr, "Failed to issue LoadUnit() call: %s\n", error.message);
+               return -1;
+       }
+
+       ret = sd_bus_message_read(reply, "o", &path);
+       if (ret < 0) {
+               if (strerror_r(-ret, err, sizeof err))
+                       fprintf(stderr, "Failed to read reply: %s\n", err);
+               return -1;
+       }
+
+       if (!path) {
+               fprintf(stderr, "ould not get object path\n");
+               return -1;
+       }
+       data->path = strdup(path);
+       return 0;
+}
+int main(int argc, char *argv[])
+{
+       struct test_data data = {
+               .bus = NULL,
+               .loop = NULL,
+               .state = UNKNOWN,
+               .prev_state = UNKNOWN,
+               .path = NULL,
+               .test = {
+                       .actions = {
+                               {"START", {ACTIVE, UNKNOWN}, 1, 0},
+                               {"RELOAD", {INACTIVE, ACTIVE}, 2, 0},
+                               {"STOP", {INACTIVE, UNKNOWN}, 1, 0}
+                       },
+                       .current_action = 0,
+                       .ok = 0
+               }
+       };
+
+       int r;
+       uint64_t now;
+       sigset_t ss;
+       char buf[512];
+       char err[512];
+
+       r = sd_bus_open_system(&data.bus);
+       if (r < 0) {
+               if (strerror_r(-r, err, sizeof err))
+                       fprintf(stderr, "Failed to read reply: %s\n", err);
+               goto fail;
+       }
+
+       r = call_subscribe(&data);
+       if (r < 0)
+               goto fail;
+
+       r = call_load_unit(&data);
+       if (r < 0)
+               goto fail;
+
+       r = snprintf(buf, sizeof buf, "type='signal',interface='org.freedesktop.DBus.Properties',member='PropertiesChanged', path='%s'", data.path);
+       if (r < 0) {
+               if (strerror_r(-r, err, sizeof err))
+                       fprintf(stderr, "Failed to create match rule: %s\n", err);
+               goto fail;
+       }
+
+       r = sd_bus_add_match(data.bus, NULL, buf, on_properties_changed, &data);
+       if (r < 0) {
+               if (strerror_r(-r, err, sizeof err))
+                       fprintf(stderr, "Failed to add PropertiesChanged match: %s\n", err);
+               goto fail;
+       }
+
+       r = sd_event_new(&data.loop);
+       if (r < 0) {
+               if (strerror_r(-r, err, sizeof err))
+                       fprintf(stderr, "Failed to create main loop: %s\n", err);
+               goto fail;
+       }
+
+       sigemptyset(&ss);
+       sigaddset(&ss, SIGINT);
+       sigaddset(&ss, SIGTERM);
+       r = sigprocmask(SIG_BLOCK, &ss, NULL);
+       if (r < 0) {
+               if (strerror_r(-r, err, sizeof err))
+                       fprintf(stderr, "Failed to change signal mask: %s\n", err);
+               goto fail;
+       }
+
+       r = sd_event_add_signal(data.loop, NULL, SIGINT, signal_handler, data.loop);
+       if (r < 0) {
+               if (strerror_r(-r, err, sizeof err))
+                       fprintf(stderr, "Failed to register SIGINT handler: %s\n", err);
+               goto fail;
+       }
+
+       r = sd_event_add_signal(data.loop, NULL, SIGTERM, signal_handler, data.loop);
+       if (r < 0) {
+               if (strerror_r(-r, err, sizeof err))
+                       fprintf(stderr, "Failed to register SIGTERM handler: %s\n", err);
+               goto fail;
+       }
+
+       r = sd_bus_attach_event(data.bus, data.loop, 0);
+       if (r < 0) {
+               if (strerror_r(-r, err, sizeof err))
+                       fprintf(stderr, "Failed to attach bus to event loop: %s\n", err);
+               goto fail;
+       }
+
+       r = sd_event_add_time(data.loop, NULL, CLOCK_REALTIME, 0, 0, start_test, &data);
+       if (r < 0) {
+               if (strerror_r(-r, err, sizeof err))
+                       fprintf(stderr, "Failed to attach timer to event loop: %s\n", err);
+               goto fail;
+       }
+
+       sd_event_now(data.loop, CLOCK_REALTIME, &now);
+
+       r = sd_event_add_time(data.loop, NULL, CLOCK_REALTIME, now+10000000, 0, timeout_handler, &data);
+       if (r < 0) {
+               if (strerror_r(-r, err, sizeof err))
+                       fprintf(stderr, "Failed to attach timer to event loop: %s\n", err);
+               goto fail;
+       }
+
+       r = sd_event_loop(data.loop);
+       if (r < 0) {
+               if (strerror_r(-r, err, sizeof err))
+                       fprintf(stderr, "Failed to run main loop: %s\n", err);
+               goto fail;
+       }
+
+       cleanup(&data);
+       return r;
+
+fail:
+       cleanup(&data);
+       return EXIT_FAILURE;
+}
diff --git a/tests/activationd_acceptance_service.c b/tests/activationd_acceptance_service.c
new file mode 100644 (file)
index 0000000..5a4b946
--- /dev/null
@@ -0,0 +1,44 @@
+/*
+ * This file is part of epc.
+ *
+ * Copyright © 2019 Samsung Electronics
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <signal.h>
+
+static void exit_handler(int signo)
+{
+       exit(EXIT_SUCCESS);
+}
+
+int main(int argc, char *argv[])
+{
+       if (signal(SIGINT, exit_handler) == SIG_ERR ||
+                       signal(SIGQUIT, exit_handler) == SIG_ERR ||
+                       signal(SIGTERM, exit_handler) == SIG_ERR) {
+               perror("catching SIGNAL");
+               exit(EXIT_FAILURE);
+       }
+
+       printf("service started, do nothing...\n");
+       while (1)
+               sleep(10);
+
+       exit_handler(0);
+}
+
diff --git a/tests/activationd_acceptance_test b/tests/activationd_acceptance_test
new file mode 100755 (executable)
index 0000000..88fe1af
--- /dev/null
@@ -0,0 +1,28 @@
+#!/bin/sh
+
+EPCD_PID=-1
+
+cleanup() {
+       systemctl stop activationd-acceptance-test
+       [ $EPCD_PID -ne -1 ] && kill $EPCD_PID > /dev/null 2>&1
+       vconftool unset  file/activationd/acceptance
+       exit 0
+}
+
+trap cleanup 0
+
+vconftool -f set -t string file/activationd/acceptance foo
+
+# assumes there's no epcd service running
+epcd > /dev/null 2>&1 &
+EPCD_PID=$!
+sleep 2
+
+/usr/bin/activationd_acceptance_checker
+
+if [ "$?" -eq "0" ]; then
+       echo "ok"
+else
+       echo "fail"
+fi
+