From: Łukasz Stelmach Date: Wed, 26 Apr 2017 17:46:23 +0000 (+0200) Subject: Merge remote-tracking branch 'tizen.org/sandbox/kopasiak/event_fw' X-Git-Tag: end-of-sprint-1~21 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=742c8378922f279b3b63ab97c313e433ba4cbb7f;p=platform%2Fcore%2Fsystem%2Ffaultd.git Merge remote-tracking branch 'tizen.org/sandbox/kopasiak/event_fw' Conflicts: Makefile.am src/log.c --- 742c8378922f279b3b63ab97c313e433ba4cbb7f diff --cc Makefile.am index 0a4bbea,efd2980..b91d67f --- a/Makefile.am +++ b/Makefile.am @@@ -28,9 -32,16 +32,17 @@@ SED_PROCESS = 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} diff --cc src/core/module.c index 0000000,04fd49f..b1837ce mode 000000,100644..100644 --- a/src/core/module.c +++ b/src/core/module.c @@@ -1,0 -1,111 +1,111 @@@ + /* + * 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 + + #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); - } ++ } + } + } diff --cc src/event.h index 0000000,59846e0..d3cd68d mode 000000,100644..100644 --- a/src/event.h +++ b/src/event.h @@@ -1,0 -1,120 +1,119 @@@ + /* + * 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 + #include + + #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 */ diff --cc src/event_processor.c index 0000000,64a7906..b5594ef mode 000000,100644..100644 --- a/src/event_processor.c +++ b/src/event_processor.c @@@ -1,0 -1,197 +1,197 @@@ + /* + * 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 + + #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); + } diff --cc src/event_types/decision_made_event.h index 0000000,c6fd827..4efa1d8 mode 000000,100644..100644 --- a/src/event_types/decision_made_event.h +++ b/src/event_types/decision_made_event.h @@@ -1,0 -1,54 +1,54 @@@ + /* + * 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 + + #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 *); ++ 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 */ diff --cc src/event_types/resource_violation_event.c index 0000000,90deeb1..f57ddce mode 000000,100644..100644 --- a/src/event_types/resource_violation_event.c +++ b/src/event_types/resource_violation_event.c @@@ -1,0 -1,94 +1,93 @@@ + /* + * 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 + #include + #include + + #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) diff --cc src/event_types/resource_violation_event.h index 0000000,5632c4d..7dd20c0 mode 000000,100644..100644 --- a/src/event_types/resource_violation_event.h +++ b/src/event_types/resource_violation_event.h @@@ -1,0 -1,52 +1,52 @@@ + /* + * 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 + + #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 */ diff --cc src/listeners/audit.c index 0000000,a00eff3..70f7ba2 mode 000000,100644..100644 --- a/src/listeners/audit.c +++ b/src/listeners/audit.c @@@ -1,0 -1,252 +1,252 @@@ + /* + * 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 + #include + #include + #include + #include + #include + #include + + #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) diff --cc src/listeners/systemd.c index 0000000,3ec551f..87f0423 mode 000000,100644..100644 --- a/src/listeners/systemd.c +++ b/src/listeners/systemd.c @@@ -1,0 -1,216 +1,216 @@@ + /* + * 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 + #include + #include + #include + + #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) diff --cc src/service.c index 0000000,c5dce60..a5e78cb mode 000000,100644..100644 --- a/src/service.c +++ b/src/service.c @@@ -1,0 -1,39 +1,39 @@@ + /* + * 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 + + #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); + }