unit_start_action.la \
vconf_key_changed_event.la \
dbus_signal_event.la \
+ unit_control_event.la \
activation_dm.la \
vconf_listener.la \
- dbus_listener.la
+ dbus_listener.la \
+ unit_control_api.la \
+ unit_control_dm.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
+unit_control_event_la_SOURCES = src/event_types/unit_control_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
+unit_control_dm_la_SOURCES = src/decision_makers/unit_control_dm.c
+unit_control_dm_config_DATA = modules.conf.d/unit_control_eh.conf.d/unit_control_eh.conf
+unit_control_dm_configdir = $(modulesconfigdir)/unit_control_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
dbus_listener_config_DATA = modules.conf.d/dbus_listener.conf.d/50-default.conf
dbus_listener_config_DATA += modules.conf.d/dbus_listener.conf.d/99-acceptance-test.conf
dbus_listener_configdir = $(modulesconfigdir)/dbus_listener.conf.d
+unit_control_api_la_SOURCES = src/listeners/unit_control_api.c
+unit_control_api_config_DATA = org.tizen.Activationd.conf
+unit_control_api_configdir = /etc/dbus-1/system.d/
actd_LDADD = $(LIBSYSTEMD_LIBS) $(GLIB_LIBS) $(JSON_C_LIBS)
--- /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 UNIT_CONTROL_EVENT_H
+#define UNIT_CONTROL_EVENT_H
+
+#include <time.h>
+#include "event.h"
+
+#define UC_EVENT_ID "unit_control"
+#define UC_TIME "et"
+#define UC_UNIT "unit"
+#define UC_METHOD "method"
+
+struct unit_control_event {
+ struct epc_event event;
+ char *method;
+ char *unit;
+ time_t event_time;
+};
+
+struct unit_control_event_data {
+ char *method;
+ char *unit;
+ time_t event_time;
+};
+
+#define to_unit_control_event(EVENT) \
+ container_of(EVENT, struct unit_control_event, event)
+
+
+#endif /* UNIT_CONTROL_EVENT_H */
--- /dev/null
+{
+ "whitelist":[ "activationd-acceptance-test-s-p.service", "activationd-acceptance-test-s-n.service" ]
+}
--- /dev/null
+<!DOCTYPE busconfig PUBLIC
+ "-//freedesktop//DTD D-BUS Bus Configuration 1.0//EN"
+ "http://www.freedesktop.org/standards/dbus/1.0/busconfig.dtd">
+<busconfig>
+ <policy user="root">
+ <allow own="org.tizen.Activationd"/>
+ <allow send_destination="org.tizen.Activationd"/>
+ </policy>
+ <policy context="default">
+ <deny send_destination="org.tizen.Activationd"/>
+ </policy>
+</busconfig>
Requires: event-processing-core
Requires: event-processing-vconf
Requires: event-processing-dbus
+Requires: event-processing-unit-control
Requires: event-processing-activation-dm
BuildRequires: pkgconfig(vconf)
Summary: dbus listener module for epc
Group: System/Monitoring
+%package -n event-processing-unit-control
+Summary: unit control dbus api module for epc
+Group: System/Monitoring
+
+%description -n event-processing-unit-control
+This package provides dbus api for unit control
+
%description -n event-processing-dbus
This package provides a listener for dbus events
%install_module vconf_listener vconf
%install_module dbus_signal_event dbus
%install_module dbus_listener dbus
+%install_module unit_control_api unit-control
+%install_module unit_control_event unit-control
+%install_module unit_control_dm unit-control
%install_module activation_dm activation-dm
%files
%files -n event-processing-dbus -f dbus-files
%{_prefix}/lib/actd/modules.conf.d/dbus_listener.conf.d/50-default.conf
+%files -n event-processing-unit-control -f unit-control-files
+%license COPYING
+%{_sysconfdir}/dbus-1/system.d/org.tizen.Activationd.conf
+%{_prefix}/lib/actd/modules.conf.d/unit_control_eh.conf.d/unit_control_eh.conf
+
%files -n activationd-test-services
%license COPYING
%manifest %{name}.manifest
--- /dev/null
+/*
+ * This file is part of unit_controld.
+ *
+ * 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 "unit_control_event.h"
+
+#define MODULE_NAME "unit_control_decision_maker"
+
+struct unit_control_decision_maker {
+ struct epc_event_handler eh;
+ struct list_head whitelist;
+};
+
+struct whitelist_entry {
+ char *unit;
+ struct list_head node;
+};
+
+static int unit_control_event_match(struct epc_event_handler *handler,
+ struct epc_event *ev)
+{
+ if (strcmp(ev->type->name, UC_EVENT_ID) == 0)
+ return 1;
+ return 0;
+}
+
+static int unit_control_execute(const char *unit, const char *command, struct epc_event *ev)
+{
+ struct dm_event_data ev_data = {
+ .reason = ev,
+ .who_made = MODULE_NAME,
+ };
+ struct epc_event *new_ev;
+ int ret;
+
+ assert(unit);
+ assert(command);
+ assert(ev);
+
+ 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, unit);
+ if (ret) {
+ log_error("Unable to create event data");
+ goto out;
+ }
+
+ if (!strcmp(command, "start"))
+ epc_fill_for_unit_action(ev_data.action_data, "StartUnit");
+ else if (!strcmp(command, "stop"))
+ epc_fill_for_unit_action(ev_data.action_data, "StopUnit");
+ else if (!strcmp(command, "restart"))
+ epc_fill_for_unit_action(ev_data.action_data, "RestartUnit");
+ else {
+ ret = -EINVAL;
+ log_error("Could not dispatch action: %s", command);
+ goto out;
+ }
+
+ 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 match_unit(const char *unit_name, const char *unit_whitelist_rule)
+{
+ if (!strcmp(unit_name, unit_whitelist_rule))
+ return 1;
+ return 0;
+}
+
+static int unit_control_make_decision(struct epc_event_handler *handler)
+{
+ struct epc_event *event = pop_epc_event(&handler->event_queue);
+ struct unit_control_decision_maker *dm = container_of(handler,
+ struct unit_control_decision_maker, eh);
+ struct unit_control_event *ev = to_unit_control_event(event);
+ int ret;
+ struct whitelist_entry *w;
+
+ list_for_each_entry(w, &dm->whitelist, node) {
+ if (!match_unit(ev->unit, w->unit))
+ continue;
+
+ ret = unit_control_execute(ev->unit, ev->method, event);
+ if (ret < 0)
+ break;
+ }
+
+ epc_object_unref(event);
+ return 0;
+}
+
+static void cleanup_whitelist_entry(struct whitelist_entry *w)
+{
+ free(w->unit);
+ free(w);
+}
+
+static void cleanup_whitelist(struct unit_control_decision_maker *dm)
+{
+ struct whitelist_entry *w, *next;
+
+ list_for_each_entry_safe(w, next, &dm->whitelist, node) {
+ list_del_init(&w->node);
+ cleanup_whitelist_entry(w);
+ }
+}
+
+static int add_whitelist_entry(struct unit_control_decision_maker *dm, const char *unit)
+{
+ struct whitelist_entry *w;
+
+ w = calloc(1, sizeof(*w));
+ if (!w) {
+ log_error("Could not allocate whitelist entry object");
+ return -ENOMEM;
+ }
+
+ log_debug("Adding whitelist etry for unit %s", unit);
+
+ w->unit = strdup(unit);
+ list_add_tail(&w->node, &dm->whitelist);
+ return 0;
+}
+
+static int unit_control_init(struct epc_event_handler *handler, struct epc_config *config)
+{
+ struct unit_control_decision_maker *dm = container_of(handler,
+ struct unit_control_decision_maker, eh);
+ int len;
+ int i;
+ int ret;
+ json_object *array, *obj;
+
+ INIT_LIST_HEAD(&dm->whitelist);
+
+ if (config == NULL)
+ return 0;
+
+ if (!json_object_object_get_ex(config->root, "whitelist", &array)) {
+ log_error("There is no 'whitelist' 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_whitelist_entry(dm, json_object_get_string(obj));
+ if (ret < 0) {
+ log_error("Could not add whitelist entry");
+ goto cleanup;
+ }
+ }
+
+ return 0;
+
+cleanup:
+ cleanup_whitelist(dm);
+ return ret;
+};
+
+static void unit_control_cleanup(struct epc_event_handler *handler)
+{
+ struct unit_control_decision_maker *dm = container_of(handler,
+ struct unit_control_decision_maker, eh);
+
+ cleanup_whitelist(dm);
+}
+
+static struct unit_control_decision_maker unit_control_dm = {
+ .eh = {
+ .name = MODULE_NAME,
+ .init = unit_control_init,
+ .cleanup = unit_control_cleanup,
+ .event_match = unit_control_event_match,
+ .handle_event = unit_control_make_decision,
+ .node = LIST_HEAD_INIT(unit_control_dm.eh.node),
+ },
+};
+
+EPC_EVENT_HANDLER_REGISTER(unit_control_dm.eh, unit_control_eh,
+ EPC_MODULE_TYPE_DECISION_MAKER)
--- /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 "unit_control_event.h"
+
+static int allocate_uc_event(struct epc_event_type *type,
+ void *data, struct epc_event **ev)
+{
+ struct unit_control_event *uc_ev;
+ struct unit_control_event_data *uc_ev_data = data;
+ int ret;
+
+ uc_ev = calloc(1, sizeof(*uc_ev));
+ if (!uc_ev)
+ return -ENOMEM;
+
+ ret = epc_event_init_internal(type, &uc_ev->event);
+ if (ret)
+ goto cleanup;
+
+ uc_ev->event_time = uc_ev_data->event_time;
+ uc_ev->method = uc_ev_data->method;
+ uc_ev->unit = uc_ev_data->unit;
+
+ *ev = &uc_ev->event;
+ return 0;
+cleanup:
+ free(uc_ev);
+
+ return ret;
+}
+
+static int deserialize_uc_event(struct epc_event_type *type,
+ struct epc_object *data, struct epc_event **ev)
+{
+ int ret = -EINVAL;
+ struct unit_control_event_data uc_ev_data;
+ struct epc_object *obj;
+ memset(&uc_ev_data, 0, sizeof(uc_ev_data));
+
+ list_for_each_entry(obj, &data->val.children, node) {
+ switch (obj->type) {
+ case TYPE_TIME_T:
+ if (!strcmp(UC_TIME, obj->key))
+ uc_ev_data.event_time = obj->val.time;
+ break;
+ case TYPE_STRING:
+ if (!strcmp(UC_METHOD, obj->key)) {
+ uc_ev_data.method = obj->val.s;
+ } else if (!strcmp(UC_UNIT, obj->key)) {
+ uc_ev_data.unit = obj->val.s;
+ }
+ break;
+ }
+ }
+
+ ret = allocate_uc_event(type, &uc_ev_data, ev);
+ if (ret < 0)
+ goto finish;
+
+ ret = epc_event_deserialize_internal(data, type, *ev);
+ if (ret < 0) {
+ struct unit_control_event *uc_ev =
+ to_unit_control_event(*ev);
+ free(uc_ev);
+ goto finish;
+ }
+ ret = 0;
+finish:
+ return ret;
+}
+
+static void uc_event_release(struct epc_event *ev)
+{
+ struct unit_control_event *uc_ev =
+ to_unit_control_event(ev);
+
+ if (uc_ev->method)
+ free(uc_ev->method);
+ if (uc_ev->unit)
+ free(uc_ev->unit);
+
+ epc_event_cleanup_internal(&uc_ev->event);
+ free(uc_ev);
+}
+
+static void uc_event_serialize(struct epc_event *ev, struct epc_object *out)
+{
+ struct unit_control_event *uc_ev =
+ to_unit_control_event(ev);
+ epc_event_serialize_internal(ev, out);
+ epc_object_append_string(out, UC_METHOD, uc_ev->method);
+ epc_object_append_time_t(out, UC_TIME, uc_ev->event_time);
+}
+
+static struct epc_event_type unit_control_event_type = {
+ .name = UC_EVENT_ID,
+ .default_ops = {
+ .release = uc_event_release,
+ .serialize = uc_event_serialize,
+ },
+ .allocate_event = allocate_uc_event,
+ .deserialize_event = deserialize_uc_event,
+ .node = LIST_HEAD_INIT(unit_control_event_type.node),
+};
+
+EPC_EVENT_TYPE_REGISTER(unit_control_event_type, unit_control_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 "event_processor.h"
+#include "systemd_dbus.h"
+#include "unit_control_event.h"
+
+#define ACTD_DBUS_API_INTERFACE_NAME "org.tizen.Activationd"
+#define ACTD_DBUS_API_SERVICE_NAME "org.tizen.Activationd"
+#define ACTD_DBUS_API_OBJECT_PATH "/org/tizen/activationd"
+
+static int method_generic_callback(sd_bus_message *m, void *userdata, sd_bus_error *ret_error, const char *method)
+{
+ _cleanup_(sd_bus_error_free) sd_bus_error error_buf = SD_BUS_ERROR_NULL;
+ int r;
+ const char *s;
+ struct unit_control_event_data uc_ev_data = {};
+ struct epc_event *ev;
+ struct timespec ts;
+
+ if (!ret_error)
+ ret_error = &error_buf;
+
+ if (strcmp(method, "start") &&
+ strcmp(method, "stop") &&
+ strcmp(method, "restart")) {
+ r = -EINVAL;
+ goto fail;
+ }
+
+ /* Read the parameters */
+ r = sd_bus_message_read(m, "s", &s);
+ if (r < 0) {
+ fprintf(stderr, "Failed to parse parameters: %s\n", strerror(-r));
+ goto fail;
+ }
+
+ if (clock_gettime(CLOCK_MONOTONIC, &ts) < 0) {
+ log_error_errno(errno, "Unable to get timestamp : %m");
+ r = -errno;
+ goto fail;
+ }
+
+ uc_ev_data.event_time = ts.tv_sec;
+
+ uc_ev_data.unit = strdup(s);
+ if (uc_ev_data.unit == NULL) {
+ r = -ENOMEM;
+ goto fail;
+ }
+
+ uc_ev_data.method = strdup(method);
+ if (uc_ev_data.method == NULL) {
+ r = -ENOMEM;
+ goto fail;
+ }
+
+ r = epc_event_create(UC_EVENT_ID, &uc_ev_data, &ev);
+ if (r) {
+ log_error_errno(r, "Unable to allocate an event: %m.");
+ r = -errno;
+ goto fail;
+ }
+
+ r = event_processor_report_event(ev);
+ epc_event_unref(ev);
+ if (r) {
+ log_error_errno(r, "Unable to report event: %m");
+ r = -EINVAL;
+ goto fail;
+ }
+
+ return sd_bus_reply_method_return(m, "s", "ok");
+fail:
+ free(uc_ev_data.method);
+ free(uc_ev_data.unit);
+ return sd_bus_error_set_errno(ret_error, -r);
+}
+
+static int method_start(sd_bus_message *m, void *userdata, sd_bus_error *ret_error)
+{
+ return method_generic_callback(m, userdata, ret_error, "start");
+}
+
+static int method_stop(sd_bus_message *m, void *userdata, sd_bus_error *ret_error)
+{
+ return method_generic_callback(m, userdata, ret_error, "stop");
+}
+
+static int method_restart(sd_bus_message *m, void *userdata, sd_bus_error *ret_error)
+{
+ return method_generic_callback(m, userdata, ret_error, "restart");
+}
+
+static const sd_bus_vtable unit_control_api_vtable[] = {
+ SD_BUS_VTABLE_START(0),
+ SD_BUS_METHOD("Start", "s", "s", method_start, SD_BUS_VTABLE_UNPRIVILEGED),
+ SD_BUS_METHOD("Stop", "s", "s", method_stop, SD_BUS_VTABLE_UNPRIVILEGED),
+ SD_BUS_METHOD("Restart", "s", "s", method_restart, SD_BUS_VTABLE_UNPRIVILEGED),
+ SD_BUS_VTABLE_END
+};
+
+
+struct unit_control_api {
+ struct epc_module module;
+ sd_bus *bus;
+};
+
+#define to_unit_control_api(MOD) \
+ container_of(MOD, struct unit_control_api, module)
+
+static void cleanup_listener(struct unit_control_api *l)
+{
+ if (l->bus)
+ sd_bus_release_name(l->bus, ACTD_DBUS_API_INTERFACE_NAME);
+}
+
+static int unit_control_api_init(struct epc_module *module,
+ struct epc_config *config,
+ sd_event* loop)
+{
+ struct unit_control_api *listener = to_unit_control_api(module);
+ int ret = 0;
+ sd_bus_slot *slot = NULL;
+
+ listener->bus = NULL;
+
+ ret = epc_acquire_systemd_bus(&listener->bus);
+ if (ret < 0) {
+ log_error_errno(ret, "Failed to acquire the default system bus connection: %m");
+ return -EINVAL;
+ }
+
+ ret = sd_bus_add_object_vtable(listener->bus,
+ &slot,
+ ACTD_DBUS_API_OBJECT_PATH,
+ ACTD_DBUS_API_INTERFACE_NAME,
+ unit_control_api_vtable,
+ listener);
+
+ if (ret < 0) {
+ fprintf(stderr, "Failed to register api calls: %s\n", strerror(-ret));
+ goto cleanup;
+ }
+
+ /* Take a well-known service name so that clients can find us */
+ ret = sd_bus_request_name(listener->bus, ACTD_DBUS_API_SERVICE_NAME, 0);
+ if (ret < 0) {
+ fprintf(stderr, "Failed to acquire service name: %s\n", strerror(-ret));
+ goto cleanup;
+ }
+ return 0;
+
+cleanup:
+ cleanup_listener(listener);
+ return ret;
+}
+
+static void unit_control_api_cleanup(struct epc_module *module)
+{
+ struct unit_control_api *listener = to_unit_control_api(module);
+ cleanup_listener(listener);
+}
+
+struct unit_control_api unit_control_api = {
+ .module = {
+ .name = "unit_control_api",
+ .type = EPC_MODULE_TYPE_LISTENER,
+
+ .init = unit_control_api_init,
+ .cleanup = unit_control_api_cleanup,
+ .node = LIST_HEAD_INIT(unit_control_api.module.node),
+ },
+};
+
+EPC_MODULE_REGISTER(&unit_control_api.module)