--- /dev/null
+/*
+ * This file is part of faultd.
+ *
+ * Copyright © 2017 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.
+ */
+
+#define _GNU_SOURCE 1
+
+#include <poll.h>
+#include <stdio.h>
+#include <systemd/sd-bus.h>
+#include <systemd/sd-event.h>
+
+#include "event_processor.h"
+#include "log.h"
+#include "module.h"
+#include "service_failed_event.h"
+
+struct systemd_listener {
+ struct faultd_module module;
+ /* Put your data here */
+};
+
+#define to_systemd_listener(MOD) \
+ container_of(MOD, struct systemd_listener, module)
+
+static int on_unit_properties_changed(sd_bus_message *m, void *userdata,
+ sd_bus_error *ret_error)
+{
+ int rc = 1;
+ const char *interface;
+ /* const char* path; */
+ /* path = NULL; */
+ uint8_t type;
+ struct sf_event_data sf_ev_data = {};
+ struct faultd_event *ev;
+
+ rc = sd_bus_message_read(m, "s", &interface);
+ if (rc < 0) {
+ log_error_errno(rc, "Invalid message format.");
+ goto finish;
+ }
+ if (strcmp("org.freedesktop.systemd1.Unit", interface) != 0) {
+ rc = 0;
+ goto finish;
+ }
+
+ rc = sd_bus_message_get_type(m, &type);
+ if (rc < 0) {
+ log_error_errno(rc, "Failed to get message type.");
+ goto finish;
+ }
+
+ log_debug("Received a message!");
+ log_debug(" Type: %s",
+ type == SD_BUS_MESSAGE_METHOD_CALL ? "method call" :
+ (type == SD_BUS_MESSAGE_METHOD_RETURN ? "method return" :
+ (type == SD_BUS_MESSAGE_METHOD_ERROR ? "method error" :
+ (type == SD_BUS_MESSAGE_SIGNAL ? "signal" : "INVALID"))));
+ log_debug(" Interface: %s", sd_bus_message_get_interface(m));
+ log_debug(" Member: %s", sd_bus_message_get_member(m));
+ log_debug(" Path: %s", sd_bus_message_get_path(m));
+ log_debug(" Message If: %s", interface);
+
+ rc = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "{sv}");
+ if (rc < 0) {
+ rc = 0;
+ }
+ log_debug(" Message dictionary:");
+ while ((rc = sd_bus_message_enter_container(m, SD_BUS_TYPE_DICT_ENTRY, "sv")) > 0) {
+ const char *key;
+
+ rc = sd_bus_message_read(m, "s", &key);
+ if (rc < 0) {
+ log_error_errno(rc, "Failed to read a DICT_ENTRY: %m.");
+ rc = 0;
+ goto finish;
+ }
+
+ if (strcmp("ActiveState", key) == 0) {
+ const char *value;
+
+ rc = sd_bus_message_enter_container(m, SD_BUS_TYPE_VARIANT, "s");
+ if (rc < 0) {
+ /* XXX */
+ rc = 0;
+ goto finish;
+ }
+ rc = sd_bus_message_read(m, "s", &value);
+ if (rc < 0) {
+ log_error_errno(rc, "Failed to read the AciveSate value: %m.");
+ goto finish;
+ }
+ rc = sd_bus_message_exit_container(m);
+ log_debug(" %s:%s", key, value);
+ if (strcmp("failed", value) == 0) {
+ ; /* XXX */
+ }
+
+ } else if (strncmp("ConditionTimestamp", key, 18) == 0) {
+ uint64_t value;
+
+ /* TODO: Fill detection_time properly */
+
+ rc = sd_bus_message_enter_container(m, SD_BUS_TYPE_VARIANT, "t");
+ if (rc < 0) {
+ log_debug("failedenering ConditionTimestamp variant");
+ /* XXX */
+ rc = 0;
+ goto finish;
+ }
+ rc = sd_bus_message_read(m, "t", &value);
+ if (rc < 0) {
+ log_error_errno(rc, "Failed to read the ConditionTimestamp value: %m.");
+ goto finish;
+ }
+ rc = sd_bus_message_exit_container(m);
+ log_debug(" %s:%ld", key, value);
+
+ } else {
+ log_debug(" %s", key);
+ rc = sd_bus_message_skip(m, "v");
+ if (rc < 0) {
+ fprintf(stderr, "Failed to skip a value.");
+ rc = 0;
+ goto finish;
+ }
+ }
+
+ rc = sd_bus_message_exit_container(m);
+ if (rc < 0) {
+ log_error_errno(rc, "Failed to exit a container: %m.");
+ rc = 0;
+ goto finish;
+ }
+ }
+
+ rc = sd_bus_message_exit_container(m);
+ if (rc < 0) {
+ rc = 0;
+ }
+
+ systemd_service_init(sd_bus_message_get_path(m), &sf_ev_data.service);
+
+ rc = faultd_event_create(SERVICE_FAILED_EVENT_ID, &sf_ev_data, &ev);
+ if (rc) {
+ log_error_errno(rc, "Unable to allocate an event: %m.");
+ systemd_service_cleanup(&sf_ev_data.service);
+ goto finish;
+ }
+
+ rc = event_processor_report_event(ev);
+ if (rc) {
+ log_error_errno(rc, "Unable to report event: %m");
+ faultd_event_unref(ev);
+ }
+finish:
+ return rc;
+}
+
+static int systemd_listener_init(struct faultd_module *module, sd_event* loop)
+{
+ sd_bus_error error = SD_BUS_ERROR_NULL;
+ sd_bus *bus = NULL;
+ int rc;
+
+ rc = sd_bus_default_system(&bus);
+ if (rc < 0) {
+ log_error_errno(rc, "Failed to acquire the defult system bus connection.");
+ return -1;
+ }
+
+ rc = sd_bus_attach_event(bus, loop, SD_EVENT_PRIORITY_NORMAL);
+ if (rc < 0) {
+ log_error_errno(rc, "Failed to attach the bus to the event loop.");
+ return -1;
+ }
+
+ rc = sd_bus_add_match(bus,
+ NULL,
+ "type='signal',sender='org.freedesktop.systemd1',"
+ "interface='org.freedesktop.DBus.Properties',"
+ "member='PropertiesChanged',"
+ "path_namespace='/org/freedesktop/systemd1/unit'",
+ on_unit_properties_changed,
+ NULL);
+ if (rc < 0) {
+ log_error_errno(rc, "Failed to add match.");
+ return -1;
+ }
+
+ rc = sd_bus_call_method(bus,
+ "org.freedesktop.systemd1",
+ "/org/freedesktop/systemd1",
+ "org.freedesktop.systemd1.Manager",
+ "Subscribe",
+ &error,
+ NULL, NULL);
+ if (rc < 0) {
+ log_error_errno(rc, "Failed to subscribe.");
+ return -1;
+ }
+
+ return 0;
+}
+
+static void systemd_listener_cleanup(struct faultd_module *module)
+{
+ /* Nothing to do here at the moment. Anyway, don't use D-Bus here,
+ it's been closed already. */
+ ;
+}
+
+struct systemd_listener systemd_listener = {
+ .module = {
+ .name = "systemd_listener",
+ .type = FAULTD_MODULE_TYPE_LISTENER,
+
+ .init = systemd_listener_init,
+ .cleanup = systemd_listener_cleanup,
+ .node = LIST_HEAD_INIT(systemd_listener.module.node),
+ },
+};
+
+FAULTD_MODULE_REGISTER(&systemd_listener.module)