sbin_PROGRAMS = faultd
faultd_SOURCES = \
- src/audit.c \
src/faultd.c \
src/log.c \
- src/systemd.c \
+ src/util.c
+ src/core/module.c \
+ src/core/notify_queue.c \
+ src/listeners/systemd.c \
+ src/listeners/audit.c \
+ src/event.c \
+ src/service.c \
+ src/event_types/decision_made_event.c \
+ src/event_types/resource_violation_event.c \
+ src/decision_makers/rv_dm.c \
+ src/event_processor.c
faultd_LDADD = $(LIBSYSTEMD_LIBS) ${AUDIT_LIBS}
--- /dev/null
-
+ /*
+ * 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.
+ */
+
+ #include <errno.h>
+
+ #include "module.h"
+ #include "log.h"
+ #include "common.h"
+
+ static struct list_head modules[FAULTD_MODULE_TYPE_MAX];
+
+ static void init_heads(void)
+ {
+ unsigned i;
+
+ for (i = 0; i < ARRAY_SIZE(modules); ++i)
+ INIT_LIST_HEAD(modules + i);
+ }
+
+ int faultd_module_register(struct faultd_module *module)
+ {
+ if (!module->name || !module->init) {
+ log_error("Missing module name or init()");
+ return -EINVAL;
+ }
-
++
+ if (!modules[0].next)
+ init_heads();
+
+ list_add_tail(&module->node, modules + module->type);
+
+ return 0;
+ }
+
+ void faultd_module_unregister(struct faultd_module *module)
+ {
+ list_del(&module->node);
+ }
+
+ int faultd_modules_init(sd_event *event_loop)
+ {
+ struct faultd_module *module, *module_to_clean;
+ int i;
+ int ret = 0;
+
+ if (!modules[0].next)
+ init_heads();
+
+ for (i = 0; i < (int)(ARRAY_SIZE(modules)); ++i) {
+ log_debug("Initializing modules category %d", i);
+ list_for_each_entry(module, modules + i, node) {
+ log_debug("Initializing %s module", module->name);
-
++
+ ret = module->init(module, event_loop);
+ if (ret)
+ goto err_cleanup;
+ }
+ }
+
+ return 0;
+
+ err_cleanup:
+ for (; i >= 0; --i) {
+ log_debug("Cleaning up modules category %d", i);
+ /* From first element of the list... */
+ for (module_to_clean = list_first_entry(modules + i,
+ struct faultd_module,
+ node);
+ /* iterate as long as modules has been initialized */
+ module_to_clean != module &&
+ &module_to_clean->node != (modules + i);
+ /* move to next one */
+ module_to_clean = list_next_entry(module_to_clean, node)) {
+ log_debug("Cleaning up %s module",
+ module_to_clean->name);
+ module_to_clean->cleanup(module_to_clean);
+ }
+ }
-
++
+ return ret;
+ }
+
+ void faultd_modules_cleanup()
+ {
+ struct faultd_module *module;
+ int i;
+
+ for (i = FAULTD_MODULE_TYPE_MAX - 1; i >= 0; --i) {
+ log_debug("Cleaning up modules category %d", i);
+ list_for_each_entry(module, modules + i, node) {
+ log_debug("Cleaning up %s module", module->name);
- }
++
+ module->cleanup(module);
++ }
+ }
+ }
--- /dev/null
-
+ /*
+ * 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.
+ */
+
+ #ifndef FAULTD_EVENT_H
+ #define FAULTD_EVENT_H
+
+ #include <time.h>
+ #include <string.h>
+
+ #include "uref.h"
+ #include "list.h"
+ #include "notify_queue.h"
+ #include "module.h"
+
+ struct faultd_event;
+
+ struct faultd_event_ops {
+ char *(*to_string)(struct faultd_event *);
+ void (*release)(struct faultd_event *);
+ };
+
+ struct faultd_event_type {
+ char *name;
+
+ struct faultd_event_ops default_ops;
+
+ /* Add function to allocate event from DB */
+
+ /* Allocate event based on passed data */
+ int (*allocate_event)(struct faultd_event_type *type,
+ void *data, struct faultd_event **);
+
+ /* To be used by event factory */
+ struct list_head node;
+ };
+
+ struct faultd_event {
+ struct timespec timestamp;
+
+ /* TODO: add here some id field */
+ struct faultd_event_type *type;
+ struct faultd_event_ops ops;
+
+ struct uref uref;
+ /* To be used by event holder */
+ struct list_head node;
+ /* To be used by event processig FW */
+ struct nqueue_node nq_node;
+ };
+
+ int faultd_event_type_register(struct faultd_event_type *type);
+ void faultd_event_type_unregister(struct faultd_event_type *type);
+
+ #define FAULTD_EVENT_TYPE_REGISTER(EVENT_TYPE, NAME) \
+ static int event_type_ ##NAME## _init(struct faultd_module *module, \
+ sd_event *event_loop) \
+ { \
+ return faultd_event_type_register(&EVENT_TYPE); \
+ } \
+ \
+ static void event_type_ ##NAME## _cleanup(struct faultd_module *module) \
+ { \
+ faultd_event_type_unregister(&EVENT_TYPE); \
+ } \
+ \
+ static struct faultd_module event_type_ ##NAME## _module = { \
+ .name = #NAME, \
+ .type = FAULTD_MODULE_TYPE_EVENT, \
+ .init = event_type_ ##NAME## _init, \
+ .cleanup = event_type_ ##NAME## _cleanup, \
+ .node = LIST_HEAD_INIT(event_type_ ##NAME## _module.node), \
+ }; \
+ \
+ FAULTD_MODULE_REGISTER(&event_type_ ##NAME## _module)
+
+ int faultd_event_create(const char *type, void *data, struct faultd_event **ev);
+
+ static inline void faultd_event_get(struct faultd_event *ev)
+ {
+ uref_get(&ev->uref);
+ }
+
+ static inline void faultd_event_put(struct faultd_event *ev)
+ {
+ uref_put(&ev->uref);
+ }
+
+ static inline int faultd_event_is_of_type(struct faultd_event *ev,
+ const char *type)
+ {
+ return strcmp(ev->type->name, type) == 0;
+ }
+
+ static inline char *faultd_event_to_string(struct faultd_event *ev)
+ {
+ return ev->ops.to_string(ev);
+ }
+
+ int faultd_event_init(struct faultd_event_type *ev_type,
+ struct faultd_event *ev);
+
+ static inline void faultd_event_cleanup(struct faultd_event *ev) {}
+
+ #endif /* FAULTD_EVENT_H */
--- /dev/null
-
+ /*
+ * 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.
+ */
+
+ #include <errno.h>
+
+ #include "event_processor.h"
+ #include "log.h"
+
+ struct event_processor {
+ struct faultd_module module;
+ struct nqueue_head pending_events;
+ struct sd_event_source *pending_events_sd_source;
+ struct list_head event_handlers;
+ sd_event *loop;
+ };
+
+ #define to_event_processor(MOD) \
+ container_of(MOD, struct event_processor, module)
+
+ /* called each time when new event arrived */
+ static int event_processor_callback(sd_event_source *s,
+ int fd, uint32_t revents, void *userdata)
+ {
+ struct event_processor *eprocessor = userdata;
+ struct faultd_event *ev = nqueue_pop(&eprocessor->pending_events,
+ struct faultd_event, nq_node);
+ struct faultd_event_handler *handler;
+
+ /* TODO: Here is a good place to put our event into DB */
+ {
+ char *str = faultd_event_to_string(ev);
+ log_debug("New event arrived: %s", str);
+ free(str);
+ }
+
+ list_for_each_entry(handler, &eprocessor->event_handlers, node) {
+ if (handler->event_match(handler, ev)) {
+ nqueue_append(&handler->event_queue, &ev->nq_node);
+ ev = NULL;
+ }
+ }
+
+ if (ev) {
+ log_error("No handler for event found");
+ faultd_event_put(ev);
+ }
-
++
+ return 0;
+ }
+
+ static int event_processor_init(struct faultd_module *module, sd_event *event)
+ {
+ struct event_processor *eprocessor = to_event_processor(module);
+ int ret;
+
+ ret = init_notify_queue_head(&eprocessor->pending_events);
+ if (ret)
+ return ret;
+
+ ret = sd_event_add_io(event, &eprocessor->pending_events_sd_source,
+ eprocessor->pending_events.fd, EPOLLIN,
+ event_processor_callback, eprocessor);
+ if (ret)
+ goto cleanup_queue;
+
+ eprocessor->loop = event;
+ return 0;
+
+ cleanup_queue:
+ cleanup_notify_queue_head(&eprocessor->pending_events);
+
+ return ret;
+ }
+
+ static void event_processor_cleanup(struct faultd_module *module)
+ {
+ struct event_processor *eprocessor = to_event_processor(module);
+ int ret;
+
+ /* We log errors but go forward to cleanup everything we can */
+ ret = sd_event_source_set_enabled(eprocessor->pending_events_sd_source,
+ SD_EVENT_OFF);
+ if (ret < 0)
+ log_error("Could not disable queue event source %d", ret);
+
+ sd_event_source_unref(eprocessor->pending_events_sd_source);
+
+ /* TODO: What to do with unhandled events? */
+ while (!nqueue_empty(&eprocessor->pending_events)) {
+ struct faultd_event *ev = nqueue_pop(&eprocessor->pending_events,
+ struct faultd_event,
+ nq_node);
+ char *str = faultd_event_to_string(ev);
+ log_error("Unhandled event: %s", str);
+ free(str);
+ faultd_event_put(ev);
+ }
+ }
+
+ struct event_processor event_processor = {
+ .module = {
+ .name = "event_processor",
+ .type = FAULTD_MODULE_TYPE_CORE,
+
+ .init = event_processor_init,
+ .cleanup = event_processor_cleanup,
+ .node = LIST_HEAD_INIT(event_processor.module.node),
+ },
+ /* pending_events will be initialized in init() */
+ .event_handlers = LIST_HEAD_INIT(event_processor.event_handlers),
+ };
+
+ FAULTD_MODULE_REGISTER(&event_processor.module);
+
+ int event_processor_report_event(struct faultd_event *ev)
+ {
+ return nqueue_append(&event_processor.pending_events,
+ &ev->nq_node);
+ }
+
+ static int event_processor_handler_callback(sd_event_source *s, int fd,
+ uint32_t revents, void *userdata)
+ {
+ struct faultd_event_handler *handler = userdata;
+
+ return handler->handle_event(handler);
+ }
+
+ int event_processor_handler_register(struct faultd_event_handler *handler)
+ {
+ int ret;
+
+ if (!handler->event_match || handler->handle_event)
+ return -EINVAL;
+
+ ret = init_notify_queue_head(&handler->event_queue);
+ if (ret)
+ return ret;
+
+ ret = sd_event_add_io(event_processor.loop,
+ &handler->event_queue_sd_source,
+ handler->event_queue.fd, EPOLLIN,
+ event_processor_handler_callback, handler);
+ if (ret)
+ goto cleanup_queue;
+
+ list_add_tail(&handler->node, &event_processor.event_handlers);
++
+ return 0;
+
+ cleanup_queue:
+ cleanup_notify_queue_head(&handler->event_queue);
+
+ return ret;
+ }
+
+ void event_processor_handler_unregister(struct faultd_event_handler *handler)
+ {
+ int ret;
+
+ /* We log errors but go forward to cleanup everything we can */
+ ret = sd_event_source_set_enabled(handler->event_queue_sd_source,
+ SD_EVENT_OFF);
+ if (ret < 0)
+ log_error("Could not disable queue event source %d", ret);
+
+ sd_event_source_unref(handler->event_queue_sd_source);
+
+ /* TODO: What to do with unhandled events? */
+ while (!nqueue_empty(&handler->event_queue)) {
+ struct faultd_event *ev = nqueue_pop(&event_processor.pending_events,
+ struct faultd_event,
+ nq_node);
+ char *str = faultd_event_to_string(ev);
+
+ log_error("Unhandled event: %s", str);
+ free(str);
+ faultd_event_put(ev);
+ }
+
+ list_del(&handler->node);
+ }
--- /dev/null
- void (*action_data_release)(void *);
+ /*
+ * 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.
+ */
+
+ #ifndef FAULTD_DECISION_MADE_EVENT_H
+ #define FAULTD_DECISION_MADE_EVENT_H
+
+ #include <time.h>
+
+ #include "action.h"
+ #include "event.h"
+ #include "common.h"
+
+ #define DECISION_MADE_EVENT_ID "decision_made"
+
+ struct decision_made_event {
+ struct faultd_event event;
+ struct faultd_event *reason;
+ char *who_made;
+ char *action;
+ void *action_data;
+ void (*action_data_release)(void *);
+ /* TODO: what more do we need? */
+ };
+
+ struct dm_event_data {
+ /* This is referenced by dm event */
+ struct faultd_event *reason;
+ /* Strings are deep copied */
+ char *who_made;
+ char *action;
+ /* Action data is shallow copied */
+ void *action_data;
-
++ void (*action_data_release)(void *);
+ };
++
+ #define to_decision_made_event(EVENT) \
+ container_of(EVENT, struct decision_made_event, event)
+
+ #endif /* FAULTD_DECISION_MADE_EVENT_H */
--- /dev/null
-
+ /*
+ * 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 <stdio.h>
+ #include <errno.h>
+ #include <malloc.h>
+
+ #include "resource_violation_event.h"
+
+ static int allocate_rv_event(struct faultd_event_type *type,
+ void *data, struct faultd_event **ev)
+ {
+ struct resource_violation_event *rv_ev;
+ struct rv_event_data *rv_ev_data = data;
+ int ret;
+
+ rv_ev = malloc(sizeof(*rv_ev));
+ if (!rv_ev)
+ return -ENOMEM;
+
+ ret = faultd_event_init(type, &rv_ev->event);
+ if (ret)
+ goto free_rv_ev;
+
+ rv_ev->service = rv_ev_data->service;
+ rv_ev->detection_time = rv_ev_data->detection_time;
+ rv_ev->resource_type = rv_ev_data->resource_type;
+
+ return 0;
+ free_rv_ev:
+ free(rv_ev);
+
+ return ret;
+ }
+
+ static void rv_event_release(struct faultd_event *ev)
+ {
+ struct resource_violation_event *rv_ev =
+ to_resource_violation_event(ev);
+
+ system_service_cleanup(&rv_ev->service);
+ faultd_event_cleanup(&rv_ev->event);
+ free(rv_ev);
+ }
+
+ static char *rv_event_to_string(struct faultd_event *ev)
+ {
+ struct resource_violation_event *rv_ev =
+ to_resource_violation_event(ev);
+ char *str;
+ int ret;
+
+ /* TODO print other fields */
+ ret = asprintf(&str, "Resource Violation Event:"
+ " Time: %lld.%.9ld"
+ " Service: pid: %d, name %s"
+ " Resource type: %d",
+ (long long)rv_ev->event.timestamp.tv_sec,
+ rv_ev->event.timestamp.tv_nsec,
+ rv_ev->service.pid,
+ rv_ev->service.name,
+ rv_ev->resource_type);
+
+ return ret > 0 ? str : NULL;
+ }
+
+ static struct faultd_event_type resource_violation_event_type = {
+ .name = RESOURCE_VIOLATION_EVENT_ID,
+ .default_ops = {
+ .to_string = rv_event_to_string,
+ .release = rv_event_release,
+ },
+ .allocate_event = allocate_rv_event,
+ .node = LIST_HEAD_INIT(resource_violation_event_type.node),
+ };
+
+ FAULTD_EVENT_TYPE_REGISTER(resource_violation_event_type, resource_violation_et)
--- /dev/null
-
+ /*
+ * 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.
+ */
+
+ #ifndef FAULTD_RESOURCE_VIOLATION_EVENT_H
+ #define FAULTD_RESOURCE_VIOLATION_EVENT_H
+
+ #include <time.h>
+
+ #include "event.h"
+ #include "common.h"
+ #include "service.h"
+
+ #define RESOURCE_VIOLATION_EVENT_ID "resource_violation"
+
+ enum resource_type {
+ FAULTD_RESOURCE_FD,
+ FAULTD_RESOURCE_MEM
+ };
+
+ struct resource_violation_event {
+ struct faultd_event event;
+ struct system_service service;
+ time_t detection_time;
+ enum resource_type resource_type;
+ /* TODO: what more do we need? */
+ };
+
+ struct rv_event_data {
+ struct system_service service;
+ time_t detection_time;
+ enum resource_type resource_type;
+ };
++
+ #define to_resource_violation_event(EVENT) \
+ container_of(EVENT, struct resource_violation_event, event)
+
+ #endif /* FAULTD_RESOURCE_VIOLATION_EVENT_H */
--- /dev/null
-
+ /*
+ * This file is a 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 <errno.h>
+ #include <libaudit.h>
+ #include <stdio.h>
+ #include <stdlib.h>
+ #include <string.h>
+ #include <systemd/sd-event.h>
+ #include <unistd.h>
+
+ #include "log.h"
+ #include "module.h"
+ #include "event.h"
+ #include "event_processor.h"
+ #include "resource_violation_event.h"
+
+ struct audit_listener {
+ struct faultd_module module;
+ int audit_fd;
+ sd_event_source *event_source;
+ };
+
+ #define to_audit_listener(MOD) \
+ container_of(MOD, struct audit_listener, module)
+
+ static struct audit_rule_data rule_data = {
+ .flags = AUDIT_FILTER_EXIT, /* trigger on exit from syscall */
+ .action = AUDIT_ALWAYS, /* always catch matching syscall */
+ .field_count = 1,
+ .fields = {AUDIT_EXIT}, /* watch exit code */
+ .values = {-EMFILE},
+ .fieldflags = {AUDIT_EQUAL}, /* trigger if equal to value*/
+ };
+
+ static int audit_handler(sd_event_source *s, int fd, uint32_t revents, void *userdata);
+
+ enum {
+ KEY_PID,
+ KEY_UNKNOWN,
+ };
+
+ static int str2key(char *p, int len)
+ {
+ if (strncmp(p, "pid", len) == 0)
+ return KEY_PID;
+
+ return KEY_UNKNOWN;
+ }
+
+ static int parse_event(char *message, int len, struct rv_event_data *ev_data)
+ {
+ char *p = message;
+ char *e;
+ int key;
+
+ p = strchr(p, '(');
+ if (!p)
+ return -1;
+
+ ++p;
+ ev_data->detection_time = strtol(p, &p, 10);
+ ev_data->service.pid = 0;
+
+ while ((p = strchr(p, ' ')) != 0) {
+ ++p;
+ e = strchr(p, '=');
+ key = str2key(p, e - p);
+
+ p = e + 1;
+ e = strchrnul(p, ' ');
+
+ switch (key) {
+ case KEY_PID:
+ ev_data->service.pid = strtol(p, &p, 10);
+ break;
+ default:
+ break;
+ }
+ }
+
+ return 0;
+ }
+
+ static int audit_handler(sd_event_source *s, int fd, uint32_t revents, void *userdata)
+ {
+ struct audit_reply reply;
+ int ret;
+ struct rv_event_data rv_ev_data = {
+ .resource_type = FAULTD_RESOURCE_FD,
+ };
+ struct faultd_event *ev;
- /*
++
+ ret = audit_get_reply(fd, &reply, GET_REPLY_NONBLOCKING, 0);
+ if (ret < 0) {
+ log_error("Could not get reply.\n");
+ return ret;
+ }
+
+ if (reply.type != AUDIT_SYSCALL)
+ return 0;
+
+ reply.message[reply.len] = '\0';
+ ret = parse_event(reply.message, reply.len, &rv_ev_data);
+ if (ret < 0) {
+ log_error("Could not parse event\n");
+ return ret;
+ }
+
+ log_debug("Got audit event: timestamp = %ld, pid = %d",
+ rv_ev_data.detection_time, rv_ev_data.service.pid);
+
+ ret = system_service_init(rv_ev_data.service.pid, NULL,
+ &rv_ev_data.service);
+ if (ret) {
+ log_info("Got resource violation but not from service. Dropping.");
+ return 0;
+ }
+
+ ret = faultd_event_create(RESOURCE_VIOLATION_EVENT_ID, &rv_ev_data, &ev);
+ if (ret) {
+ log_error("Unable to allocate event");
+ goto cleanup_service;
+ }
+
+ ret = event_processor_report_event(ev);
+ if (ret) {
+ log_error("Unable to report event");
+ goto put_event;
+ }
+
+ return 0;
+
+ put_event:
+ faultd_event_put(ev);
+ return ret;
+
+ cleanup_service:
+ system_service_cleanup(&rv_ev_data.service);
+
+ return ret;
+ }
+
+ static int audit_listener_init(struct faultd_module *module, sd_event *event)
+ {
+ struct audit_listener *alistener = to_audit_listener(module);
+ int fd;
+ sd_event_source *event_source;
+ int ret;
+
+ fd = audit_open();
+ if (fd < 0) {
+ log_error("Could not open audit socket: %m\n");
+ return fd;
+ }
+
+ ret = audit_set_pid(fd, getpid(), WAIT_YES);
+ if (ret < 0) {
+ log_error("Could not set pid (%d)\n", ret);
+ goto close_audit;
+ }
+
++ /*
+ * TODO: Is this in a correct place?
+ * Shouldn't be after filter registration
+ */
+ ret = sd_event_add_io(event, &event_source,
+ fd, EPOLLIN, audit_handler, NULL);
+ if (ret < 0) {
+ log_error_errno(ret, "Could not add io event: %m");
+ goto unset_pid;
+ }
+
+ /* TODO: select only relevant syscalls */
+ audit_rule_syscallbyname_data(&rule_data, "all");
+
+ ret = audit_add_rule_data(fd, &rule_data, AUDIT_FILTER_EXIT, AUDIT_ALWAYS);
+ if (ret <= 0 && ret != -EEXIST) {
+ log_error("Could not add rule (%d).", ret);
+ goto remove_from_event_loop;
+ }
+
+ alistener->audit_fd = fd;
+ alistener->event_source = event_source;
+
+ return 0;
+
+ remove_from_event_loop:
+ sd_event_source_unref(event_source);
+ unset_pid:
+ audit_set_pid(fd, 0, WAIT_YES);
+ close_audit:
+ audit_close(fd);
+
+ return ret;
+ }
+
+ static void audit_listener_cleanup(struct faultd_module *module)
+ {
+ struct audit_listener *alistener = to_audit_listener(module);
+ int fd = alistener->audit_fd;
+ sd_event_source *event_source = alistener->event_source;
+ int ret;
+
+ /* We log errors but go forward to cleanup everything we can */
+ ret = sd_event_source_set_enabled(event_source, SD_EVENT_OFF);
+ if (ret < 0)
+ log_error("Could not disable audit event source %d", ret);
+
+ sd_event_source_unref(event_source);
+
+ ret = audit_delete_rule_data(fd, &rule_data, AUDIT_FILTER_EXIT, AUDIT_ALWAYS);
+ if (ret < 0 && ret != -EEXIST)
+ log_error("Could not add rule (%d)", ret);
+
+ ret = audit_set_pid(fd, 0, WAIT_YES);
+ if (ret < 0)
+ log_error("Could not set pid (%d)", ret);
+
+ audit_close(fd);
+ }
+
+ struct audit_listener audit_listener = {
+ .module = {
+ .name = "audit_listener",
+ .type = FAULTD_MODULE_TYPE_LISTENER,
+
+ .init = audit_listener_init,
+ .cleanup = audit_listener_cleanup,
+ .node = LIST_HEAD_INIT(audit_listener.module.node),
+ },
+ .audit_fd = -1,
+ };
+
+ FAULTD_MODULE_REGISTER(&audit_listener.module)
--- /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.
+ */
+
+ #include <stdio.h>
+ #include <poll.h>
+ #include <systemd/sd-bus.h>
+ #include <systemd/sd-event.h>
+
+ #include "log.h"
+ #include "module.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;
+
+ 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;
+ }
+
+ fprintf(stdout,"'");
+ fflush(stdout);
+ 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.");
+ rc = 0;
+ goto finish;
+ }
+ rc = sd_bus_message_exit_container(m);
+ log_debug(" %s:%s", 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: %s.", strerror(-rc));
+ rc = 0;
+ goto finish;
+ }
+ }
+
+ rc = sd_bus_message_exit_container(m);
+ if (rc < 0) {
+ rc = 0;
+ }
+ 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)
+ {
+ 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.");
+ /* We cannot do anything without bus.. */
+ return;
+ }
+
+ rc = sd_bus_call_method(bus,
+ "org.freedesktop.systemd1",
+ "/org/freedesktop/systemd1",
+ "org.freedesktop.systemd1.Manager",
+ "Unsubscribe",
+ &error,
+ NULL, NULL);
++
+ /* TODO: shouldn't we also detach event here? */
+
+ if (rc < 0)
+ log_error_errno(rc, "Failed to unsubscribe.");
+ }
+
+ 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)
--- /dev/null
-
+ /*
+ * 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.
+ */
+
+ #include <malloc.h>
+
+ #include "service.h"
+
+ int system_service_init(pid_t pid, char *name, struct system_service *s)
+ {
+
+ /* TODO: Get real pid if < 0 */
+ s->pid = pid;
++
+ /* TODO: Get real service name if NULL */
+ s->name = name;
+
+ return 0;
+ }
+
+ void system_service_cleanup(struct system_service *s)
+ {
+ if (s)
+ free(s->name);
+ }