service_restart_action.la \
unit_start_action.la \
vconf_key_changed_event.la \
+ dbus_signal_event.la \
activation_dm.la \
- vconf_listener.la
+ vconf_listener.la \
+ dbus_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
+dbus_signal_event_la_SOURCES = src/event_types/dbus_signal_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
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
+dbus_listener_la_SOURCES = src/listeners/dbus.c
+dbus_listener_config_DATA = modules.conf.d/dbus_listener.conf.d/50-default.conf
+dbus_listener_configdir = $(modulesconfigdir)/dbus_listener.conf.d
epcd_LDADD = $(LIBSYSTEMD_LIBS) $(GLIB_LIBS) $(JSON_C_LIBS)
install-data-local:
$(MKDIR_P) $(DESTDIR)${vconf_listener_configdir}
+ $(MKDIR_P) $(DESTDIR)${dbus_listener_configdir}
--- /dev/null
+/*
+ * 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_DBUS_SIGNAL_EVENT_H
+#define _EPC_DBUS_SIGNAL_EVENT_H
+
+#include <time.h>
+#include "event.h"
+
+#define DBUS_SIGNAL_EVENT_ID "dbus_signal"
+#define DS_EV_TIME "et"
+#define DS_EV_ID "event_id"
+#define DS_EV_SENDER "sender"
+#define DS_EV_INTERFACE "interface"
+#define DS_EV_MEMBER "member"
+#define DS_EV_PATH "path"
+#define DS_EV_PATH_NAMESPACE "path_namespace"
+#define DS_EV_DESTINATION "destination"
+#define DS_EV_PARAMS "params"
+
+struct dbus_signal_event {
+ struct epc_event event;
+ time_t event_time;
+ char *event_id;
+ char *sender;
+ char *interface;
+ char *member;
+ char *path;
+ char *path_namespace;
+ char *destination;
+ struct epc_object *params;
+};
+
+struct dbus_signal_event_data {
+ time_t event_time;
+ char *event_id;
+ char *sender;
+ char *interface;
+ char *member;
+ char *path;
+ char *path_namespace;
+ char *destination;
+ struct epc_object *params;
+};
+
+#define to_dbus_signal_event(EVENT) \
+ container_of(EVENT, struct dbus_signal_event, event)
+
+#endif /* _EPC_DBUS_SIGNAL_EVENT_H */
--- /dev/null
+{
+ "signals":[
+ {"id":"example_signal", "interface":"org.freedesktop.ExampleInterface", "member":"ExampleSignal", "path_namespace":"/org/freedesktop"}
+ ]
+}
Group: System/Monitoring
Requires: event-processing-core
Requires: event-processing-vconf
+Requires: event-processing-dbus
Requires: event-processing-activation-dm
BuildRequires: pkgconfig(vconf)
%description -n event-processing-vconf
This package provides a listener for vconf events
+%package -n event-processing-dbus
+Summary: dbus listener module for epc
+Group: System/Monitoring
+
+%description -n event-processing-dbus
+This package provides a listener for dbus events
+
%package -n event-processing-activation-dm
Summary: Activation decision maker
Group: System/Monitoring
%install_module unit_start_action extra
%install_module vconf_key_changed_event vconf
%install_module vconf_listener vconf
+%install_module dbus_signal_event dbus
+%install_module dbus_listener dbus
%install_module activation_dm activation-dm
%files
%files -n event-processing-vconf -f vconf-files
%{_prefix}/lib/epc/modules.conf.d/vconf_listener.conf.d/50-default.conf
+%files -n event-processing-dbus -f dbus-files
+%{_prefix}/lib/epc/modules.conf.d/dbus_listener.conf.d/50-default.conf
+
%files -n activationd-test-services
%license COPYING
%manifest %{name}.manifest
--- /dev/null
+/*
+ * 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 "dbus_signal_event.h"
+
+static int allocate_dbus_signal_event(struct epc_event_type *type,
+ void *data, struct epc_event **ev)
+{
+ struct dbus_signal_event *ds_ev;
+ struct dbus_signal_event_data *ds_ev_data = data;
+ int ret;
+
+ ds_ev = calloc(1, sizeof(*ds_ev));
+ if (!ds_ev)
+ return -ENOMEM;
+
+ ret = epc_event_init_internal(type, &ds_ev->event);
+ if (ret)
+ goto cleanup;
+
+ ds_ev->event_time = ds_ev_data->event_time;
+ ds_ev->event_id = ds_ev_data->event_id;
+ ds_ev->sender = ds_ev_data->sender;
+ ds_ev->interface = ds_ev_data->interface;
+ ds_ev->member = ds_ev_data->member;
+ ds_ev->path = ds_ev_data->path;
+ ds_ev->path_namespace = ds_ev_data->path_namespace;
+ ds_ev->destination = ds_ev_data->destination;
+ ds_ev->params = ds_ev_data->params;
+
+ *ev = &ds_ev->event;
+ return 0;
+cleanup:
+ free(ds_ev);
+
+ return ret;
+}
+
+static int deserialize_dbus_signal_event(struct epc_event_type *type,
+ struct epc_object *data, struct epc_event **ev)
+{
+ int ret = -EINVAL;
+ struct dbus_signal_event_data ds_ev_data;
+ struct epc_object *obj;
+ memset(&ds_ev_data, 0, sizeof(ds_ev_data));
+
+ list_for_each_entry(obj, &data->val.children, node) {
+ switch (obj->type) {
+ case TYPE_TIME_T:
+ if (!strcmp(DS_EV_TIME, obj->key))
+ ds_ev_data.event_time = obj->val.time;
+ break;
+ case TYPE_STRING:
+ if (!strcmp(DS_EV_ID, obj->key))
+ ds_ev_data.event_id = strdup(obj->val.s);
+ else if (!strcmp(DS_EV_SENDER, obj->key))
+ ds_ev_data.sender = strdup(obj->val.s);
+ else if (!strcmp(DS_EV_INTERFACE, obj->key))
+ ds_ev_data.interface = strdup(obj->val.s);
+ else if (!strcmp(DS_EV_MEMBER, obj->key))
+ ds_ev_data.member = strdup(obj->val.s);
+ else if (!strcmp(DS_EV_PATH, obj->key))
+ ds_ev_data.path = strdup(obj->val.s);
+ else if (!strcmp(DS_EV_PATH_NAMESPACE, obj->key))
+ ds_ev_data.path_namespace = strdup(obj->val.s);
+ else if (!strcmp(DS_EV_DESTINATION, obj->key))
+ ds_ev_data.destination = strdup(obj->val.s);
+ break;
+ case TYPE_OBJECT:
+ if (!strcmp(DS_EV_PARAMS, obj->key)) {
+ epc_object_ref(obj);
+ ds_ev_data.params = obj;
+ }
+ break;
+ }
+ }
+
+ ret = allocate_dbus_signal_event(type, &ds_ev_data, ev);
+ if (ret < 0)
+ goto finish;
+
+ ret = epc_event_deserialize_internal(data, type, *ev);
+ if (ret < 0) {
+ struct dbus_signal_event *ds_ev =
+ to_dbus_signal_event(*ev);
+ free(ds_ev);
+ goto finish;
+ }
+ ret = 0;
+finish:
+ return ret;
+}
+
+static void dbus_signal_event_release(struct epc_event *ev)
+{
+ struct dbus_signal_event *ds_ev =
+ to_dbus_signal_event(ev);
+
+ free(ds_ev->event_id);
+ free(ds_ev->sender);
+ free(ds_ev->interface);
+ free(ds_ev->member);
+ free(ds_ev->path);
+ free(ds_ev->path_namespace);
+ free(ds_ev->destination);
+ if (ds_ev->params)
+ epc_object_destroy(ds_ev->params);
+ epc_event_cleanup_internal(&ds_ev->event);
+ free(ds_ev);
+}
+
+static void dbus_signal_event_serialize(struct epc_event *ev, struct epc_object *out)
+{
+ struct dbus_signal_event *ds_ev =
+ to_dbus_signal_event(ev);
+ epc_event_serialize_internal(ev, out);
+ epc_object_append_time_t(out, DS_EV_TIME, ds_ev->event_time);
+ epc_object_append_string(out, DS_EV_ID, ds_ev->event_id);
+ if (ds_ev->sender)
+ epc_object_append_string(out, DS_EV_SENDER, ds_ev->sender);
+ if (ds_ev->interface)
+ epc_object_append_string(out, DS_EV_INTERFACE, ds_ev->interface);
+ if (ds_ev->member)
+ epc_object_append_string(out, DS_EV_MEMBER, ds_ev->member);
+ if (ds_ev->path)
+ epc_object_append_string(out, DS_EV_PATH, ds_ev->path);
+ if (ds_ev->path_namespace)
+ epc_object_append_string(out, DS_EV_PATH_NAMESPACE, ds_ev->path_namespace);
+ if (ds_ev->destination)
+ epc_object_append_string(out, DS_EV_DESTINATION, ds_ev->destination);
+ if (ds_ev->params)
+ epc_object_append_object(out, DS_EV_PARAMS, ds_ev->params);
+}
+
+static struct epc_event_type dbus_signal_event_type = {
+ .name = DBUS_SIGNAL_EVENT_ID,
+ .default_ops = {
+ .release = dbus_signal_event_release,
+ .serialize = dbus_signal_event_serialize,
+ },
+ .allocate_event = allocate_dbus_signal_event,
+ .deserialize_event = deserialize_dbus_signal_event,
+ .node = LIST_HEAD_INIT(dbus_signal_event_type.node),
+};
+
+EPC_EVENT_TYPE_REGISTER(dbus_signal_event_type, dbus_signal_et)
--- /dev/null
+/*
+ * 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 "log.h"
+#include "module.h"
+#include "common.h"
+#include "list.h"
+#include "json-config.h"
+#include "event_processor.h"
+#include "systemd_dbus.h"
+#include "dbus_signal_event.h"
+
+struct dbus_signal {
+ char *event_id;
+ char *sender;
+ char *interface;
+ char *member;
+ char *path;
+ char *path_namespace;
+ char *destination;
+ struct list_head node;
+};
+
+struct dbus_listener {
+ struct epc_module module;
+ struct list_head signals;
+};
+
+#define to_dbus_listener(MOD) \
+ container_of(MOD, struct dbus_listener, module)
+
+static int append_param(struct epc_object *params, char type, int pos, const void *val)
+{
+ int r;
+ char key[64];
+
+ memset (key, 0, sizeof key);
+
+ r = snprintf(key, sizeof key, "arg%d", pos);
+ if (r < 0)
+ return r;
+
+ switch (type) {
+ case SD_BUS_TYPE_STRING:
+ r = epc_object_append_string(params, key, (char *)val);
+ break;
+ case SD_BUS_TYPE_BOOLEAN:
+ r = epc_object_append_bool(params, key, *(bool *)val);
+ break;
+ case SD_BUS_TYPE_DOUBLE:
+ r = epc_object_append_double(params, key, *(double *)val);
+ break;
+ case SD_BUS_TYPE_UINT64:
+ case SD_BUS_TYPE_INT64:
+ case SD_BUS_TYPE_UINT32:
+ case SD_BUS_TYPE_INT32:
+ r = epc_object_append_int(params, key, *(int *)val);
+ break;
+ default:
+ r = 0;
+ break;
+ }
+ if (r < 0)
+ return r;
+ return 0;
+}
+
+static int parse_message_args(sd_bus_message *m, struct epc_object *params)
+{
+ int r;
+ char type;
+ const char *contents;
+ int pos = 0;
+
+ while (1) {
+ r = sd_bus_message_peek_type(m, &type, &contents);
+ if (r == 0) {
+ break;
+ } else if (r < 0) {
+ log_error("sd_bus_message_peek_type: %s\n", strerror(-r));
+ return r;
+ }
+ pos++;
+
+ switch (type) {
+ case SD_BUS_TYPE_STRING: {
+ const char *v;
+
+ r = sd_bus_message_read_basic(m, type, &v);
+ if (r < 0)
+ return r;
+
+ r = append_param(params, type, pos, v);
+ if (r < 0)
+ return r;
+ break;
+ }
+ case SD_BUS_TYPE_BOOLEAN:
+ case SD_BUS_TYPE_UINT64:
+ case SD_BUS_TYPE_INT64:
+ case SD_BUS_TYPE_UINT32:
+ case SD_BUS_TYPE_INT32:
+ case SD_BUS_TYPE_DOUBLE: {
+ union {
+ int b;
+ uint64_t u64;
+ int64_t i64;
+ uint32_t u32;
+ int32_t i32;
+ double d;
+ } v;
+
+ r = sd_bus_message_read_basic(m, type, &v);
+ if (r < 0)
+ return r;
+
+ r = append_param(params, type, pos, &v);
+ if (r < 0)
+ return r;
+ break;
+ }
+ default: {
+ r = sd_bus_message_read_basic(m, type, NULL);
+ if (r < 0)
+ return r;
+ break;
+ }
+ }
+
+ }
+ return 0;
+}
+
+
+static int on_dbus_signal_match(sd_bus_message *m, void *userdata, sd_bus_error *ret_error) {
+ struct dbus_signal *s = (struct dbus_signal *)userdata;
+
+ struct dbus_signal_event_data ds_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 -1;
+ }
+
+ ds_ev_data.event_time = ts.tv_sec;
+
+#define COPY_COND(x) do { \
+ if (s->x) { \
+ ds_ev_data.x = strdup(s->x); \
+ if (ds_ev_data.x == NULL) \
+ goto finish; \
+ } \
+ } while (0)
+
+ COPY_COND(event_id);
+ COPY_COND(sender);
+ COPY_COND(interface);
+ COPY_COND(member);
+ COPY_COND(path);
+ COPY_COND(path_namespace);
+ COPY_COND(destination);
+
+#undef COPY_COND
+
+ if (epc_object_new(&ds_ev_data.params) < 0)
+ goto finish;
+
+ ret = parse_message_args(m, ds_ev_data.params);
+ if (ret) {
+ log_error_errno(ret, "Unable to parse signal parameters: %m.");
+ goto finish;
+ }
+
+ ret = epc_event_create(DBUS_SIGNAL_EVENT_ID, &ds_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 0;
+finish:
+ free(ds_ev_data.event_id);
+ free(ds_ev_data.sender);
+ free(ds_ev_data.interface);
+ free(ds_ev_data.member);
+ free(ds_ev_data.path);
+ free(ds_ev_data.path_namespace);
+ free(ds_ev_data.destination);
+ if (ds_ev_data.params)
+ epc_object_destroy(ds_ev_data.params);
+
+ return -1;
+}
+
+static void signal_cleanup(struct dbus_signal *s)
+{
+ free(s->event_id);
+ free(s->sender);
+ free(s->interface);
+ free(s->member);
+ free(s->path);
+ free(s->path_namespace);
+ free(s->destination);
+ free(s);
+}
+
+
+static void cleanup(struct dbus_listener *l)
+{
+ struct dbus_signal *s, *next;
+
+ list_for_each_entry_safe(s, next, &l->signals, node) {
+ list_del(&s->node);
+ signal_cleanup(s);
+ }
+}
+
+static int add_signal(struct dbus_listener *l, json_object *root, sd_bus *bus)
+{
+ int ret;
+ struct dbus_signal *s;
+ char match_buf[1024];
+ int size;
+ char err[512];
+
+ s = calloc(1, sizeof(*s));
+ if (!s) {
+ log_error("Could not allocate dbus_signal object");
+ return -ENOMEM;
+ }
+
+ ret = get_config_field(root, "id", &s->event_id, json_type_string);
+ if (ret < 0)
+ goto out;
+
+ log_debug("Adding signal: %s", s->event_id);
+
+ (void) get_config_field(root, "sender", &s->sender, json_type_string);
+
+ ret = get_config_field(root, "interface", &s->interface, json_type_string);
+ if (ret < 0)
+ goto out;
+
+ ret = get_config_field(root, "member", &s->member, json_type_string);
+ if (ret < 0)
+ goto out;
+
+ (void) get_config_field(root, "path", &s->path, json_type_string);
+ (void) get_config_field(root, "path_namespace", &s->path_namespace, json_type_string);
+
+ if (!s->path && !s->path_namespace)
+ goto out;
+
+ (void) get_config_field(root, "destination", &s->destination, json_type_string);
+
+ memset(match_buf, 0, sizeof match_buf);
+ size = 0;
+
+ ret = snprintf(match_buf+size, sizeof match_buf-size, "type='signal',");
+ if (ret < 0)
+ goto out;
+ size += ret;
+
+#define APPEND_MATCH(x) do { \
+ ret = snprintf(match_buf+size, sizeof match_buf-size, #x "='%s',", s->x); \
+ if (ret < 0) \
+ goto out; \
+ size += ret; \
+ } while (0)
+
+ if (s->sender)
+ APPEND_MATCH(sender);
+ APPEND_MATCH(interface);
+ APPEND_MATCH(member);
+
+ if (s->path)
+ APPEND_MATCH(path);
+ else if (s->path_namespace)
+ APPEND_MATCH(path_namespace);
+
+ if (s->destination)
+ APPEND_MATCH(destination);
+
+#undef APPEND_MATCH
+
+ match_buf[size-1] = '\0';
+
+ ret = sd_bus_add_match(bus, NULL, match_buf, on_dbus_signal_match, s);
+ if (ret < 0) {
+ if (strerror_r(-ret, err, sizeof err))
+ log_error("Failed to add signal match: %s\n", err);
+ goto out;
+ }
+
+ list_add_tail(&s->node, &l->signals);
+ return 0;
+
+out:
+ signal_cleanup(s);
+ return ret;
+}
+
+
+static int dbus_listener_init(struct epc_module *module,
+ struct epc_config *config,
+ sd_event* loop)
+{
+ struct dbus_listener *listener = to_dbus_listener(module);
+ int ret = 0, len, i;
+ json_object *arr, *obj;
+ sd_bus *bus = NULL;
+ char err[512];
+
+ INIT_LIST_HEAD(&listener->signals);
+
+ if (config == NULL)
+ return 0;
+
+ ret = epc_acquire_systemd_bus(&bus);
+ if (ret < 0) {
+ log_error_errno(ret, "Failed to acquire the default system bus connection: %m");
+ return -EINVAL;
+ }
+
+ if (!json_object_object_get_ex(config->root, "signals", &arr)) {
+ log_error("There is no 'signals' array");
+ return -EINVAL;
+ }
+
+ if (!json_object_is_type(arr, json_type_array)) {
+ log_error("Config value is not an array");
+ return -EINVAL;
+ }
+
+ len = json_object_array_length(arr);
+ for (i = 0; i < len; ++i) {
+ obj = json_object_array_get_idx(arr, i);
+ ret = add_signal(listener, obj, bus);
+ if (ret < 0) {
+ log_error("Could not add signal");
+ goto cleanup;
+ }
+ }
+
+ ret = sd_bus_attach_event(bus, loop, 0);
+ if (ret < 0) {
+ if (strerror_r(-ret, err, sizeof err))
+ log_error("Failed to attach bus to event loop: %s\n", err);
+ goto cleanup;
+ }
+
+ return 0;
+
+cleanup:
+ cleanup(listener);
+ return ret;
+}
+
+static void dbus_listener_cleanup(struct epc_module *module)
+{
+ struct dbus_listener *listener = to_dbus_listener(module);
+ cleanup(listener);
+}
+
+struct dbus_listener dbus_listener = {
+ .module = {
+ .name = "dbus_listener",
+ .type = EPC_MODULE_TYPE_LISTENER,
+
+ .init = dbus_listener_init,
+ .cleanup = dbus_listener_cleanup,
+ .node = LIST_HEAD_INIT(dbus_listener.module.node),
+ },
+};
+
+EPC_MODULE_REGISTER(&dbus_listener.module)