From 2cd0a1ef6b47d30bee9f2180775fc983e2222e58 Mon Sep 17 00:00:00 2001 From: Suvendhu Hansa Date: Thu, 11 Sep 2025 13:29:19 +0530 Subject: [PATCH] Register external handler --- libbbfdm-api/legacy/dmapi.h | 1 + libbbfdm-ubus/bbfdm-ubus.c | 200 +++++++++++++ libbbfdm-ubus/bbfdm-ubus.h | 8 + utilities/Makefile | 2 +- .../share/bbfdm/scripts/bbf_default_reload.sh | 42 +++ utilities/src/ubus/bbf_config.c | 270 ++++++++++++++++-- utilities/src/ubus/utils.c | 250 +++++++++++----- utilities/src/ubus/utils.h | 35 ++- 8 files changed, 707 insertions(+), 101 deletions(-) create mode 100644 utilities/files/usr/share/bbfdm/scripts/bbf_default_reload.sh diff --git a/libbbfdm-api/legacy/dmapi.h b/libbbfdm-api/legacy/dmapi.h index 295e7009..c25c0524 100644 --- a/libbbfdm-api/legacy/dmapi.h +++ b/libbbfdm-api/legacy/dmapi.h @@ -162,6 +162,7 @@ typedef struct dm_map_obj { struct dm_leaf_s *root_leaf; int (*init_module)(void *data); int (*clean_module)(void *data); + int (*uci_sync_handler)(void); } DM_MAP_OBJ; struct dm_reference { diff --git a/libbbfdm-ubus/bbfdm-ubus.c b/libbbfdm-ubus/bbfdm-ubus.c index f55a2dab..637d6b74 100644 --- a/libbbfdm-ubus/bbfdm-ubus.c +++ b/libbbfdm-ubus/bbfdm-ubus.c @@ -31,6 +31,7 @@ #include "plugin.h" #define BBFDM_DEFAULT_MICROSERVICE_MODULE_PATH "/usr/share/bbfdm/micro_services" +#define BBFDM_SERVICE_CONFIG_PATH "/etc/bbfdm/services" // Global variables static void *deamon_lib_handle = NULL; @@ -636,6 +637,118 @@ static int regiter_ubus_object(struct ubus_context *ctx) static void bbfdm_ctx_init(struct bbfdm_context *bbfdm_ctx) { INIT_LIST_HEAD(&bbfdm_ctx->event_handlers); + INIT_LIST_HEAD(&bbfdm_ctx->config.apply_handlers); +} + +static void free_apply_handlers(bbfdm_config_t *config) +{ + struct apply_handler_node *node = NULL, *tmp = NULL; + + if (config == NULL) + return; + + list_for_each_entry_safe(node, tmp, &config->apply_handlers, list) { + list_del(&node->list); + BBFDM_FREE(node->file_path); + BBFDM_FREE(node); + } +} + +static int load_apply_handlers_from_file(bbfdm_config_t *config) +{ + char serv_config[MAX_DM_PATH] = {0}; + + if (config == NULL) { + BBF_ERR("bbfdm_config is null"); + return -1; + } + + snprintf(serv_config, sizeof(serv_config), "%s/%s.json", BBFDM_SERVICE_CONFIG_PATH, config->service_name); + if (!bbfdm_file_exists(serv_config) || !bbfdm_is_regular_file(serv_config)) { + BBF_ERR("Config file %s not exists for service %s", serv_config, config->service_name); + return 0; + } + + json_object *json_root = json_object_from_file(serv_config); + if (!json_root) { + BBF_ERR("Failed to read json file %s", serv_config); + return -1; + } + + json_object *daemon_config = NULL; + json_object_object_get_ex(json_root, "daemon", &daemon_config); + if (!daemon_config) { + BBFDM_ERR("Failed to find daemon object"); + json_object_put(json_root); + return -1; + } + + json_object *apply_handler = NULL; + json_object_object_get_ex(daemon_config, "apply_handler", &apply_handler); + if (!apply_handler) { + json_object_put(json_root); + return 0; + } + + char type[2][8] = { "dmmap", "uci" }; + + for (int i = 0; i < 2; i++) { + json_object *array = NULL; + + if (!json_object_object_get_ex(apply_handler, type[i], &array) || + json_object_get_type(array) != json_type_array) { + continue; + } + + size_t count = json_object_array_length(array); + for (size_t j = 0; j < count; j++) { + json_object *hndl_obj = json_object_array_get_idx(array, j); + json_object *files = NULL; + + json_object_object_get_ex(hndl_obj, "file", &files); + if (!files || json_object_get_type(files) != json_type_array) { + continue; + } + + size_t f_count = json_object_array_length(files); + for (size_t k = 0; k < f_count; k++) { + char path[MAX_DM_PATH] = {0}; + + json_object *f_inst = json_object_array_get_idx(files, k); + snprintf(path, sizeof(path), "/etc/%s/%s", + (strcmp(type[i], "uci") == 0) ? "config" : "bbfdm/dmmap", json_object_get_string(f_inst)); + + // check if already present + bool exist = false; + struct apply_handler_node *node = NULL; + list_for_each_entry(node, &config->apply_handlers, list) { + if (DM_STRCMP(node->file_path, path) == 0) { + exist = true; + break; + } + } + + if (exist == true) + continue; + + node = (struct apply_handler_node *)calloc(1, sizeof(struct apply_handler_node)); + if (node == NULL) { + BBFDM_ERR("Failed to allocate memory for apply handlers"); + free_apply_handlers(config); + json_object_put(json_root); + return -1; + } + + INIT_LIST_HEAD(&node->list); + list_add_tail(&node->list, &config->apply_handlers); + + node->file_path = strdup(path); + } + } + } + + json_object_put(json_root); + return 0; } static int load_micro_service_config(bbfdm_config_t *config) @@ -647,6 +760,11 @@ static int load_micro_service_config(bbfdm_config_t *config) return -1; } + if (load_apply_handlers_from_file(config) != 0) { + BBF_ERR("Failed to load handlers from service file"); + return -1; + } + if (INTERNAL_ROOT_TREE == NULL) { // This API will only be called with micro-services started with '-m' option @@ -709,6 +827,8 @@ int bbfdm_print_data_model_schema(struct bbfdm_context *bbfdm_ctx, const enum bb }; int err = 0; + bbfdm_ctx_init(bbfdm_ctx); + err = load_micro_service_config(&bbfdm_ctx->config); if (err) { fprintf(stderr, "Failed to load micro-service config\n"); @@ -752,10 +872,86 @@ int bbfdm_print_data_model_schema(struct bbfdm_context *bbfdm_ctx, const enum bb bbf_cleanup(&bbf_ctx); + free_apply_handlers(&bbfdm_ctx->config); + bbfdm_ctx_cleanup(bbfdm_ctx); return err; } +static void perform_uci_sync_op(struct uloop_timeout *timeout) +{ + DM_MAP_OBJ *dynamic_obj = INTERNAL_ROOT_TREE; + + if (dynamic_obj == NULL) + return; + + for (int i = 0; dynamic_obj[i].path; i++) { + if (dynamic_obj[i].uci_sync_handler) { + dynamic_obj[i].uci_sync_handler(); + } + } +} + +static void bbfdm_apply_event_cb(struct ubus_context *ctx __attribute__((unused)), + struct ubus_event_handler *ev, + const char *type __attribute__((unused)), + struct blob_attr *msg) +{ + if (!msg) + return; + + struct bbfdm_context *bbfdm_ctx = container_of(ev, struct bbfdm_context, apply_event); + if (bbfdm_ctx == NULL) + return; + + bbfdm_config_t *config = &bbfdm_ctx->config; + + const struct blobmsg_policy p[2] = { + { "proto", BLOBMSG_TYPE_STRING }, + { "uci_changed", BLOBMSG_TYPE_ARRAY } + }; + + struct blob_attr *tb[2] = {NULL, NULL}; + blobmsg_parse(p, 2, tb, blob_data(msg), blob_len(msg)); + + if (!tb[0] || !tb[1]) + return; + + const char *proto = blobmsg_get_string(tb[0]); + struct blob_attr *attr = NULL; + int rem = 0; + + blobmsg_for_each_attr(attr, tb[1], rem) { + char *conf_name = blobmsg_get_string(attr); + + /* Now check if the config file is intended file */ + struct apply_handler_node *node = NULL; + + list_for_each_entry(node, &config->apply_handlers, list) { + if (DM_STRCMP(node->file_path, conf_name) != 0) + continue; + + BBF_INFO("Scheduling UCI sync operation for changes performed by %s", proto); + memset(&bbfdm_ctx->sync_timer, 0, sizeof(struct uloop_timeout)); + bbfdm_ctx->sync_timer.cb = perform_uci_sync_op; + uloop_timeout_set(&bbfdm_ctx->sync_timer, 10); + + return; + } + } +} + +static void register_bbfdm_apply_event(struct bbfdm_context *bbfdm_ctx) +{ + if (bbfdm_ctx == NULL) + return; + + memset(&bbfdm_ctx->apply_event, 0, sizeof(struct ubus_event_handler)); + bbfdm_ctx->apply_event.cb = bbfdm_apply_event_cb; + + ubus_register_event_handler(&bbfdm_ctx->ubus_ctx, &bbfdm_ctx->apply_event, "bbfdm.apply"); +} + int bbfdm_ubus_regiter_init(struct bbfdm_context *bbfdm_ctx) { int err = 0, cur_log_mask=0; @@ -800,11 +996,15 @@ int bbfdm_ubus_regiter_init(struct bbfdm_context *bbfdm_ctx) return -1; } + register_bbfdm_apply_event(bbfdm_ctx); + return register_events_to_ubus(&bbfdm_ctx->ubus_ctx, &bbfdm_ctx->event_handlers); } int bbfdm_ubus_regiter_free(struct bbfdm_context *bbfdm_ctx) { + free_apply_handlers(&bbfdm_ctx->config); + ubus_unregister_event_handler(&bbfdm_ctx->ubus_ctx, &bbfdm_ctx->apply_event); free_ubus_event_handler(&bbfdm_ctx->ubus_ctx, &bbfdm_ctx->event_handlers); bbfdm_ctx_cleanup(bbfdm_ctx); uloop_done(); diff --git a/libbbfdm-ubus/bbfdm-ubus.h b/libbbfdm-ubus/bbfdm-ubus.h index fcd5d38c..59853935 100644 --- a/libbbfdm-ubus/bbfdm-ubus.h +++ b/libbbfdm-ubus/bbfdm-ubus.h @@ -16,7 +16,13 @@ struct bbfdm_async_req { void *result; }; +struct apply_handler_node { + char *file_path; + struct list_head list; +}; + typedef struct bbfdm_config { + struct list_head apply_handlers; char service_name[32]; // Service name for micro-service identification char in_name[128]; // Service plugin path char in_plugin_dir[128]; // Service extra/internal plugin directory path @@ -25,8 +31,10 @@ typedef struct bbfdm_config { struct bbfdm_context { bbfdm_config_t config; + struct ubus_event_handler apply_event; struct ubus_context ubus_ctx; struct list_head event_handlers; + struct uloop_timeout sync_timer; }; typedef struct bbfdm_data { diff --git a/utilities/Makefile b/utilities/Makefile index fdf926f1..c4c4eabe 100644 --- a/utilities/Makefile +++ b/utilities/Makefile @@ -4,7 +4,7 @@ OBJS = src/ubus/bbf_config.o src/ubus/utils.o PROG_CFLAGS = $(CFLAGS) -Wall -Werror PROG_LDFLAGS = $(LDFLAGS) -PROG_LIBS += -luci -lubus -lubox -lblobmsg_json +PROG_LIBS += -luci -lubus -lubox -lblobmsg_json -ljson-c INSTALL_DIR = /usr/sbin diff --git a/utilities/files/usr/share/bbfdm/scripts/bbf_default_reload.sh b/utilities/files/usr/share/bbfdm/scripts/bbf_default_reload.sh new file mode 100644 index 00000000..66bdacfe --- /dev/null +++ b/utilities/files/usr/share/bbfdm/scripts/bbf_default_reload.sh @@ -0,0 +1,42 @@ +#!/bin/sh + +# Script: bbf_default_reload.sh +# Description: +# This script reloads UCI Configs based on input args. +# Input args should be space separated uci file names +# +# Usage: +# sh bbf_default_reload.sh network firewall +# +# Actions: +# - performs "ubus call uci commit '{"config":""}' for +# each uci file received in argument list + +. /usr/share/libubox/jshn.sh + +log() { + echo "${@}"|logger -t bbf.config.default.reload -p info +} + +input="$@" + +# Validate input +if [ -z "$input" ]; then + log "Error: No input provided" + exit 1 +fi + +for uci in ${input}; do + log "Reloading ${uci} config" + + json_init + json_add_string "config" "${uci}" + json_compact + + json_data=$(json_dump) + ubus -t 5 call uci commit "${json_data}" + + json_cleanup +done + +exit 0 diff --git a/utilities/src/ubus/bbf_config.c b/utilities/src/ubus/bbf_config.c index ac973f06..1b04bfd9 100644 --- a/utilities/src/ubus/bbf_config.c +++ b/utilities/src/ubus/bbf_config.c @@ -14,6 +14,8 @@ #include #include #include +#include +#include #include "utils.h" @@ -26,6 +28,7 @@ #define BBF_CONFIG_DAEMON_NAME "bbf_configd" #define CRITICAL_DEF_JSON "/etc/bbfdm/critical_services.json" +#define BBFDM_MICROSERVICE_INPUT_PATH "/etc/bbfdm/services" // Structure to represent an instance of a service struct instance { @@ -48,14 +51,17 @@ struct config_package { }; struct bbf_config_async_req { + int idx; struct ubus_context *ctx; struct ubus_request_data req; struct uloop_timeout timeout; struct blob_attr *services; struct config_package package[MAX_PACKAGE_NUM]; + struct list_head changed_uci_list; }; static struct blob_buf g_critical_bb; +static struct list_head g_apply_handlers; #ifdef BBF_CONFIG_DEBUG static void log_instance(struct instance *inst) @@ -475,6 +481,48 @@ static void send_bbf_config_change_event() ubus_free(ctx); } +static void send_bbf_apply_event(int idx, struct list_head *changed_uci_list) +{ + if (changed_uci_list == NULL || list_empty(changed_uci_list)) + return; + + struct ubus_context *ctx; + struct blob_buf bb = {0}; + struct modi_uci_node *node = NULL, *tmp = NULL; + + memset(&bb, 0, sizeof(struct blob_buf)); + blob_buf_init(&bb, 0); + + blobmsg_add_string(&bb, "proto", get_proto_name_by_idx(idx)); + void *array = blobmsg_open_array(&bb, "uci_changed"); + list_for_each_entry_safe(node, tmp, changed_uci_list, list) { + if (node->uci == NULL) { + list_del(&node->list); + FREE(node); + continue; + } + + blobmsg_add_string(&bb, NULL, node->uci); + list_del(&node->list); + FREE(node->uci); + FREE(node); + } + blobmsg_close_array(&bb, array); + + ctx = ubus_connect(NULL); + if (ctx == NULL) { + ULOG_ERR("Can't create UBUS context for 'bbfdm.apply' event"); + blob_buf_free(&bb); + return; + } + + ULOG_INFO("Sending bbfdm.apply event"); + + ubus_send_event(ctx, "bbfdm.apply", bb.head); + blob_buf_free(&bb); + ubus_free(ctx); +} + static void send_reply(struct ubus_context *ctx, struct ubus_request_data *req, const char *message, const char *description) { struct blob_buf bb = {0}; @@ -498,13 +546,14 @@ static void complete_deferred_request(struct bbf_config_async_req *async_req) // Complete the deferred request and send the response ubus_complete_deferred_request(async_req->ctx, &async_req->req, 0); + // Send 'bbf.config.change' event to run refresh instances + send_bbf_config_change_event(); + send_bbf_apply_event(async_req->idx, &async_req->changed_uci_list); + // Free the allocated memory FREE(async_req->services); FREE(async_req); - // Send 'bbf.config.change' event to run refresh instances - send_bbf_config_change_event(); - // Set internal commit to false g_internal_commit = false; @@ -607,9 +656,11 @@ static int bbf_config_commit_handler(struct ubus_context *ctx, struct ubus_objec struct blob_attr *tb[__MAX]; bool monitor = false, reload = true; unsigned char idx = 0; - uint32_t wifi_config_flags = 0; + struct list_head action_list; + struct list_head *changed_uci; ULOG_INFO("Commit handler called"); + INIT_LIST_HEAD(&action_list); if (blobmsg_parse(bbf_config_policy, __MAX, tb, blob_data(msg), blob_len(msg))) { send_reply(ctx, req, "error", "Failed to parse blob"); @@ -622,6 +673,9 @@ static int bbf_config_commit_handler(struct ubus_context *ctx, struct ubus_objec return -1; } + changed_uci = &async_req->changed_uci_list; + INIT_LIST_HEAD(changed_uci); + // Set internal commit to true g_internal_commit = true; @@ -669,21 +723,42 @@ static int bbf_config_commit_handler(struct ubus_context *ctx, struct ubus_objec } ULOG_INFO("Committing changes for specified services and reloading"); - reload_specified_services(ctx, idx, async_req->services, true, reload, &wifi_config_flags); + reload_specified_services(ctx, idx, async_req->services, true, reload, &action_list, + &g_apply_handlers, changed_uci); } else { ULOG_INFO("Applying changes to dmmap UCI config"); - uci_apply_changes(DMMAP_CONFDIR, idx, true); // commit dmmap changes + uci_apply_changes_dmmap(idx, true, &action_list, &g_apply_handlers); ULOG_INFO("Committing changes for all services and reloading"); - reload_all_services(ctx, idx, true, reload, &wifi_config_flags); + reload_all_services(ctx, idx, true, reload, &action_list, &g_apply_handlers, changed_uci); } - if (wifi_config_flags) { - ULOG_ERR("Reloading changes for wifi services"); - wifi_reload_handler_script(wifi_config_flags); + struct action_node *node = NULL, *tmp = NULL; + list_for_each_entry_safe(node, tmp, &action_list, list) { + char cmd[4096] = {0}; + unsigned pos = 0; + + ULOG_INFO("Reloading changes"); + + if (!file_exists(node->action)) { + list_del(&node->list); + FREE(node); + continue; + } + + pos += snprintf(cmd, sizeof(cmd), "sh %s", node->action); + + for (int i = 0; i < node->idx; i++) { + pos += snprintf(&cmd[pos], sizeof(cmd) - pos, " %s", node->arg[i]); + } + + exec_apply_handler_script(cmd); + list_del(&node->list); + FREE(node); } if (monitor) { ULOG_INFO("Deferring request and setting up async completion"); + async_req->idx = idx; ubus_defer_request(ctx, req, &async_req->req); async_req->timeout.cb = complete_request_callback; uloop_timeout_set(&async_req->timeout, 2000); @@ -691,13 +766,14 @@ static int bbf_config_commit_handler(struct ubus_context *ctx, struct ubus_objec ULOG_INFO("Sending immediate success response"); send_reply(ctx, req, "status", "ok"); + // Send 'bbf.config.change' event to run refresh instances + send_bbf_config_change_event(); + send_bbf_apply_event(idx, changed_uci); + // Free the allocated memory FREE(async_req->services); FREE(async_req); - // Send 'bbf.config.change' event to run refresh instances - send_bbf_config_change_event(); - // Set internal commit to false g_internal_commit = false; @@ -733,12 +809,12 @@ static int bbf_config_revert_handler(struct ubus_context *ctx, struct ubus_objec if (arr_len) { ULOG_INFO("Reverting specified services"); - reload_specified_services(ctx, idx, services, false, false, NULL); + reload_specified_services(ctx, idx, services, false, false, NULL, NULL, NULL); } else { - ULOG_INFO("Applying changes to dmmap UCI config"); - uci_apply_changes(DMMAP_CONFDIR, idx, false); // revert dmmap changes + ULOG_INFO("Reverting changes to dmmap UCI config"); + uci_apply_changes_dmmap(idx, false, NULL, NULL); // revert dmmap changes ULOG_INFO("Reverting all services"); - reload_all_services(ctx, idx, false, false, NULL); + reload_all_services(ctx, idx, false, false, NULL, NULL, NULL); } ULOG_INFO("Sending success response"); @@ -796,6 +872,164 @@ static void load_critical_services() blobmsg_add_json_from_file(&g_critical_bb, CRITICAL_DEF_JSON); } +static int filter(const struct dirent *entry) +{ + return entry->d_name[0] != '.'; +} + +static int compare(const struct dirent **a, const struct dirent **b) +{ + size_t len_a = strlen((*a)->d_name); + size_t len_b = strlen((*b)->d_name); + + if (len_a < len_b) // Sort by length (shorter first) + return -1; + + if (len_a > len_b) + return 1; + + return strcasecmp((*a)->d_name, (*b)->d_name); // If lengths are equal, sort alphabetically +} + +static void free_apply_handlers() +{ + struct applier_node *node = NULL, *tmp = NULL; + + list_for_each_entry_safe(node, tmp, &g_apply_handlers, list) { + list_del(&node->list); + FREE(node->file_path); + FREE(node->action); + FREE(node); + } +} + +static void __load_handlers(const char *file) +{ + if (file == NULL || strlen(file) == 0) + return; + + json_object *json_root = json_object_from_file(file); + if (!json_root) { + ULOG_INFO("Failed to read json file %s", file); + return; + } + + json_object *daemon_config = NULL; + json_object_object_get_ex(json_root, "daemon", &daemon_config); + if (!daemon_config) { + ULOG_INFO("Failed to find daemon object"); + json_object_put(json_root); + return; + } + + json_object *apply_handler = NULL; + json_object_object_get_ex(daemon_config, "apply_handler", &apply_handler); + if (!apply_handler) { + json_object_put(json_root); + return; + } + + char type[2][8] = { "dmmap", "uci" }; + + for (int i = 0; i < 2; i++) { + json_object *array = NULL; + + if (!json_object_object_get_ex(apply_handler, type[i], &array) || + json_object_get_type(array) != json_type_array) { + continue; + } + + size_t count = json_object_array_length(array); + for (size_t j = 0; j < count; j++) { + json_object *hndl_obj = json_object_array_get_idx(array, j); + json_object *files = NULL, *handler = NULL; + + json_object_object_get_ex(hndl_obj, "external_handler", &handler); + if (!handler) { + continue; + } + + const char *action = json_object_get_string(handler); + if (strlen(action) == 0 || !file_exists(action)) { + continue; + } + + json_object_object_get_ex(hndl_obj, "file", &files); + if (!files || json_object_get_type(files) != json_type_array) { + continue; + } + + size_t f_count = json_object_array_length(files); + for (size_t k = 0; k < f_count; k++) { + char path[1024] = {0}; + + json_object *f_inst = json_object_array_get_idx(files, k); + snprintf(path, sizeof(path), "/etc/%s/%s", + (strcmp(type[i], "uci") == 0) ? "config" : "bbfdm/dmmap", json_object_get_string(f_inst)); + + + // check if already present + bool exist = false; + struct applier_node *node = NULL; + list_for_each_entry(node, &g_apply_handlers, list) { + if (strcmp(node->file_path, path) == 0 && strcmp(node->action, action) == 0) { + exist = true; + break; + } + } + + if (exist == true) + continue; + + node = (struct applier_node *)calloc(1, sizeof(struct applier_node)); + if (node == NULL) { + ULOG_INFO("Failed to allocate memory for apply handlers"); + json_object_put(json_root); + return; + } + + INIT_LIST_HEAD(&node->list); + list_add_tail(&node->list, &g_apply_handlers); + + node->file_path = strdup(path); + node->action = strdup(action); + } + } + } + + json_object_put(json_root); + return; +} + +static void load_apply_handlers() +{ + struct dirent **namelist; + + INIT_LIST_HEAD(&g_apply_handlers); + + int num_files = scandir(BBFDM_MICROSERVICE_INPUT_PATH, &namelist, filter, compare); + + for (int i = 0; i < num_files; i++) { + char file_path[512] = {0}; + + snprintf(file_path, sizeof(file_path), "%s/%s", BBFDM_MICROSERVICE_INPUT_PATH, namelist[i]->d_name); + + if (!file_exists(file_path) || !regular_file(file_path)) { + free(namelist[i]); + continue; + } + + __load_handlers(file_path); + + free(namelist[i]); + } + + if (namelist) + free(namelist); + + return; +} + int main(int argc, char **argv) { struct ubus_event_handler ev = { @@ -835,6 +1069,7 @@ int main(int argc, char **argv) ubus_add_uloop(uctx); load_critical_services(); + load_apply_handlers(); if (ubus_add_object(uctx, &bbf_config_object)) { ULOG_ERR("Failed to add 'bbf.config' ubus object"); @@ -849,6 +1084,7 @@ int main(int argc, char **argv) uloop_run(); exit: + free_apply_handlers(); blob_buf_free(&g_critical_bb); uloop_done(); ubus_free(uctx); diff --git a/utilities/src/ubus/utils.c b/utilities/src/ubus/utils.c index 9c834498..0c8488f4 100644 --- a/utilities/src/ubus/utils.c +++ b/utilities/src/ubus/utils.c @@ -11,6 +11,7 @@ #include #include #include +#include #include "utils.h" @@ -35,6 +36,136 @@ static struct proto_args supported_protocols[] = { }, }; +static void add_external_action_list(struct list_head *action_list, struct list_head *ext_handler, const char *file_path) +{ + if (file_path == NULL || strlen(file_path) == 0 || action_list == NULL) + return; + + struct applier_node *app_node = NULL; + bool ext_exist = false; + + char *config = strrchr(file_path, '/'); + if (config) { + config = config + 1; + } + + list_for_each_entry(app_node, ext_handler, list) { + if (strcmp(app_node->file_path, file_path) != 0) { + continue; + } + + ext_exist = true; + + bool node_exist = false; + bool arg_exist = false; + struct action_node *act_node = NULL; + + list_for_each_entry(act_node, action_list, list) { + if (strcmp(app_node->action, act_node->action) == 0) { + node_exist = true; + for (int i = 0; i < act_node->idx; i++) { + if (strcmp(act_node->arg[i], config) == 0) { + arg_exist = true; + break; + } + } + break; + } + } + + if (node_exist == false) { + act_node = (struct action_node *)calloc(1, sizeof(struct action_node)); + if (act_node == NULL) { + ULOG_INFO("Failed to allocate memory for action list"); + return; + } + + snprintf(act_node->action, sizeof(act_node->action), "%s", app_node->action); + INIT_LIST_HEAD(&act_node->list); + list_add_tail(&act_node->list, action_list); + } + + if (arg_exist == false && act_node->idx < ARG_COUNT) { + snprintf(act_node->arg[act_node->idx], ARG_LEN, "%s", config); + act_node->idx = act_node->idx + 1; + ULOG_DEBUG("Added %s handler for %s config", act_node->action, config); + } + } + + if (ext_exist == true || strncmp(file_path, DMMAP_CONFDIR, strlen(DMMAP_CONFDIR)) == 0) { + /* external handler exist, so already added in list or + * the file is a dmmap file so it has no default handler + * to add in the action list */ + return; + } + + /* external handler not exist, add default handler */ + struct action_node *act_node = NULL; + bool node_exist = false; + bool arg_exist = false; + + list_for_each_entry(act_node, action_list, list) { + if (strcmp(app_node->action, DEFAULT_HANDLER_ACT) == 0) { + node_exist = true; + for (int i = 0; i < act_node->idx; i++) { + if (strcmp(act_node->arg[i], config) == 0) { + arg_exist = true; + break; + } + } + break; + } + } + + if (node_exist == false) { + act_node = (struct action_node *)calloc(1, sizeof(struct action_node)); + if (act_node == NULL) { + ULOG_INFO("Failed to allocate memory for action list"); + return; + } + + snprintf(act_node->action, sizeof(act_node->action), "%s", DEFAULT_HANDLER_ACT); + INIT_LIST_HEAD(&act_node->list); + list_add_tail(&act_node->list, action_list); + } + + if (arg_exist == false && act_node->idx < ARG_COUNT) { + snprintf(act_node->arg[act_node->idx], ARG_LEN, "%s", config); + act_node->idx = act_node->idx + 1; + ULOG_DEBUG("Added default handler for %s config", config); + } +} + +static void add_changed_uci_list(struct list_head *changed_uci, const char *file_path) +{ + if (changed_uci == NULL || file_path == NULL || strlen(file_path) == 0) + return; + + struct modi_uci_node *node = NULL; + bool exist = false; + + list_for_each_entry(node, changed_uci, list) { + if (!node->uci || strcmp(node->uci, file_path) != 0) + continue; + + exist = true; + break; + } + + if (exist) + return; + + node = (struct modi_uci_node *)calloc(1, sizeof(struct modi_uci_node)); + if (!node) { + ULOG_INFO("Failed to allocate memory for changed uci list"); + return; + } + + node->uci = strdup(file_path); + INIT_LIST_HEAD(&node->list); + list_add_tail(&node->list, changed_uci); +} + unsigned char get_idx_by_proto(const char *proto) { for (int i = 0; i < ARRAY_SIZE(supported_protocols); i++) { @@ -93,24 +224,6 @@ bool file_exists(const char *path) return stat(path, &buffer) == 0; } -static bool is_wifi_configs(const char *config_name, uint32_t *wifi_config_flags) -{ - if (!config_name && !wifi_config_flags) - return false; - - if (strcmp(config_name, "wireless") == 0) { - *wifi_config_flags |= WIRELESS_CONFIG; - return true; - } - - if (strcmp(config_name, "mapcontroller") == 0) { - *wifi_config_flags |= MAPCONTROLLER_CONFIG; - return true; - } - - return false; -} - int bbf_config_call(struct ubus_context *ctx, const char *object, const char *method, struct blob_buf *data, ubus_data_handler_t callback, void *arg) { int fault = 0; @@ -136,34 +249,9 @@ int bbf_config_call(struct ubus_context *ctx, const char *object, const char *me return 0; } -static void reload_service(struct ubus_context *ctx, const char *config_name, bool is_commit) -{ - struct blob_buf bb = {0}; - - if (!ctx || !config_name) { - ULOG_ERR("Failed to reload service: 'ctx' or 'config_name' is NULL"); - return; - } - - memset(&bb, 0, sizeof(struct blob_buf)); - - blob_buf_init(&bb, 0); - - blobmsg_add_string(&bb, "config", config_name); - - int result = bbf_config_call(ctx, "uci", (is_commit) ? "commit" : "revert", &bb, NULL, NULL); - if (result != 0) { - ULOG_ERR("Failed to %s configuration '%s'", (is_commit ? "commit" : "revert"), config_name); - } else { - ULOG_DEBUG("Successfully executed %s on configuration '%s'.", (is_commit ? "commit" : "revert"), config_name); - } - - blob_buf_free(&bb); -} - - void reload_specified_services(struct ubus_context *ctx, int idx, struct blob_attr *services, - bool is_commit, bool reload, uint32_t *wifi_config_flags) + bool is_commit, bool reload, struct list_head *action_list, + struct list_head *handler_list, struct list_head *changed_uci) { struct uci_context *uci_ctx = NULL; struct blob_attr *service = NULL; @@ -210,6 +298,9 @@ void reload_specified_services(struct ubus_context *ctx, int idx, struct blob_at ULOG_DEBUG("Looking up UCI configuration for service '%s'", config_name); + char file_path[1024] = {0}; + snprintf(file_path, sizeof(file_path), "%s%s", conf_dir, package); + if (uci_lookup_ptr(uci_ctx, &ptr, package, true) != UCI_OK) { ULOG_ERR("Failed to lookup UCI pointer for service '%s'. Skipping", config_name); continue; @@ -221,6 +312,10 @@ void reload_specified_services(struct ubus_context *ctx, int idx, struct blob_at ULOG_ERR("Failed to commit UCI changes for service '%s'", config_name); continue; } + + if (!is_dmmap) { + add_changed_uci_list(changed_uci, file_path); + } } else { ULOG_DEBUG("Reverting UCI changes for service '%s'", config_name); if (uci_revert(uci_ctx, &ptr) != UCI_OK) { @@ -229,12 +324,12 @@ void reload_specified_services(struct ubus_context *ctx, int idx, struct blob_at } } - if (reload && !is_dmmap) { - if (is_wifi_configs(package, wifi_config_flags)) - continue; + if (is_commit && is_dmmap) { + add_external_action_list(action_list, handler_list, file_path); + } - ULOG_INFO("Reloading service '%s'", package); - reload_service(ctx, package, is_commit); + if (reload && !is_dmmap) { + add_external_action_list(action_list, handler_list, file_path); } } @@ -243,7 +338,8 @@ void reload_specified_services(struct ubus_context *ctx, int idx, struct blob_at } void reload_all_services(struct ubus_context *ctx, int idx, bool is_commit, - bool reload, uint32_t *wifi_config_flags) + bool reload, struct list_head *action_list, + struct list_head *handler_list, struct list_head *changed_uci) { struct uci_context *uci_ctx = NULL; char **configs = NULL, **p = NULL; @@ -271,6 +367,8 @@ void reload_all_services(struct ubus_context *ctx, int idx, bool is_commit, struct uci_ptr ptr = {0}; ULOG_DEBUG("Looking up UCI configuration for '%s'", *p); + char file_path[1024] = {0}; + snprintf(file_path, sizeof(file_path), "%s%s", CONFIG_CONFDIR, *p); if (uci_lookup_ptr(uci_ctx, &ptr, *p, true) != UCI_OK) { ULOG_ERR("Failed to lookup UCI pointer for config '%s'. Skipping", *p); @@ -288,6 +386,8 @@ void reload_all_services(struct ubus_context *ctx, int idx, bool is_commit, ULOG_ERR("Failed to commit changes for config '%s'", *p); continue; } + + add_changed_uci_list(changed_uci, file_path); } else { ULOG_DEBUG("Reverting UCI changes for config '%s'", *p); if (uci_revert(uci_ctx, &ptr) != UCI_OK) { @@ -297,11 +397,7 @@ void reload_all_services(struct ubus_context *ctx, int idx, bool is_commit, } if (reload) { - if (is_wifi_configs(*p, wifi_config_flags)) - continue; - - ULOG_INFO("Reloading service for config '%s'", *p); - reload_service(ctx, *p, is_commit); + add_external_action_list(action_list, handler_list, file_path); } } @@ -311,26 +407,15 @@ exit: uci_free_context(uci_ctx); } -void wifi_reload_handler_script(uint32_t wifi_config_flags) +void exec_apply_handler_script(const char *cmd) { -#define WIFI_CONFIG_RELOAD_SCRIPT "/etc/wifidmd/bbf_config_reload.sh" - char cmd[512] = {0}; - - if (!file_exists(WIFI_CONFIG_RELOAD_SCRIPT)) - return; - - snprintf(cmd, sizeof(cmd), "sh %s '{\"wireless\":\"%d\",\"mapcontroller\":\"%d\"}'", - WIFI_CONFIG_RELOAD_SCRIPT, - wifi_config_flags & WIRELESS_CONFIG ? 1 : 0, - wifi_config_flags & MAPCONTROLLER_CONFIG ? 1 : 0); - FILE *pp = popen(cmd, "r"); // flawfinder: ignore if (pp) { pclose(pp); } } -void uci_apply_changes(const char *conf_dir, int idx, bool is_commit) +void uci_apply_changes_dmmap(int idx, bool is_commit, struct list_head *action_list, struct list_head *ext_handler) { struct uci_context *uci_ctx = NULL; char **configs = NULL, **p = NULL; @@ -342,16 +427,9 @@ void uci_apply_changes(const char *conf_dir, int idx, bool is_commit) return; } - if (conf_dir) { - ULOG_DEBUG("Setting UCI configuration directory to '%s'", conf_dir); - uci_set_confdir(uci_ctx, conf_dir); - - if (strcmp(conf_dir, DMMAP_CONFDIR) == 0) { - snprintf(save_dir, sizeof(save_dir), "%s", get_proto_dmmap_savedir_by_idx(idx)); - } else if(strcmp(conf_dir, CONFIG_CONFDIR) == 0) { - snprintf(save_dir, sizeof(save_dir), "%s", get_proto_conf_savedir_by_idx(idx)); - } - } + ULOG_DEBUG("Setting UCI configuration directory to '%s'", DMMAP_CONFDIR); + uci_set_confdir(uci_ctx, DMMAP_CONFDIR); + snprintf(save_dir, sizeof(save_dir), "%s", get_proto_dmmap_savedir_by_idx(idx)); ULOG_DEBUG("Setting UCI save directory to '%s'", save_dir); uci_set_savedir(uci_ctx, save_dir); @@ -378,6 +456,10 @@ void uci_apply_changes(const char *conf_dir, int idx, bool is_commit) ULOG_ERR("Failed to commit changes for config '%s'", *p); continue; } + + char file_path[1024] = {0}; + snprintf(file_path, sizeof(file_path), "%s%s", DMMAP_CONFDIR, *p); + add_external_action_list(action_list, ext_handler, file_path); } else { ULOG_DEBUG("Reverting changes for config '%s'", *p); if (uci_revert(uci_ctx, &ptr) != UCI_OK) { @@ -392,3 +474,13 @@ void uci_apply_changes(const char *conf_dir, int idx, bool is_commit) exit: uci_free_context(uci_ctx); } + +bool regular_file(const char *path) +{ + struct stat buffer; + + if (!path) + return false; + + return stat(path, &buffer) == 0 && S_ISREG(buffer.st_mode); +} diff --git a/utilities/src/ubus/utils.h b/utilities/src/ubus/utils.h index 98e704a5..f729ea6d 100644 --- a/utilities/src/ubus/utils.h +++ b/utilities/src/ubus/utils.h @@ -27,29 +27,56 @@ #define CONFIG_CONFDIR "/etc/config/" #define DMMAP_CONFDIR "/etc/bbfdm/dmmap/" +#define DEFAULT_HANDLER_ACT "/etc/bbfdm/bbf_default_reload.sh" +#define ARG_LEN 64 +#define ARG_COUNT 40 +#define ACTION_LEN 512 enum wifi_config_flags_enum { WIRELESS_CONFIG = 1, MAPCONTROLLER_CONFIG = 1<<1, }; +struct applier_node { + char *file_path; + char *action; + struct list_head list; +}; + +struct action_node { + struct list_head list; + char action[ACTION_LEN]; + char arg[ARG_COUNT][ARG_LEN]; + int idx; +}; + +struct modi_uci_node { + char *uci; + struct list_head list; +}; + void strncpyt(char *dst, const char *src, size_t n); int bbf_config_call(struct ubus_context *ctx, const char *object, const char *method, struct blob_buf *data, ubus_data_handler_t callback, void *arg); void reload_specified_services(struct ubus_context *ctx, int idx, struct blob_attr *services, - bool is_commit, bool reload, uint32_t *wifi_config_flags); + bool is_commit, bool reload, struct list_head *action_list, + struct list_head *handler_list, struct list_head *changed_uci); void reload_all_services(struct ubus_context *ctx, int idx, bool is_commit, - bool reload, uint32_t *wifi_config_flags); + bool reload, struct list_head *action_list, + struct list_head *handler_list, struct list_head *changed_uci); -void wifi_reload_handler_script(uint32_t wifi_config_flags); +void exec_apply_handler_script(const char *cmd); -void uci_apply_changes(const char *conf_dir, int idx, bool is_commit); +void uci_apply_changes_dmmap(int idx, bool is_commit, struct list_head *action_list, + struct list_head *handler_list); unsigned char get_idx_by_proto(const char *proto); const char *get_proto_conf_savedir_by_idx(int idx); const char *get_proto_dmmap_savedir_by_idx(int idx); const char *get_proto_name_by_idx(int idx); +bool file_exists(const char *path); +bool regular_file(const char *path); #endif //__UTILS_H__