diff --git a/CMakeLists.txt b/CMakeLists.txt index 7736f2978554b64c741fdc63f4f5e638ecbdf11e..2c14b50c6fa86c6a9d8d73cc67576ab946f9f0d0 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -3,6 +3,7 @@ cmake_minimum_required(VERSION 3.0) PROJECT(bbf C) add_subdirectory(libbbfdm-api) +add_subdirectory(libbbfdm-ubus) add_subdirectory(libbbfdm) add_subdirectory(bbfdmd) diff --git a/bbfdmd/ubus/CMakeLists.txt b/bbfdmd/ubus/CMakeLists.txt index a0596585e678656dfd943b3acb63d4bfdd40d4e4..b10e8a5f584df125a1b8869568d3f94eb7ee9ead 100644 --- a/bbfdmd/ubus/CMakeLists.txt +++ b/bbfdmd/ubus/CMakeLists.txt @@ -3,21 +3,10 @@ cmake_minimum_required(VERSION 3.0) PROJECT(bbfdmd) ADD_DEFINITIONS(-fstrict-aliasing -Wall -Wextra -Werror -Wformat -Wformat-signedness -fPIC -D_GNU_SOURCE) -ADD_DEFINITIONS(-DBBF_VENDOR_PREFIX="${BBF_VENDOR_PREFIX}") -SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -I${CMAKE_SOURCE_DIR} -I${CMAKE_SOURCE_DIR}/libbbfdm-api/") - -IF(${BBFDMD_MAX_MSG_LEN}) - ADD_DEFINITIONS(-DBBFDM_MAX_MSG_LEN=${BBFDMD_MAX_MSG_LEN}) -ENDIF() - -OPTION(BBF_SCHEMA_FULL_TREE "build with schema full tree" OFF) - -IF(BBF_SCHEMA_FULL_TREE) - add_compile_definitions(BBF_SCHEMA_FULL_TREE) -ENDIF(BBF_SCHEMA_FULL_TREE) +SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -I${CMAKE_SOURCE_DIR} -I${CMAKE_SOURCE_DIR}/libbbfdm-api/ -I${CMAKE_SOURCE_DIR}/libbbfdm-ubus/") FILE(GLOB BBF_SOURCES *.c) ADD_EXECUTABLE(bbfdmd ${BBF_SOURCES}) -TARGET_LINK_LIBRARIES(bbfdmd ubus ubox blobmsg_json dl bbfdm-api) +TARGET_LINK_LIBRARIES(bbfdmd bbfdm-ubus) INSTALL(TARGETS bbfdmd DESTINATION usr/sbin) diff --git a/bbfdmd/ubus/bbfdmd.c b/bbfdmd/ubus/bbfdmd.c index 7607ae6eb2c2d8cba15fe3feb3c117773b566294..23d8977066cf5bd6181fc144b82a22566c9fdf05 100644 --- a/bbfdmd/ubus/bbfdmd.c +++ b/bbfdmd/ubus/bbfdmd.c @@ -1,7 +1,7 @@ /* * bbfdmd.c: BBFDMD deamon * - * Copyright (C) 2023 IOPSYS Software Solutions AB. All rights reserved. + * Copyright (C) 2023-2024 IOPSYS Software Solutions AB. All rights reserved. * * Author: Vivek Dutta <vivek.dutta@iopsys.eu> * Author: Amin Ben Romdhane <amin.benromdhane@iopsys.eu> @@ -9,1237 +9,25 @@ * See LICENSE file for license related information. */ -#include <stdio.h> -#include <unistd.h> -#include <stdlib.h> -#include <libubox/blobmsg.h> -#include <libubox/uloop.h> -#include <libubus.h> #include <sys/prctl.h> -#include <sys/mman.h> -#include "bbfdmd.h" -#include "set.h" -#include "get.h" -#include "get_helper.h" -#include "operate.h" -#include "add_delete.h" -#include "events.h" -#include "pretty_print.h" -#include "get_helper.h" -#include "plugin.h" +#include "common.h" +#include "bbfdm-ubus.h" #include "cli.h" -#ifndef DAEMON_JSON_INPUT -#define BBFDM_JSON_INPUT "/tmp/bbfdm/input.json" -#else -#define BBFDM_JSON_INPUT DAEMON_JSON_INPUT -#endif - -#define BBFDM_DEFAULT_MODULES_PATH "/usr/share/bbfdm" -#define BBFDM_DEFAULT_PLUGINS_PATH BBFDM_DEFAULT_MODULES_PATH"/plugins" -#define BBFDM_DEFAULT_MICROSERVICE_MODULE_PATH BBFDM_DEFAULT_MODULES_PATH"/micro_services" -#define BBFDM_DEFAULT_MICROSERVICE_INPUT_PATH "/etc/bbfdm/micro_services" -#define BBFDM_DEFAULT_UBUS_OBJ "bbfdm" -#define BBFDM_DEFAULT_DEBUG_LEVEL LOG_ERR - -extern struct list_head loaded_json_files; -extern struct list_head json_list; -extern struct list_head json_memhead; - -// micro-services should not use fork by default -#define BBF_SUBPROCESS_DEPTH (0) - -LIST_HEAD(head_registered_service); - -static void run_schema_updater(struct bbfdm_context *u); -static void periodic_instance_updater(struct uloop_timeout *t); - -// Global variables -static void *deamon_lib_handle = NULL; - -static void sig_handler(int sig) -{ - if (sig == SIGSEGV) { - handle_pending_signal(sig); - } -} - -static void signal_init(void) -{ - signal(SIGSEGV, sig_handler); -} - -static void usage(char *prog) -{ - fprintf(stderr, "Usage: %s [options]\n", prog); - fprintf(stderr, "\n"); - fprintf(stderr, "options:\n"); - fprintf(stderr, " -s <socket path> ubus socket\n"); - fprintf(stderr, " -m <json path> json input configuration for micro services\n"); - fprintf(stderr, " -c <command input> Run cli command\n"); - fprintf(stderr, " -h Displays this help\n"); - fprintf(stderr, "\n"); -} - -static void bbfdm_cleanup(struct bbfdm_context *u) -{ - bbf_global_clean(DEAMON_DM_ROOT_OBJ); - - free_path_list(&u->instances); - free_path_list(&u->old_instances); - if (!is_micro_service) { // It's not a micro-service instance - free_services_from_list(&head_registered_service); - } - - /* DotSo Plugin */ - free_dotso_plugin(deamon_lib_handle); - deamon_lib_handle = NULL; - - /* JSON Plugin */ - free_json_plugin(); -} - -static bool is_sync_operate_cmd(bbfdm_data_t *data __attribute__((unused))) -{ - return false; -} - -static bool is_subprocess_required(int subprocess_level, const char *path) -{ - bool ret = false; - size_t len = DM_STRLEN(path); - if (len == 0) - return ret; - - if (count_delim(path) < subprocess_level) { - if (path[len - 1] == '.') - ret = true; - } - - return ret; -} - -static void fill_optional_data(bbfdm_data_t *data, struct blob_attr *msg) -{ - struct blob_attr *attr; - size_t rem; - - if (!data || !msg) - return; - - blobmsg_for_each_attr(attr, msg, rem) { - - if (is_str_eq(blobmsg_name(attr), "proto")) { - const char *val = blobmsg_get_string(attr); - data->bbf_ctx.dm_type = get_proto_type(val); - } - - if (is_str_eq(blobmsg_name(attr), "format")) - data->is_raw = is_str_eq(blobmsg_get_string(attr), "raw") ? true : false; - } - - char *proto = (data->bbf_ctx.dm_type == BBFDM_BOTH) ? "both" : (data->bbf_ctx.dm_type == BBFDM_CWMP) ? "cwmp" : "usp"; - DEBUG("Proto:|%s|, is_raw:|%d|", proto, data->is_raw); -} - -static void async_req_free(struct bbfdm_async_req *r) -{ - free(r); -} - -static void async_complete_cb(struct uloop_process *p, __attribute__((unused)) int ret) -{ - struct bbfdm_async_req *r = container_of(p, struct bbfdm_async_req, process); - - if (r) { - INFO("Async call with pid(%d) completes", r->process.pid); - struct blob_buf *bb = (struct blob_buf *)&r->result; - - ubus_send_reply(r->ctx, &r->req, bb->head); - INFO("pid(%d) blob data sent raw(%d)", r->process.pid, blob_raw_len(bb->head)); - ubus_complete_deferred_request(r->ctx, &r->req, 0); - if (r->is_operate) { - register_instance_refresh_timer(r->ctx, 0); - } - munmap(r->result, DEF_IPC_DATA_LEN); - async_req_free(r); - } - -} - -static struct bbfdm_async_req *async_req_new(void) -{ - struct bbfdm_async_req *r = malloc(sizeof(*r)); - - if (r) { - memset(&r->process, 0, sizeof(r->process)); - r->result = NULL; - } - - return r; -} - -static int bbfdm_start_deferred(bbfdm_data_t *data, void (*EXEC_CB)(bbfdm_data_t *data, void *d), bool is_operate) -{ - struct bbfdm_async_req *r = NULL; - pid_t child; - struct bbfdm_context *u; - void *result = NULL; - - result = mmap(NULL, DEF_IPC_DATA_LEN, PROT_READ| PROT_WRITE, MAP_SHARED|MAP_ANONYMOUS, -1, 0); - if (result == MAP_FAILED) { - ERR("Error creating memory map for result"); - goto err_out; - } - memset(result, 0, DEF_IPC_DATA_LEN); - r = async_req_new(); - if (r == NULL) { - ERR("Error allocating async req"); - goto err_out; - } - - child = fork(); - if (child == -1) { - ERR("fork error"); - goto err_out; - } else if (child == 0) { - u = container_of(data->ctx, struct bbfdm_context, ubus_ctx); - if (u == NULL) { - ERR("{fork} Failed to get the bbfdm context"); - exit(EXIT_FAILURE); - } - - // child initialise signal to prevent segfaults - signal_init(); - /* free fd's and memory inherited from parent */ - uloop_done(); - ubus_shutdown(data->ctx); - async_req_free(r); - fclose(stdin); - fclose(stdout); - fclose(stderr); - - INFO("{fork} Calling from subprocess"); - EXEC_CB(data, result); - - bbfdm_cleanup(u); - closelog(); - /* write result and exit */ - exit(EXIT_SUCCESS); - } - - // parent - INFO("Creating bbfdm(%d) sub process(%d) for path(%s)", getpid(), child, data->bbf_ctx.in_param); - r->result = result; - r->ctx = data->ctx; - r->process.pid = child; - r->process.cb = async_complete_cb; - r->is_operate = is_operate; - uloop_process_add(&r->process); - ubus_defer_request(data->ctx, data->req, &r->req); - return 0; - -err_out: - if (r) - async_req_free(r); - - if (result) - munmap(result, DEF_IPC_DATA_LEN); - - return UBUS_STATUS_UNKNOWN_ERROR; -} - -static bool is_object_schema_update_available(struct bbfdm_context *u) -{ - bool ret = false; - LIST_HEAD(paths_list); - bbfdm_data_t data = { - .ctx = 0, - .req = 0, - .is_raw = true, - .plist = &paths_list, - .bbf_ctx.nextlevel = false, - .bbf_ctx.iscommand = true, - .bbf_ctx.isevent = true, - .bbf_ctx.isinfo = true, - .bbf_ctx.dm_type = BBFDM_USP - }; - - int old_schema_len = u->schema_len; - - // If new parameter gets added it would be a minimum tuple of three params - int min_len = 100; - - add_path_list(ROOT_NODE, &paths_list); - int new_schema_len = bbfdm_get_supported_dm(&data); - if (new_schema_len == 0) { - WARNING("Failed to get schema"); - free_path_list(&paths_list); - return ret; - } - - if (new_schema_len - old_schema_len > min_len) { - DEBUG("DM Schema update available old:new[%zd:%zd]", old_schema_len, new_schema_len); - if (old_schema_len != 0) { - ret = true; - } - } - - free_path_list(&paths_list); - - return ret; -} - -static const struct blobmsg_policy dm_get_policy[] = { - [DM_GET_PATH] = { .name = "path", .type = BLOBMSG_TYPE_STRING }, - [DM_GET_PATHS] = { .name = "paths", .type = BLOBMSG_TYPE_ARRAY }, - [DM_GET_MAXDEPTH] = { .name = "maxdepth", .type = BLOBMSG_TYPE_INT32 }, - [DM_GET_OPTIONAL] = { .name = "optional", .type = BLOBMSG_TYPE_TABLE}, -}; - -static int bbfdm_get_handler(struct ubus_context *ctx, struct ubus_object *obj __attribute__((unused)), - struct ubus_request_data *req, const char *method __attribute__((unused)), - struct blob_attr *msg) -{ - struct blob_attr *tb[__DM_GET_MAX]; - LIST_HEAD(paths_list); - bbfdm_data_t data; - uint8_t maxdepth = 0; - bool is_subprocess_needed = false; - struct bbfdm_context *u; - - u = container_of(ctx, struct bbfdm_context, ubus_ctx); - if (u == NULL) { - ERR("Failed to get the bbfdm context"); - return UBUS_STATUS_UNKNOWN_ERROR; - } - - memset(&data, 0, sizeof(bbfdm_data_t)); - - if (blobmsg_parse(dm_get_policy, __DM_GET_MAX, tb, blob_data(msg), blob_len(msg))) { - ERR("Failed to parse blob"); - return UBUS_STATUS_UNKNOWN_ERROR; - } - - if (!(tb[DM_GET_PATH]) && !(tb[DM_GET_PATHS])) - return UBUS_STATUS_INVALID_ARGUMENT; - - if (tb[DM_GET_PATH]) { - char *path = blobmsg_get_string(tb[DM_GET_PATH]); - add_path_list(path, &paths_list); - is_subprocess_needed = is_subprocess_required(u->config.subprocess_level, path); - } - - if (tb[DM_GET_PATHS]) { - struct blob_attr *paths = tb[DM_GET_PATHS]; - struct blob_attr *path = NULL; - size_t rem; - - blobmsg_for_each_attr(path, paths, rem) { - char *path_str = blobmsg_get_string(path); - - add_path_list(path_str, &paths_list); - if (!is_subprocess_needed) - is_subprocess_needed = is_subprocess_required(u->config.subprocess_level, path_str); - } - } - - if (tb[DM_GET_MAXDEPTH]) - maxdepth = blobmsg_get_u32(tb[DM_GET_MAXDEPTH]); - - data.ctx = ctx; - data.req = req; - data.plist = &paths_list; - data.depth = maxdepth; - - fill_optional_data(&data, tb[DM_GET_OPTIONAL]); - - if (is_subprocess_needed) { - INFO("Creating subprocess for get method"); - bbfdm_start_deferred(&data, bbfdm_get_value, false); - } else { - bbfdm_get_value(&data, NULL); - } - - free_path_list(&paths_list); - return 0; -} - -static const struct blobmsg_policy dm_schema_policy[] = { - [DM_SCHEMA_PATH] = { .name = "path", .type = BLOBMSG_TYPE_STRING }, - [DM_SCHEMA_PATHS] = { .name = "paths", .type = BLOBMSG_TYPE_ARRAY }, - [DM_SCHEMA_FIRST_LEVEL] = { .name = "first_level", .type = BLOBMSG_TYPE_BOOL}, - [DM_SCHEMA_OPTIONAL] = { .name = "optional", .type = BLOBMSG_TYPE_TABLE}, -}; - -static int bbfdm_schema_handler(struct ubus_context *ctx, struct ubus_object *obj __attribute__((unused)), - struct ubus_request_data *req, const char *method __attribute__((unused)), - struct blob_attr *msg) -{ - struct blob_attr *tb[__DM_SCHEMA_MAX]; - LIST_HEAD(paths_list); - bbfdm_data_t data; - struct bbfdm_context *u; - - u = container_of(ctx, struct bbfdm_context, ubus_ctx); - if (u == NULL) { - ERR("Failed to get the bbfdm context"); - return UBUS_STATUS_UNKNOWN_ERROR; - } - - memset(&data, 0, sizeof(bbfdm_data_t)); - - if (blobmsg_parse(dm_schema_policy, __DM_SCHEMA_MAX, tb, blob_data(msg), blob_len(msg))) { - ERR("Failed to parse blob"); - return UBUS_STATUS_UNKNOWN_ERROR; - } - - if (!(tb[DM_SCHEMA_PATH]) && !(tb[DM_SCHEMA_PATHS])) - return UBUS_STATUS_INVALID_ARGUMENT; - - if (tb[DM_SCHEMA_PATH]) { - char *path = blobmsg_get_string(tb[DM_SCHEMA_PATH]); - - add_path_list(path, &paths_list); - } - - if (tb[DM_SCHEMA_PATHS]) { - struct blob_attr *paths = tb[DM_GET_PATHS]; - struct blob_attr *path = NULL; - size_t rem; - - blobmsg_for_each_attr(path, paths, rem) { - char *path_str = blobmsg_get_string(path); - - add_path_list(path_str, &paths_list); - } - } - - fill_optional_data(&data, tb[DM_SCHEMA_OPTIONAL]); - - unsigned int dm_type = data.bbf_ctx.dm_type; - - data.ctx = ctx; - data.req = req; - data.bbf_ctx.nextlevel = (tb[DM_SCHEMA_FIRST_LEVEL]) ? blobmsg_get_bool(tb[DM_SCHEMA_FIRST_LEVEL]) : false; - data.bbf_ctx.iscommand = (dm_type == BBFDM_CWMP) ? false : true; - data.bbf_ctx.isevent = (dm_type == BBFDM_CWMP) ? false : true; - data.bbf_ctx.isinfo = (dm_type == BBFDM_CWMP) ? false : true; - data.plist = &paths_list; - -#ifdef BBF_SCHEMA_FULL_TREE - data.bbf_ctx.isinfo = true; - bbfdm_get_supported_dm(&data); -#else - if (dm_type == BBFDM_CWMP) - bbfdm_get_names(&data); - else - bbfdm_get_supported_dm(&data); -#endif - - free_path_list(&paths_list); - return 0; -} - -static const struct blobmsg_policy dm_instances_policy[] = { - [DM_INSTANCES_PATH] = { .name = "path", .type = BLOBMSG_TYPE_STRING }, - [DM_INSTANCES_PATHS] = { .name = "paths", .type = BLOBMSG_TYPE_ARRAY }, - [DM_INSTANCES_FIRST_LEVEL] = { .name = "first_level", .type = BLOBMSG_TYPE_BOOL }, - [DM_INSTANCES_OPTIONAL] = { .name = "optional", .type = BLOBMSG_TYPE_TABLE }, -}; - -static int bbfdm_instances_handler(struct ubus_context *ctx, struct ubus_object *obj __attribute__((unused)), - struct ubus_request_data *req, const char *method __attribute__((unused)), - struct blob_attr *msg) -{ - struct blob_attr *tb[__DM_INSTANCES_MAX]; - LIST_HEAD(paths_list); - bbfdm_data_t data; - - memset(&data, 0, sizeof(bbfdm_data_t)); - - if (blobmsg_parse(dm_instances_policy, __DM_INSTANCES_MAX, tb, blob_data(msg), blob_len(msg))) { - ERR("Failed to parse blob"); - return UBUS_STATUS_UNKNOWN_ERROR; - } - - if (!(tb[DM_INSTANCES_PATH]) && !(tb[DM_INSTANCES_PATHS])) - return UBUS_STATUS_INVALID_ARGUMENT; - - if (tb[DM_INSTANCES_PATH]) { - char *path = blobmsg_get_string(tb[DM_INSTANCES_PATH]); - add_path_list(path, &paths_list); - } - - if (tb[DM_INSTANCES_PATHS]) { - struct blob_attr *paths = tb[DM_INSTANCES_PATHS]; - struct blob_attr *path = NULL; - size_t rem; - - blobmsg_for_each_attr(path, paths, rem) { - char *path_str = blobmsg_get_string(path); - - add_path_list(path_str, &paths_list); - } - } - - data.ctx = ctx; - data.req = req; - data.bbf_ctx.nextlevel = (tb[DM_INSTANCES_FIRST_LEVEL]) ? blobmsg_get_bool(tb[DM_INSTANCES_FIRST_LEVEL]) : false; - data.plist = &paths_list; - - fill_optional_data(&data, tb[DM_INSTANCES_OPTIONAL]); - - bbfdm_get_instances(&data); - - free_path_list(&paths_list); - return 0; -} - -static const struct blobmsg_policy dm_set_policy[] = { - [DM_SET_PATH] = { .name = "path", .type = BLOBMSG_TYPE_STRING }, - [DM_SET_VALUE] = { .name = "value", .type = BLOBMSG_TYPE_STRING }, - [DM_SET_OBJ_PATH] = { .name = "obj_path", .type = BLOBMSG_TYPE_TABLE }, - [DM_SET_OPTIONAL] = { .name = "optional", .type = BLOBMSG_TYPE_TABLE }, -}; - -int bbfdm_set_handler(struct ubus_context *ctx, struct ubus_object *obj, - struct ubus_request_data *req, const char *method, - struct blob_attr *msg) -{ - struct blob_attr *tb[__DM_SET_MAX] = {NULL}; - char path[PATH_MAX] = {'\0'}; - bbfdm_data_t data; - int fault = 0; - LIST_HEAD(pv_list); - - memset(&data, 0, sizeof(bbfdm_data_t)); - - if (blobmsg_parse(dm_set_policy, __DM_SET_MAX, tb, blob_data(msg), blob_len(msg))) { - ERR("Failed to parse blob"); - return UBUS_STATUS_UNKNOWN_ERROR; - } - - if (!tb[DM_SET_PATH]) - return UBUS_STATUS_INVALID_ARGUMENT; - - if (!tb[DM_SET_VALUE] && !tb[DM_SET_OBJ_PATH]) - return UBUS_STATUS_INVALID_ARGUMENT; - - snprintf(path, PATH_MAX, "%s", (char *)blobmsg_data(tb[DM_SET_PATH])); - - fill_optional_data(&data, tb[DM_SET_OPTIONAL]); - - INFO("ubus method|%s|, name|%s|, path(%s)", method, obj->name, path); - - blob_buf_init(&data.bb, 0); - bbf_init(&data.bbf_ctx); - - data.ctx = ctx; - data.bbf_ctx.in_param = path; - - fault = fill_pvlist_set(&data, path, tb[DM_SET_VALUE] ? blobmsg_get_string(tb[DM_SET_VALUE]) : NULL, tb[DM_SET_OBJ_PATH], &pv_list); - if (fault) { - ERR("Fault in fill pvlist set path |%s| : |%d|", data.bbf_ctx.in_param, fault); - fill_err_code_array(&data, fault); - goto end; - } - - if (list_empty(&pv_list)) { - ERR("Fault in fill pvlist set path |%s| : |list is empty|", data.bbf_ctx.in_param); - fill_err_code_array(&data, USP_FAULT_INTERNAL_ERROR); - fault = USP_FAULT_INTERNAL_ERROR; - goto end; - } - - data.plist = &pv_list; - - fault = bbfdm_set_value(&data); - -end: - if ((data.bbf_ctx.dm_type == BBFDM_BOTH) && (is_micro_service == false)) { - bbf_entry_services(data.bbf_ctx.dm_type, (!fault) ? true : false, true); - } - - bbf_cleanup(&data.bbf_ctx); - free_pv_list(&pv_list); - - ubus_send_reply(ctx, req, data.bb.head); - blob_buf_free(&data.bb); - - return 0; -} - -static const struct blobmsg_policy dm_operate_policy[__DM_OPERATE_MAX] = { - [DM_OPERATE_COMMAND] = { .name = "command", .type = BLOBMSG_TYPE_STRING }, - [DM_OPERATE_COMMAND_KEY] = { .name = "command_key", .type = BLOBMSG_TYPE_STRING }, - [DM_OPERATE_INPUT] = { .name = "input", .type = BLOBMSG_TYPE_TABLE }, - [DM_OPERATE_OPTIONAL] = { .name = "optional", .type = BLOBMSG_TYPE_TABLE }, -}; - -static int bbfdm_operate_handler(struct ubus_context *ctx, struct ubus_object *obj __attribute__((unused)), - struct ubus_request_data *req, const char *method __attribute__((unused)), - struct blob_attr *msg) -{ - struct blob_attr *tb[__DM_OPERATE_MAX] = {NULL}; - char path[PATH_MAX] = {0}; - char *str = NULL; - bbfdm_data_t data; - - memset(&data, 0, sizeof(bbfdm_data_t)); - - if (blobmsg_parse(dm_operate_policy, __DM_OPERATE_MAX, tb, blob_data(msg), blob_len(msg))) { - ERR("Failed to parse blob"); - return UBUS_STATUS_UNKNOWN_ERROR; - } - - if (!(tb[DM_OPERATE_COMMAND])) - return UBUS_STATUS_INVALID_ARGUMENT; - - snprintf(path, PATH_MAX, "%s", (char *)blobmsg_data(tb[DM_OPERATE_COMMAND])); - - data.ctx = ctx; - data.req = req; - data.bbf_ctx.in_param = path; - data.bbf_ctx.linker = tb[DM_OPERATE_COMMAND_KEY] ? blobmsg_get_string(tb[DM_OPERATE_COMMAND_KEY]) : ""; - - if (tb[DM_OPERATE_INPUT]) { - str = blobmsg_format_json(tb[DM_OPERATE_INPUT], true); - data.bbf_ctx.in_value = str; - } - - fill_optional_data(&data, tb[DM_OPERATE_OPTIONAL]); - - INFO("ubus method|%s|, name|%s|, path(%s)", method, obj->name, data.bbf_ctx.in_param); - - if (is_sync_operate_cmd(&data)) { - bbfdm_operate_cmd(&data, NULL); - } else { - cancel_instance_refresh_timer(ctx); - bbfdm_start_deferred(&data, bbfdm_operate_cmd, true); - } - - FREE(str); - return 0; -} - -static const struct blobmsg_policy dm_add_policy[] = { - [DM_ADD_PATH] = { .name = "path", .type = BLOBMSG_TYPE_STRING }, - [DM_ADD_OBJ_PATH] = { .name = "obj_path", .type = BLOBMSG_TYPE_TABLE }, - [DM_ADD_OPTIONAL] = { .name = "optional", .type = BLOBMSG_TYPE_TABLE }, -}; - -int bbfdm_add_handler(struct ubus_context *ctx, struct ubus_object *obj, - struct ubus_request_data *req, const char *method, - struct blob_attr *msg) -{ - struct blob_attr *tb[__DM_ADD_MAX]; - char path[PATH_MAX]; - bbfdm_data_t data; - int fault = 0; - - memset(&data, 0, sizeof(bbfdm_data_t)); - - if (blobmsg_parse(dm_add_policy, __DM_ADD_MAX, tb, blob_data(msg), blob_len(msg))) { - ERR("Failed to parse blob"); - return UBUS_STATUS_UNKNOWN_ERROR; - } - - if (!tb[DM_ADD_PATH]) - return UBUS_STATUS_INVALID_ARGUMENT; - - snprintf(path, PATH_MAX, "%s", (char *)blobmsg_data(tb[DM_ADD_PATH])); - - data.ctx = ctx; - data.bbf_ctx.in_param = path; - - fill_optional_data(&data, tb[DM_ADD_OPTIONAL]); - - INFO("ubus method|%s|, name|%s|, path(%s)", method, obj->name, data.bbf_ctx.in_param); - - blob_buf_init(&data.bb, 0); - bbf_init(&data.bbf_ctx); - - fault = create_add_response(&data); - if (fault) { - ERR("Fault in add path |%s|", data.bbf_ctx.in_param); - goto end; - } - - if (tb[DM_ADD_OBJ_PATH]) { - LIST_HEAD(pv_list); - - snprintf(path, PATH_MAX, "%s%s.", (char *)blobmsg_data(tb[DM_ADD_PATH]), data.bbf_ctx.addobj_instance); - - fault = fill_pvlist_set(&data, path, NULL, tb[DM_ADD_OBJ_PATH], &pv_list); - if (fault) { - ERR("Fault in fill pvlist set path |%s|", path); - fill_err_code_array(&data, USP_FAULT_INTERNAL_ERROR); - free_pv_list(&pv_list); - goto end; - } - - data.plist = &pv_list; - - bbfdm_set_value(&data); - - free_pv_list(&pv_list); - } - -end: - if ((data.bbf_ctx.dm_type == BBFDM_BOTH) && (is_micro_service == false)) { - bbf_entry_services(data.bbf_ctx.dm_type, (!fault) ? true : false, false); - } - - bbf_cleanup(&data.bbf_ctx); - - ubus_send_reply(ctx, req, data.bb.head); - blob_buf_free(&data.bb); - - return 0; -} - -static const struct blobmsg_policy dm_del_policy[] = { - [DM_DEL_PATH] = { .name = "path", .type = BLOBMSG_TYPE_STRING }, - [DM_DEL_PATHS] = { .name = "paths", .type = BLOBMSG_TYPE_ARRAY }, - [DM_DEL_OPTIONAL] = { .name = "optional", .type = BLOBMSG_TYPE_TABLE }, -}; - -int bbfdm_del_handler(struct ubus_context *ctx, struct ubus_object *obj, - struct ubus_request_data *req, const char *method, - struct blob_attr *msg) -{ - struct blob_attr *tb[__DM_DEL_MAX]; - LIST_HEAD(paths_list); - bbfdm_data_t data; - int fault = 0; - - memset(&data, 0, sizeof(bbfdm_data_t)); - - if (blobmsg_parse(dm_del_policy, __DM_DEL_MAX, tb, blob_data(msg), blob_len(msg))) { - ERR("Failed to parse blob"); - return UBUS_STATUS_UNKNOWN_ERROR; - } - - if (!tb[DM_DEL_PATH] && !tb[DM_DEL_PATHS]) - return UBUS_STATUS_INVALID_ARGUMENT; - - if (tb[DM_DEL_PATH]) { - char *path = blobmsg_get_string(tb[DM_DEL_PATH]); - add_path_list(path, &paths_list); - } - - if (tb[DM_DEL_PATHS]) { - struct blob_attr *paths = tb[DM_DEL_PATHS]; - struct blob_attr *path = NULL; - size_t rem; - - blobmsg_for_each_attr(path, paths, rem) { - char *path_str = blobmsg_get_string(path); - - add_path_list(path_str, &paths_list); - } - } - - data.ctx = ctx; - data.plist = &paths_list; - - fill_optional_data(&data, tb[DM_DEL_OPTIONAL]); - - INFO("ubus method|%s|, name|%s|", method, obj->name); - - blob_buf_init(&data.bb, 0); - bbf_init(&data.bbf_ctx); - - data.bbf_ctx.in_param = tb[DM_DEL_PATH] ? blobmsg_get_string(tb[DM_DEL_PATH]) : ""; - - fault = create_del_response(&data); - - if ((data.bbf_ctx.dm_type == BBFDM_BOTH) && (is_micro_service == false)) { - bbf_entry_services(data.bbf_ctx.dm_type, (!fault) ? true : false, true); - } - - bbf_cleanup(&data.bbf_ctx); - free_path_list(&paths_list); - - ubus_send_reply(ctx, req, data.bb.head); - blob_buf_free(&data.bb); - - return 0; -} - -enum { - BBF_SERVICE_CMD, - BBF_SERVICE_NAME, - BBF_SERVICE_PARENT_DM, - BBF_SERVICE_OBJECTS, - __BBF_SERVICE_MAX, -}; - -static const struct blobmsg_policy service_policy[] = { - [BBF_SERVICE_CMD] = { .name = "cmd", .type = BLOBMSG_TYPE_STRING }, - [BBF_SERVICE_NAME] = { .name = "name", .type = BLOBMSG_TYPE_STRING }, - [BBF_SERVICE_PARENT_DM] = { .name = "parent_dm", .type = BLOBMSG_TYPE_STRING }, - [BBF_SERVICE_OBJECTS] = { .name = "objects", .type = BLOBMSG_TYPE_ARRAY }, -}; - -static void service_list(struct blob_buf *bb) -{ - void *array; - - array = blobmsg_open_array(bb, "supported_cmd"); - blobmsg_add_string(bb, NULL, "register"); - blobmsg_add_string(bb, NULL, "list"); - blobmsg_close_array(bb, array); - - array = blobmsg_open_array(bb, "registered_service"); - get_list_of_registered_service(&head_registered_service, bb); - blobmsg_close_array(bb, array); -} - -static int bbfdm_service_handler(struct ubus_context *ctx, struct ubus_object *obj, - struct ubus_request_data *req __attribute__((unused)), const char *method, - struct blob_attr *msg) -{ - struct blob_attr *tb[__BBF_SERVICE_MAX] = {NULL}; - struct blob_buf bb; - struct bbfdm_context *u; - - u = container_of(ctx, struct bbfdm_context, ubus_ctx); - if (u == NULL) { - ERR("Failed to get the bbfdm context"); - return 0; - } - - memset(&bb, 0, sizeof(struct blob_buf)); - blob_buf_init(&bb, 0); - - if (blobmsg_parse(service_policy, __BBF_SERVICE_MAX, tb, blob_data(msg), blob_len(msg))) { - service_list(&bb); - goto end; - } - - INFO("ubus method|%s|, name|%s|", method, obj->name); - - if (is_micro_service) { // It's a micro-service instance - blobmsg_add_string(&bb, "error", "Its not allowed to register a micro-service for another micro-service!!"); - goto end; - } - - if (!tb[BBF_SERVICE_CMD]) { - service_list(&bb); - goto end; - } - - char *srv_cmd = blobmsg_get_string(tb[BBF_SERVICE_CMD]); - - if (is_str_eq(srv_cmd, "register")) { - - if (!tb[BBF_SERVICE_NAME]) { - blobmsg_add_string(&bb, "error", "service name should be defined!!"); - goto end; - } - - if (!tb[BBF_SERVICE_PARENT_DM]) { - blobmsg_add_string(&bb, "error", "service parent dm should be defined!!"); - goto end; - } - - if (!tb[BBF_SERVICE_OBJECTS]) { - blobmsg_add_string(&bb, "error", "service objects should be defined!!"); - goto end; - } - - char *srv_name = blobmsg_get_string(tb[BBF_SERVICE_NAME]); - char *srv_parent_dm = blobmsg_get_string(tb[BBF_SERVICE_PARENT_DM]); - bool res = true; - - if (tb[BBF_SERVICE_OBJECTS]) { - struct blob_attr *objs = tb[BBF_SERVICE_OBJECTS]; - struct blob_attr *attr_obj = NULL; - size_t rem; - - blobmsg_for_each_attr(attr_obj, objs, rem) { - char *srv_obj = blobmsg_get_string(attr_obj); - res |= load_service(DEAMON_DM_ROOT_OBJ, &head_registered_service, srv_name, srv_parent_dm, srv_obj); - } - } else { - res = false; - } - - blobmsg_add_u8(&bb, "status", res); - run_schema_updater(u); - } else { - service_list(&bb); - } - -end: - ubus_send_reply(ctx, req, bb.head); - blob_buf_free(&bb); - - return 0; -} - -enum { - BBF_NOTIFY_NAME, - BBF_NOTIFY_PRAMS, - __BBF_NOTIFY_MAX, -}; - -static const struct blobmsg_policy dm_notify_event_policy[] = { - [BBF_NOTIFY_NAME] = { .name = "name", .type = BLOBMSG_TYPE_STRING }, - [BBF_NOTIFY_PRAMS] = { .name = "input", .type = BLOBMSG_TYPE_ARRAY }, -}; - -static int bbfdm_notify_event(struct ubus_context *ctx, struct ubus_object *obj, - struct ubus_request_data *req __attribute__((unused)), const char *method, - struct blob_attr *msg) -{ - struct blob_attr *tb[__BBF_NOTIFY_MAX] = {NULL}; - char method_name[256] = {0}; - struct bbfdm_context *u; - - u = container_of(ctx, struct bbfdm_context, ubus_ctx); - if (u == NULL) { - ERR("failed to get the bbfdm context"); - return UBUS_STATUS_UNKNOWN_ERROR; - } - - if (blobmsg_parse(dm_notify_event_policy, __BBF_NOTIFY_MAX, tb, blob_data(msg), blob_len(msg))) { - ERR("Failed to parse blob"); - return UBUS_STATUS_UNKNOWN_ERROR; - } - - if (!tb[BBF_NOTIFY_NAME]) - return UBUS_STATUS_INVALID_ARGUMENT; - - INFO("ubus method|%s|, name|%s|", method, obj->name); - snprintf(method_name, sizeof(method_name), "%s.%s", DM_STRLEN(u->config.out_root_obj) ? u->config.out_root_obj : u->config.out_name, BBF_EVENT_NAME); - ubus_send_event(ctx, method_name, msg); - - return 0; -} - -static struct ubus_method bbf_methods[] = { - UBUS_METHOD("get", bbfdm_get_handler, dm_get_policy), - UBUS_METHOD("schema", bbfdm_schema_handler, dm_schema_policy), - UBUS_METHOD("instances", bbfdm_instances_handler, dm_instances_policy), - UBUS_METHOD("set", bbfdm_set_handler, dm_set_policy), - UBUS_METHOD("operate", bbfdm_operate_handler, dm_operate_policy), - UBUS_METHOD("add", bbfdm_add_handler, dm_add_policy), - UBUS_METHOD("del", bbfdm_del_handler, dm_del_policy), - UBUS_METHOD("service", bbfdm_service_handler, service_policy), - UBUS_METHOD("notify_event", bbfdm_notify_event, dm_notify_event_policy), -}; - -static struct ubus_object_type bbf_type = UBUS_OBJECT_TYPE("", bbf_methods); - -static struct ubus_object bbf_object = { - .name = "", - .type = &bbf_type, - .methods = bbf_methods, - .n_methods = ARRAY_SIZE(bbf_methods) -}; - -static void run_schema_updater(struct bbfdm_context *u) -{ - bool ret; - char method_name[256] = {0}; - - ret = is_object_schema_update_available(u); - if (ret && (is_micro_service == false)) { - struct blob_buf bb; - - memset(&bb, 0, sizeof(struct blob_buf)); - INFO("Schema update available"); - snprintf(method_name, sizeof(method_name), "%s.%s", u->config.out_name, BBF_UPDATE_SCHEMA_EVENT); - blob_buf_init(&bb, 0); - ubus_send_event(&u->ubus_ctx, method_name, bb.head); - blob_buf_free(&bb); - } -} - -static void broadcast_add_del_event(struct ubus_context *ctx, const char *method, struct list_head *inst, bool is_add) -{ - struct blob_buf bb; - struct pathNode *ptr; - char method_name[40]; - void *a; - - if (list_empty(inst)) { - return; - } - - memset(&bb, 0, sizeof(struct blob_buf)); - blob_buf_init(&bb, 0); - - a = blobmsg_open_array(&bb, "instances"); - list_for_each_entry(ptr, inst, list) { - blobmsg_add_string(&bb, NULL, ptr->path); - DEBUG("#%s:: %s, method %s #", (is_add)?"Add":"Del", ptr->path, method); - } - blobmsg_close_array(&bb, a); - - snprintf(method_name, sizeof(method_name), "%s.%s", method, is_add ? BBF_ADD_EVENT : BBF_DEL_EVENT); - - if (is_add) - ubus_send_event(ctx, method_name, bb.head); - else - ubus_send_event(ctx, method_name, bb.head); - - blob_buf_free(&bb); -} - -static void update_instances_list(struct list_head *inst) -{ - int ret; - struct dmctx bbf_ctx = { - .in_param = ROOT_NODE, - .nextlevel = false, - .disable_mservice_browse = true, - .dm_type = BBFDM_BOTH - }; - - bbf_init(&bbf_ctx); - - ret = bbfdm_cmd_exec(&bbf_ctx, BBF_INSTANCES); - if (ret == 0) { - struct blob_attr *cur = NULL; - size_t rem = 0; - - // Apply all bbfdm changes - dmuci_commit_bbfdm(); - - blobmsg_for_each_attr(cur, bbf_ctx.bb.head, rem) { - struct blob_attr *tb[1] = {0}; - const struct blobmsg_policy p[1] = { - { "path", BLOBMSG_TYPE_STRING } - }; - - blobmsg_parse(p, 1, tb, blobmsg_data(cur), blobmsg_len(cur)); - - char *name = (tb[0]) ? blobmsg_get_string(tb[0]) : ""; - - add_path_list(name, inst); - } - } else { - WARNING("Failed to get instances, err code %d", ret); - } - - bbf_cleanup(&bbf_ctx); -} - -static void instance_compare_publish(struct bbfdm_context *daemon_ctx) -{ - struct pathNode *ptr; - LIST_HEAD(inst_list); - struct list_head *new_inst, *old_inst; - const char *method; - - new_inst = &daemon_ctx->instances; - old_inst = &daemon_ctx->old_instances; - - method = DM_STRLEN(daemon_ctx->config.out_root_obj) ? daemon_ctx->config.out_root_obj : daemon_ctx->config.out_name; - list_for_each_entry(ptr, old_inst, list) { - if (!present_in_path_list(new_inst, ptr->path)) { - add_path_list(ptr->path, &inst_list); - } - } - broadcast_add_del_event(&daemon_ctx->ubus_ctx, method, &inst_list, false); - free_path_list(&inst_list); - - list_for_each_entry(ptr, new_inst, list) { - if (!present_in_path_list(old_inst, ptr->path)) { - add_path_list(ptr->path, &inst_list); - } - } - broadcast_add_del_event(&daemon_ctx->ubus_ctx, method, &inst_list, true); - free_path_list(&inst_list); -} - -static void periodic_instance_updater(struct uloop_timeout *t) -{ - struct bbfdm_context *u; - - u = container_of(t, struct bbfdm_context, instance_timer); - if (u == NULL) { - ERR("Failed to get the bbfdm context"); - return; - } - - if (list_empty(&u->instances)) { - if (!list_empty(&u->old_instances)) { - list_splice_init(&u->old_instances, &u->instances); - } else { - update_instances_list(&u->instances); - return; - } - } - - free_path_list(&u->old_instances); - list_splice_init(&u->instances, &u->old_instances); - - update_instances_list(&u->instances); - if (!list_empty(&u->instances) && !list_empty(&u->old_instances)) { - INFO("Comparing instances ..."); - instance_compare_publish(u); - } -} - -static bool register_service(struct ubus_context *ctx) -{ - struct blob_buf bb = {0}; - uint32_t ubus_id; - struct bbfdm_context *u; - - u = container_of(ctx, struct bbfdm_context, ubus_ctx); - if (u == NULL) { - ERR("failed to get the bbfdm context"); - return false; - } - // check if object already present - int ret = ubus_lookup_id(ctx, u->config.out_root_obj, &ubus_id); - if (ret != 0) - return false; - - memset(&bb, 0, sizeof(struct blob_buf)); - blob_buf_init(&bb, 0); - - blobmsg_add_string(&bb, "cmd", "register"); - blobmsg_add_string(&bb, "name", u->config.out_name); - blobmsg_add_string(&bb, "parent_dm", u->config.out_parent_dm); - - void *arr = blobmsg_open_array(&bb, "objects"); - for (int i = 0; i < MAX_OBJS && DM_STRLEN(u->config.out_objects[i]) != 0; i++) - blobmsg_add_string(&bb, NULL, u->config.out_objects[i]); - blobmsg_close_array(&bb, arr); - - ubus_invoke(ctx, ubus_id, "service", bb.head, NULL, NULL, 5000); - blob_buf_free(&bb); - - return true; -} - -static int _parse_daemon_config_options(bbfdm_config_t *config, json_object *daemon_obj) -{ - char *opt_val = NULL; - - if (!config || !daemon_obj) { - fprintf(stderr, "Invalid input options \n"); - return -1; - } - - opt_val = dmjson_get_value(daemon_obj, 2, "config", "loglevel"); - if (DM_STRLEN(opt_val)) { - config->log_level = (uint8_t) strtoul(opt_val, NULL, 10); - set_debug_level(config->log_level); - } else { - set_debug_level(BBFDM_DEFAULT_DEBUG_LEVEL); - } - - opt_val = dmjson_get_value(daemon_obj, 2, "config", "subprocess_level"); - if (DM_STRLEN(opt_val)) { - config->subprocess_level = (unsigned int) strtoul(opt_val, NULL, 10); - } else { - config->subprocess_level = BBF_SUBPROCESS_DEPTH; - } - return 0; -} - -static int _parse_daemon_input_options(bbfdm_config_t *config, json_object *daemon_obj) -{ - char *opt_val = NULL; - - if (!config || !daemon_obj) { - fprintf(stderr, "Invalid input options \n"); - return -1; - } - - opt_val = dmjson_get_value(daemon_obj, 2, "input", "plugin_dir"); - if (DM_STRLEN(opt_val)) { - strncpyt(config->in_plugin_dir, opt_val, sizeof(config->in_plugin_dir)); - } else if(is_micro_service == false) { - strncpyt(config->in_plugin_dir, BBFDM_DEFAULT_PLUGINS_PATH, sizeof(config->in_plugin_dir)); - } - - opt_val = dmjson_get_value(daemon_obj, 2, "input", "name"); - if (DM_STRLEN(opt_val)) { - strncpyt(config->in_name, opt_val, sizeof(config->in_name)); - - opt_val = strrchr(opt_val, '/'); - if (opt_val) { - strncpyt(config->service_name, opt_val + 1, sizeof(config->service_name)); - } - } else if (is_micro_service == false) { // default value for main process - snprintf(config->in_name, sizeof(config->in_name), "%s/libbbfdm.so", BBFDM_DEFAULT_MODULES_PATH); - strncpyt(config->service_name, BBFDM_DEFAULT_UBUS_OBJ, sizeof(config->service_name)); - } - return 0; -} - -static int _fill_daemon_input_option(bbfdm_config_t *config, char *sname) -{ - char opt_val[MAX_DM_PATH] = {0}; - - if (!config || !sname || strlen(sname) == 0) { - fprintf(stderr, "Invalid input options for service name \n"); - return -1; - } - - strncpyt(config->service_name, sname, sizeof(config->service_name)); - - // check if the service plugin is DotSO plugin - snprintf(opt_val, MAX_DM_PATH, "%s/%s.so", BBFDM_DEFAULT_MICROSERVICE_MODULE_PATH, sname); - if (!file_exists(opt_val)) { - snprintf(opt_val, MAX_DM_PATH, "%s/%s.json", BBFDM_DEFAULT_MICROSERVICE_MODULE_PATH, sname); - } - - if (!file_exists(opt_val)) { - fprintf(stderr, "Failed to load service plugin %s \n", sname); - return -1; - } - - strncpyt(config->in_name, opt_val, sizeof(config->in_name)); - - snprintf(opt_val, MAX_DM_PATH, "%s/%s", BBFDM_DEFAULT_MICROSERVICE_MODULE_PATH, sname); - if (folder_exists(opt_val)) { - strncpyt(config->in_plugin_dir, opt_val, sizeof(config->in_plugin_dir)); - } - - return 0; -} - -static int _parse_daemon_output_options(bbfdm_config_t *config, json_object *daemon_obj) +static void usage(char *prog) { - char *opt_val = NULL; - - if (!config || !daemon_obj) { - fprintf(stderr, "Invalid input options \n"); - return -1; - } - - opt_val = dmjson_get_value(daemon_obj, 2, "output", "root_obj"); - if (DM_STRLEN(opt_val)) { - strncpyt(config->out_root_obj, opt_val, sizeof(config->out_root_obj)); - } else if (is_micro_service == true) { // for main process, there is no root obj - strncpyt(config->out_root_obj, BBFDM_DEFAULT_UBUS_OBJ, sizeof(config->out_root_obj)); - } - - opt_val = dmjson_get_value(daemon_obj, 2, "output", "name"); - if (strlen(opt_val)) { - snprintf(config->out_name, sizeof(config->out_name), "%s%s%s", - is_micro_service ? config->out_root_obj : opt_val, - is_micro_service ? "." : "", - is_micro_service ? opt_val : ""); - } else { - snprintf(config->out_name, sizeof(config->out_name), "%s", is_micro_service ? "" : BBFDM_DEFAULT_UBUS_OBJ); - } - - return 0; + fprintf(stderr, "Usage: %s [options]\n", prog); + fprintf(stderr, "\n"); + fprintf(stderr, "options:\n"); + fprintf(stderr, " -s <socket path> ubus socket\n"); + fprintf(stderr, " -m <json path> json input configuration for micro services\n"); + fprintf(stderr, " -c <command input> Run cli command\n"); + fprintf(stderr, " -h Displays this help\n"); + fprintf(stderr, "\n"); } -static int _parse_input_cli_options(bbfdm_config_t *config, json_object *json_obj) +static int parse_input_cli_options(bbfdm_config_t *config, json_object *json_obj) { char *opt_val = NULL; @@ -1277,248 +65,34 @@ static int _parse_input_cli_options(bbfdm_config_t *config, json_object *json_ob return 0; } -static int bbfdm_load_deamon_config(bbfdm_config_t *config, const char *module) +static int load_cli_config(bbfdm_config_t *config) { - char *opt_val = NULL; - int err = 0; json_object *json_obj = NULL; - char json_path[MAX_DM_PATH] = {0}; - - if (!module || !strlen(module)) - return -1; - if (strchr(module, '/')) { // absolute path - strncpyt(json_path, module, MAX_DM_PATH); - } else { - snprintf(json_path, MAX_DM_PATH, "%s/%s.json", BBFDM_DEFAULT_MICROSERVICE_INPUT_PATH, module); - } - - json_obj = json_object_from_file(json_path); + json_obj = json_object_from_file(BBFDM_JSON_INPUT); if (!json_obj) { - fprintf(stderr, "Failed to read input %s file \n", json_path); - goto exit; - } - - _parse_input_cli_options(config, json_obj); - - json_object *daemon_obj = dmjson_get_obj(json_obj, 1, "daemon"); - if (!daemon_obj) { - err = -1; - goto exit; - } - - _parse_daemon_config_options(config, daemon_obj); - - opt_val = dmjson_get_value(daemon_obj, 1, "service_name"); - if (strlen(opt_val)) { - err = _fill_daemon_input_option(config, opt_val); - } else { - err = _parse_daemon_input_options(config, daemon_obj); - } - - if (err == -1) { - goto exit; - } - - _parse_daemon_output_options(config, daemon_obj); - - json_object_put(json_obj); - return err; -exit: - if (json_obj) { - json_object_put(json_obj); - } - - return err; -} - -static int bbfdm_regiter_ubus(struct ubus_context *ctx) -{ - int ret; - struct bbfdm_context *u; - - u = container_of(ctx, struct bbfdm_context, ubus_ctx); - if (u == NULL) { - ERR("failed to get the bbfdm context"); - return -1; - } - - bbf_object.name = u->config.out_name; - bbf_object.type->name = u->config.out_name; - if (is_micro_service) { - bbf_object.n_methods = bbf_object.n_methods - 2; - bbf_object.type->n_methods = bbf_object.n_methods; - ret = ubus_add_object(ctx, &bbf_object); - } else { - ret = ubus_add_object(ctx, &bbf_object); - } - return ret; -} - -static void lookup_event_cb(struct ubus_context *ctx, - struct ubus_event_handler *ev __attribute__((unused)), - const char *type, struct blob_attr *msg) -{ - const struct blobmsg_policy policy = { - "path", BLOBMSG_TYPE_STRING - }; - struct blob_attr *attr; - const char *path; - struct bbfdm_context *u; - - u = container_of(ctx, struct bbfdm_context, ubus_ctx); - if (u == NULL) { - ERR("failed to get the bbfdm context"); - return; - } - - if (type && strcmp(type, "ubus.object.add") != 0) - return; - - blobmsg_parse(&policy, 1, &attr, blob_data(msg), blob_len(msg)); - - if (!attr) - return; - - path = blobmsg_data(attr); - if (path && strcmp(path, u->config.out_root_obj) == 0) { - // register micro-service - register_service(ctx); - } -} - -void register_instance_refresh_timer(struct ubus_context *ctx, int start_in) -{ - struct bbfdm_context *u; - - u = container_of(ctx, struct bbfdm_context, ubus_ctx); - if (u == NULL) { - ERR("Failed to get the bbfdm context"); - return; - } - - if (start_in >= 0) { - INFO("Register instance refresh timer in %d ms...", start_in); - u->instance_timer.cb = periodic_instance_updater; - uloop_timeout_set(&u->instance_timer, start_in); - } -} - -void cancel_instance_refresh_timer(struct ubus_context *ctx) -{ - struct bbfdm_context *u; - - u = container_of(ctx, struct bbfdm_context, ubus_ctx); - if (u == NULL) { - ERR("Failed to get the bbfdm context"); - return; - } - - DEBUG("Cancelling Instance refresh timer"); - uloop_timeout_cancel(&u->instance_timer); -} - -static void bbf_config_change_cb(struct ubus_context *ctx, struct ubus_event_handler *ev, - const char *type, struct blob_attr *msg) -{ - (void)ev; - (void)ctx; - (void)msg; - - if (type && strcmp(type, "bbf.config.change") != 0) - return; - - INFO("Config updated, Scheduling instance refresh timers"); - - cancel_instance_refresh_timer(ctx); - register_instance_refresh_timer(ctx, 0); -} - -static void bbfdm_ctx_init(struct bbfdm_context *bbfdm_ctx) -{ - memset(bbfdm_ctx, 0, sizeof(struct bbfdm_context)); - INIT_LIST_HEAD(&bbfdm_ctx->instances); - INIT_LIST_HEAD(&bbfdm_ctx->old_instances); - INIT_LIST_HEAD(&bbfdm_ctx->event_handlers); -} - -static int daemon_load_datamodel(struct bbfdm_context *daemon_ctx) -{ - int err = -1; - char *file_path = daemon_ctx->config.in_name; - - if (DM_STRLEN(file_path) == 0) { - ERR("Input type/name not supported or defined"); - return -1; - } - - char *ext = strrchr(file_path, '.'); - if (ext == NULL) { - ERR("Input file without extension"); - } else if (strcasecmp(ext, ".json") == 0) { - INFO("Loading JSON plugin %s", file_path); - err = load_json_plugin(&loaded_json_files, &json_list, &json_memhead, file_path, &daemon_ctx->config, &DEAMON_DM_ROOT_OBJ); - } else if (strcasecmp(ext, ".so") == 0) { - INFO("Loading DotSo plugin %s", file_path); - err = load_dotso_plugin(&deamon_lib_handle, file_path, &daemon_ctx->config, &DEAMON_DM_ROOT_OBJ); - } else { - ERR("Input type %s not supported", ext); - } - - if (!err) { - INFO("Loading sub-modules %s", daemon_ctx->config.in_plugin_dir); - bbf_global_init(DEAMON_DM_ROOT_OBJ, daemon_ctx->config.in_plugin_dir); - } else { - ERR("Failed loading %s", file_path); - } - - if (DM_STRLEN(daemon_ctx->config.out_name) == 0) { - ERR("output name not defined"); + fprintf(stderr, "Failed to read input %s file \n", BBFDM_JSON_INPUT); return -1; } - if (is_micro_service) { - if (DM_STRLEN(daemon_ctx->config.out_parent_dm) == 0) { - ERR("output parent dm not defined"); - return -1; - } - - if (DM_STRLEN(daemon_ctx->config.out_objects[0]) == 0) { - ERR("output objects is not defined"); - return -1; - } - - if (DM_STRLEN(daemon_ctx->config.out_root_obj) == 0) { - ERR("output root obj not defined"); - return -1; - } - } + parse_input_cli_options(config, json_obj); - return err; + json_object_put(json_obj); + return 0; } -static struct ubus_event_handler add_event = { .cb = lookup_event_cb }; -static struct ubus_event_handler config_change_handler = { .cb = bbf_config_change_cb }; - int main(int argc, char **argv) { - struct bbfdm_context bbfdm_ctx; - const char *ubus_socket = NULL, *input_file = BBFDM_JSON_INPUT; + struct bbfdm_context bbfdm_ctx = {0}; char *cli_argv[4] = {0}; int err = 0, ch, cli_argc = 0, i; - bool ubus_init_done = false; - char log_level[32] = {0}; - bbfdm_ctx_init(&bbfdm_ctx); + memset(&bbfdm_ctx, 0, sizeof(struct bbfdm_context)); while ((ch = getopt(argc, argv, "hs:m:c:")) != -1) { switch (ch) { - case 's': - ubus_socket = optarg; - break; case 'm': - input_file = optarg; - is_micro_service = input_file ? true : false; + bbfdm_ubus_set_service_name(&bbfdm_ctx, optarg); break; case 'c': cli_argc = argc-optind+1; @@ -1534,57 +108,28 @@ int main(int argc, char **argv) } } - signal_init(); - - err = bbfdm_load_deamon_config(&bbfdm_ctx.config, input_file); - if (err) { - fprintf(stderr, "Failed to load %s config from json file (%s)\n", bbfdm_ctx.config.service_name, input_file); - goto exit; - } - - snprintf(log_level, sizeof(log_level), "bbfdm%s%s", - is_micro_service ? "." : "", - is_micro_service ? bbfdm_ctx.config.service_name : ""); - - openlog(log_level, LOG_CONS | LOG_PID | LOG_NDELAY, LOG_LOCAL1); - if (cli_argc) { - err = bbfdm_cli_exec_command(&bbfdm_ctx.config, cli_argc, cli_argv); - goto exit; - } + if (dm_is_micro_service() == true) { + fprintf(stderr, "Failed to run cli with micro-service\n"); + return -1; + } - err = daemon_load_datamodel(&bbfdm_ctx); - if (err) { - ERR("Failed to load datamodel"); - goto exit; - } + err = load_cli_config(&bbfdm_ctx.config); + if (err) { + fprintf(stderr, "Failed to load cli config from json file (%s)\n", BBFDM_JSON_INPUT); + return err; + } - err = ubus_connect_ctx(&bbfdm_ctx.ubus_ctx, ubus_socket); - if (err != UBUS_STATUS_OK) { - ERR("Failed to connect to ubus"); - return -1; + return bbfdm_cli_exec_command(&bbfdm_ctx.config, cli_argc, cli_argv); } - uloop_init(); - ubus_add_uloop(&bbfdm_ctx.ubus_ctx); - ubus_init_done = true; - - err = bbfdm_regiter_ubus(&bbfdm_ctx.ubus_ctx); - if (err != UBUS_STATUS_OK) - goto exit; - - run_schema_updater(&bbfdm_ctx); - register_instance_refresh_timer(&bbfdm_ctx.ubus_ctx, 1000); - - err = register_events_to_ubus(&bbfdm_ctx.ubus_ctx, &bbfdm_ctx.event_handlers); - if (err != 0) - goto exit; + openlog("bbfdm", LOG_CONS | LOG_PID | LOG_NDELAY, LOG_LOCAL1); - err = ubus_register_event_handler(&bbfdm_ctx.ubus_ctx, &config_change_handler, "bbf.config.change"); + err = bbfdm_ubus_regiter_init(&bbfdm_ctx); if (err != 0) goto exit; - if (is_micro_service == true) { // It's a micro-service instance + if (dm_is_micro_service() == true) { char proc_name[32] = {0}; // Create process name using service name and prefix "dm_" @@ -1592,28 +137,13 @@ int main(int argc, char **argv) // Set process name for the current process prctl(PR_SET_NAME, proc_name, NULL, NULL, NULL); - - // Register the micro-service - register_service(&bbfdm_ctx.ubus_ctx); - - // If the micro-service is not registered, listen for "ubus.object.add" event - // and register the micro-service using event handler for it - err = ubus_register_event_handler(&bbfdm_ctx.ubus_ctx, &add_event, "ubus.object.add"); - if (err != 0) - goto exit; } - INFO("Waiting on uloop...."); + BBF_INFO("Waiting on uloop...."); uloop_run(); exit: - free_ubus_event_handler(&bbfdm_ctx.ubus_ctx, &bbfdm_ctx.event_handlers); - - if (ubus_init_done) { - uloop_done(); - ubus_shutdown(&bbfdm_ctx.ubus_ctx); - } - bbfdm_cleanup(&bbfdm_ctx); + bbfdm_ubus_regiter_free(&bbfdm_ctx); closelog(); return err; diff --git a/bbfdmd/ubus/ipc.h b/bbfdmd/ubus/ipc.h deleted file mode 100644 index 5af354a7b2cf4bddab0cb711c89038287cf23415..0000000000000000000000000000000000000000 --- a/bbfdmd/ubus/ipc.h +++ /dev/null @@ -1,22 +0,0 @@ -/* - * ipc.h: File to handle ipc related functionality - * - * Copyright (C) 2020-2023 IOPSYS Software Solutions AB. All rights reserved. - * - * Author: Vivek Dutta <vivek.dutta@iopsys.eu> - * - * See LICENSE file for license related information. - */ - -#ifndef IPC_H -#define IPC_H - -#include <sys/mman.h> - -#ifdef BBFDM_MAX_MSG_LEN - #define DEF_IPC_DATA_LEN (BBFDM_MAX_MSG_LEN - 128) // Configured Len - 128 bytes -#else - #define DEF_IPC_DATA_LEN (10 * 1024 * 1024 - 128) // 10M - 128 bytes -#endif - -#endif /* IPC_H */ diff --git a/docs/api/uci/bbfdm.json b/docs/api/uci/bbfdm.json index b3a2052bb0054a02d398bf258eca5987e5ca3296..ce90d289da61d96299f7e059263f7b1689264ff3 100644 --- a/docs/api/uci/bbfdm.json +++ b/docs/api/uci/bbfdm.json @@ -30,8 +30,8 @@ "name": "loglevel", "type": "integer", "required": "no", - "default": "1", - "description": "Internal loglevel for debugging {0: No Logs; 1: Errors only; 2: Errors and warnings; 3: Error, warning and info; 4: Everything}" + "default": "3", + "description": "Internal loglevel for debugging {0: No Logs; 1: Alert; 2: Critical; 3: Error; 4: Warning; 5: Notice; 6: Info; 7: Debug}" }, { "name": "subprocess_level", diff --git a/docs/api/uci/bbfdm.md b/docs/api/uci/bbfdm.md index 8d45f50f39fa33c3075919cd10f0476b1e8c50b9..4e4ec1699d742804441fcb1fc228b6f16fe11c6a 100644 --- a/docs/api/uci/bbfdm.md +++ b/docs/api/uci/bbfdm.md @@ -98,8 +98,7 @@ <div class="td_row_even">1</div> </td> <td class="td_row_even"> - <div class="td_row_even">Internal loglevel for debugging {0: No Logs; 1: Errors only; 2: Errors - and warnings; 3: Error, warning and info; 4: Everything}</div> + <div class="td_row_even">Internal loglevel for debugging {0: No Logs; 1: Alert; 2: Critical; 3: Error; 4: Warning; 5: Notice; 6: Info; 7: Debug}</div> </td> </tr> <tr> @@ -119,23 +118,6 @@ <div class="td_row_even">This parameter configures when subprocess can be used for get operation. Level here denotes the Datamodel object depth up-to which subprocess will be used to collect the get data. For example, if this is configured to 1, then only get for 'Device.' shall be called within the subprocess. If configured as level 2, then all the get with up-to depth 2 like 'Device.WiFi.', 'Device.IP.' shall be called in subprocess.</div> </td> </tr> - <tr> - <td class="td_row_even"> - <div class="td_row_even">bbf_caching_time</div> - </td> - <td class="td_row_even"> - <div class="td_row_even">integer</div> - </td> - <td class="td_row_even"> - <div class="td_row_even">no</div> - </td> - <td class="td_row_even"> - <div class="td_row_even">0</div> - </td> - <td class="td_row_even"> - <div class="td_row_even">Max caching time in seconds for ubus output used in datamodel parameters. If not configured, output shall be cleared end the end of call.</div> - </td> - </tr> <tr> <td class="td_row_even"> <div class="td_row_even">refresh_time</div> diff --git a/libbbfdm-api/dmapi.c b/libbbfdm-api/dmapi.c index 443282ac88b7f6572e3c4fb1cd26b546b9dcfae7..3097b11f012f8d5a77e02fe4b5bc7f69cbd62d95 100644 --- a/libbbfdm-api/dmapi.c +++ b/libbbfdm-api/dmapi.c @@ -264,7 +264,7 @@ int bbfdm_get_references(struct dmctx *ctx, int match_action, const char *base_p goto end; } - if (is_micro_service == true) { // It's a micro-service instance + if (dm_is_micro_service() == true) { // It's a micro-service instance if (out_len - len < strlen(base_path) + strlen(key_name) + strlen(key_value) + 9) { // 9 = 'path[key_name==\"key_value\"].' BBF_ERR("Buffer overflow detected. The output buffer is not large enough to hold the additional data!!!"); @@ -395,7 +395,7 @@ int bbfdm_operate_reference_linker(struct dmctx *ctx, char *reference_path, char if (DM_STRLEN(*reference_value) != 0) return 0; - if (is_micro_service == true) // It's a micro-service instance + if (dm_is_micro_service() == true) // It's a micro-service instance *reference_value = bbfdm_get_reference_value(reference_path); return 0; diff --git a/libbbfdm-api/dmapi.h b/libbbfdm-api/dmapi.h index 4b3991bfeba5eeb242c8bb408a43132652b7e7df..eb5e99f4759ef9b0ae075d2f5f0b4e30103d1c25 100644 --- a/libbbfdm-api/dmapi.h +++ b/libbbfdm-api/dmapi.h @@ -33,9 +33,6 @@ extern struct dm_permession_s DMASYNC; extern char *DMT_TYPE[]; -extern unsigned char gLogLevel; -extern bool is_micro_service; - #ifndef BBF_MAX_OBJECT_INSTANCES #define BBF_MAX_OBJECT_INSTANCES (255) #endif diff --git a/libbbfdm-api/dmbbf.c b/libbbfdm-api/dmbbf.c index f35435cd4a9ac9adc6838cfaa7696ec3e06d63e0..43a7691f76148b09b89416718bb5018629e0c29a 100644 --- a/libbbfdm-api/dmbbf.c +++ b/libbbfdm-api/dmbbf.c @@ -18,11 +18,9 @@ #include "dmbbf.h" #define MAX_DM_PATH (1024) -#define DEFAULT_LOG_LEVEL (2) #define SEPARATOR_LIST_VALUES ";" -unsigned char gLogLevel = DEFAULT_LOG_LEVEL; -bool is_micro_service = false; +static bool is_micro_service = false; char *DMT_TYPE[] = { [DMT_STRING] = "xsd:string", @@ -43,6 +41,16 @@ struct dm_permession_s DMWRITE = {"1", NULL}; struct dm_permession_s DMSYNC = {"sync", NULL}; struct dm_permession_s DMASYNC = {"async", NULL}; +bool dm_is_micro_service(void) +{ + return is_micro_service; +} + +void dm_set_micro_service(void) +{ + is_micro_service = true; +} + static int dm_browse(struct dmctx *dmctx, DMNODE *parent_node, DMOBJ *entryobj, void *data, char *instance); static bool is_instance_number_alias(char **str) @@ -819,7 +827,7 @@ static int is64digit(char c) char *get_value_by_reference(struct dmctx *ctx, char *value) { - if (is_micro_service == true) // It's a micro-service instance + if (dm_is_micro_service() == true) // It's a micro-service instance return value; char *pch = NULL, *spch = NULL; diff --git a/libbbfdm-api/dmbbf.h b/libbbfdm-api/dmbbf.h index 2478674fe35a0e260358e75de5f4fb621193c4a4..7405dc3072e7674a9df579ddf4e5bcf3163f54b5 100644 --- a/libbbfdm-api/dmbbf.h +++ b/libbbfdm-api/dmbbf.h @@ -27,6 +27,9 @@ #include "dmmem.h" #include "dmapi.h" +bool dm_is_micro_service(void); +void dm_set_micro_service(void); + int get_number_of_entries(struct dmctx *ctx, void *data, char *instance, int (*browseinstobj)(struct dmctx *ctx, struct dmnode *node, void *data, char *instance)); char *handle_instance(struct dmctx *dmctx, DMNODE *parent_node, struct uci_section *s, char *inst_opt, char *alias_opt); char *handle_instance_without_section(struct dmctx *dmctx, DMNODE *parent_node, int inst_nbr); @@ -68,27 +71,19 @@ static inline int DM_LINK_INST_OBJ(struct dmctx *dmctx, DMNODE *parent_node, voi // Macros for different log levels #define BBF_ERR(MESSAGE, ...) do { \ - if (gLogLevel >= 1) { \ - syslog(LOG_ERR, "[%s:%d] " MESSAGE, __FUNCTION__, __LINE__, ##__VA_ARGS__); /* Flawfinder: ignore */ \ - } \ + syslog(LOG_ERR, "[%s:%d] " MESSAGE, __FUNCTION__, __LINE__, ##__VA_ARGS__); /* Flawfinder: ignore */ \ } while(0) #define BBF_WARNING(MESSAGE, ...) do { \ - if (gLogLevel >= 2) { \ - syslog(LOG_WARNING, "[%s:%d] " MESSAGE, __FUNCTION__, __LINE__, ##__VA_ARGS__); /* Flawfinder: ignore */ \ - } \ + syslog(LOG_WARNING, "[%s:%d] " MESSAGE, __FUNCTION__, __LINE__, ##__VA_ARGS__); /* Flawfinder: ignore */ \ } while(0) #define BBF_INFO(MESSAGE, ...) do { \ - if (gLogLevel >= 3) { \ - syslog(LOG_INFO, "[%s:%d] " MESSAGE, __FUNCTION__, __LINE__, ##__VA_ARGS__); /* Flawfinder: ignore */ \ - } \ + syslog(LOG_INFO, "[%s:%d] " MESSAGE, __FUNCTION__, __LINE__, ##__VA_ARGS__); /* Flawfinder: ignore */ \ } while(0) #define BBF_DEBUG(MESSAGE, ...) do { \ - if (gLogLevel >= 4) { \ - syslog(LOG_DEBUG, "[%s:%d] " MESSAGE, __FUNCTION__, __LINE__, ##__VA_ARGS__); /* Flawfinder: ignore */ \ - } \ + syslog(LOG_DEBUG, "[%s:%d] " MESSAGE, __FUNCTION__, __LINE__, ##__VA_ARGS__); /* Flawfinder: ignore */ \ } while(0) diff --git a/libbbfdm-api/dmentry.c b/libbbfdm-api/dmentry.c index 1f2b1974fd0676afda0c2aca69fdc0d0c5185132..b429148da678d4e56675ae58125679475e8539c0 100644 --- a/libbbfdm-api/dmentry.c +++ b/libbbfdm-api/dmentry.c @@ -258,7 +258,7 @@ int dm_validate_allowed_objects(struct dmctx *ctx, struct dm_reference *referenc if (match(reference->path, *objects, 0, NULL)) { - if (is_micro_service) { + if (dm_is_micro_service()) { if (DM_STRLEN(reference->value)) return 0; } else { diff --git a/libbbfdm-ubus/CMakeLists.txt b/libbbfdm-ubus/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..57af0ec6a52732a884135284cf6d561d127c7a71 --- /dev/null +++ b/libbbfdm-ubus/CMakeLists.txt @@ -0,0 +1,32 @@ +cmake_minimum_required(VERSION 3.0) + +PROJECT(libbbfdm-ubus) + +ADD_DEFINITIONS(-Wall -Werror -D_GNU_SOURCE) +ADD_DEFINITIONS(-DBBF_VENDOR_PREFIX="${BBF_VENDOR_PREFIX}") + +SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -I${CMAKE_SOURCE_DIR} -I${CMAKE_SOURCE_DIR}/libbbfdm-api/") + +IF(${BBFDMD_MAX_MSG_LEN}) + ADD_DEFINITIONS(-DBBFDM_MAX_MSG_LEN=${BBFDMD_MAX_MSG_LEN}) +ENDIF() + +OPTION(BBF_SCHEMA_FULL_TREE "build with schema full tree" OFF) + +IF(BBF_SCHEMA_FULL_TREE) + add_compile_definitions(BBF_SCHEMA_FULL_TREE) +ENDIF(BBF_SCHEMA_FULL_TREE) + +FILE(GLOB BBF_UBUS_SOURCES *.c) + +ADD_LIBRARY(bbfdm-ubus SHARED ${BBF_UBUS_SOURCES}) + +TARGET_LINK_LIBRARIES(bbfdm-ubus uci ubus ubox json-c blobmsg_json bbfdm-api) + +INSTALL(TARGETS bbfdm-ubus + LIBRARY DESTINATION usr/lib) + +FILE(GLOB libbbfdm-ubus_headers bbfdm-ubus.h) +INSTALL(FILES ${libbbfdm-ubus_headers} + DESTINATION usr/include/libbbfdm-ubus +) diff --git a/bbfdmd/ubus/add_delete.c b/libbbfdm-ubus/add_delete.c similarity index 93% rename from bbfdmd/ubus/add_delete.c rename to libbbfdm-ubus/add_delete.c index 772781c0800c295ad4fc5357e7f5a28dcb9e12a8..2ed2bce41697e15e7d159bd7cf9dc8ecae45035c 100644 --- a/bbfdmd/ubus/add_delete.c +++ b/libbbfdm-ubus/add_delete.c @@ -19,7 +19,7 @@ static int bbfdm_add_object(bbfdm_data_t *data) { int fault = 0; - INFO("Req to add object |%s|", data->bbf_ctx.in_param); + BBF_INFO("Req to add object |%s|", data->bbf_ctx.in_param); void *array = blobmsg_open_array(&data->bb, "results"); @@ -50,7 +50,7 @@ static int bbfdm_del_object(bbfdm_data_t *data) data->bbf_ctx.in_param = pn->path; - INFO("Req to delete object |%s|", data->bbf_ctx.in_param); + BBF_INFO("Req to delete object |%s|", data->bbf_ctx.in_param); fault = bbfdm_cmd_exec(&data->bbf_ctx, BBF_DEL_OBJECT); if (fault) { diff --git a/bbfdmd/ubus/add_delete.h b/libbbfdm-ubus/add_delete.h similarity index 93% rename from bbfdmd/ubus/add_delete.h rename to libbbfdm-ubus/add_delete.h index 33d895f519d0c646280214b79681da961d26411e..f09631c189d9f49ae35889798d9f458585313a62 100644 --- a/bbfdmd/ubus/add_delete.h +++ b/libbbfdm-ubus/add_delete.h @@ -1,8 +1,6 @@ #ifndef ADD_DEL_H #define ADD_DEL_H -#include "bbfdmd.h" - enum { DM_ADD_PATH, DM_ADD_OBJ_PATH, diff --git a/libbbfdm-ubus/bbfdm-ubus.c b/libbbfdm-ubus/bbfdm-ubus.c new file mode 100644 index 0000000000000000000000000000000000000000..03dc6284624b76958e32fd5e2015590c33cd1052 --- /dev/null +++ b/libbbfdm-ubus/bbfdm-ubus.c @@ -0,0 +1,1529 @@ +/* + * bbfdm-ubus.c: bbfdm-ubus API to expose Data Model over ubus + * + * Copyright (C) 2023-2024 IOPSYS Software Solutions AB. All rights reserved. + * + * Author: Vivek Dutta <vivek.dutta@iopsys.eu> + * Author: Amin Ben Romdhane <amin.benromdhane@iopsys.eu> + * + * See LICENSE file for license related information. + */ + +#include <stdio.h> +#include <unistd.h> +#include <stdlib.h> +#include <libubox/blobmsg.h> +#include <libubox/uloop.h> +#include <libubus.h> + +#include <sys/mman.h> + +#include "bbfdm-ubus.h" +#include "set.h" +#include "get.h" +#include "operate.h" +#include "add_delete.h" +#include "events.h" +#include "pretty_print.h" +#include "get_helper.h" +#include "plugin.h" + +#define BBFDM_DEFAULT_MODULES_PATH "/usr/share/bbfdm" +#define BBFDM_DEFAULT_PLUGINS_PATH BBFDM_DEFAULT_MODULES_PATH"/plugins" +#define BBFDM_DEFAULT_MICROSERVICE_MODULE_PATH BBFDM_DEFAULT_MODULES_PATH"/micro_services" +#define BBFDM_DEFAULT_UBUS_OBJ "bbfdm" + +extern struct list_head loaded_json_files; +extern struct list_head json_list; +extern struct list_head json_memhead; + +LIST_HEAD(head_registered_service); + +static void run_schema_updater(struct bbfdm_context *u); +static void periodic_instance_updater(struct uloop_timeout *t); + +// Global variables +static void *deamon_lib_handle = NULL; + +static void bbfdm_ctx_cleanup(struct bbfdm_context *u) +{ + bbf_global_clean(DEAMON_DM_ROOT_OBJ); + + free_path_list(&u->instances); + free_path_list(&u->old_instances); + + /* Main daemon */ + if (dm_is_micro_service() == false) { + free_services_from_list(&head_registered_service); + } + + /* DotSo Plugin */ + free_dotso_plugin(deamon_lib_handle); + deamon_lib_handle = NULL; + + /* JSON Plugin */ + free_json_plugin(); +} + +static bool is_sync_operate_cmd(bbfdm_data_t *data __attribute__((unused))) +{ + return false; +} + +static bool is_subprocess_required(int subprocess_level, const char *path) +{ + bool ret = false; + size_t len = DM_STRLEN(path); + if (len == 0) + return ret; + + if (count_delim(path) < subprocess_level) { + if (path[len - 1] == '.') + ret = true; + } + + return ret; +} + +static void fill_optional_data(bbfdm_data_t *data, struct blob_attr *msg) +{ + struct blob_attr *attr; + size_t rem; + + if (!data || !msg) + return; + + blobmsg_for_each_attr(attr, msg, rem) { + + if (is_str_eq(blobmsg_name(attr), "proto")) { + const char *val = blobmsg_get_string(attr); + data->bbf_ctx.dm_type = get_proto_type(val); + } + + if (is_str_eq(blobmsg_name(attr), "format")) + data->is_raw = is_str_eq(blobmsg_get_string(attr), "raw") ? true : false; + } + + char *proto = (data->bbf_ctx.dm_type == BBFDM_BOTH) ? "both" : (data->bbf_ctx.dm_type == BBFDM_CWMP) ? "cwmp" : "usp"; + BBF_DEBUG("Proto:|%s|, is_raw:|%d|", proto, data->is_raw); +} + +static void async_req_free(struct bbfdm_async_req *r) +{ + free(r); +} + +static void async_complete_cb(struct uloop_process *p, __attribute__((unused)) int ret) +{ + struct bbfdm_async_req *r = container_of(p, struct bbfdm_async_req, process); + + if (r) { + BBF_INFO("Async call with pid(%d) completes", r->process.pid); + struct blob_buf *bb = (struct blob_buf *)&r->result; + + ubus_send_reply(r->ctx, &r->req, bb->head); + BBF_INFO("pid(%d) blob data sent raw(%zu)", r->process.pid, blob_raw_len(bb->head)); + ubus_complete_deferred_request(r->ctx, &r->req, 0); + if (r->is_operate) { + register_instance_refresh_timer(r->ctx, 0); + } + munmap(r->result, DEF_IPC_DATA_LEN); + async_req_free(r); + } + +} + +static struct bbfdm_async_req *async_req_new(void) +{ + struct bbfdm_async_req *r = malloc(sizeof(*r)); + + if (r) { + memset(&r->process, 0, sizeof(r->process)); + r->result = NULL; + } + + return r; +} + +static int bbfdm_start_deferred(bbfdm_data_t *data, void (*EXEC_CB)(bbfdm_data_t *data, void *d), bool is_operate) +{ + struct bbfdm_async_req *r = NULL; + pid_t child; + struct bbfdm_context *u; + void *result = NULL; + + result = mmap(NULL, DEF_IPC_DATA_LEN, PROT_READ| PROT_WRITE, MAP_SHARED|MAP_ANONYMOUS, -1, 0); + if (result == MAP_FAILED) { + BBF_ERR("Error creating memory map for result"); + goto err_out; + } + memset(result, 0, DEF_IPC_DATA_LEN); + r = async_req_new(); + if (r == NULL) { + BBF_ERR("Error allocating async req"); + goto err_out; + } + + child = fork(); + if (child == -1) { + BBF_ERR("fork error"); + goto err_out; + } else if (child == 0) { + u = container_of(data->ctx, struct bbfdm_context, ubus_ctx); + if (u == NULL) { + BBF_ERR("{fork} Failed to get the bbfdm context"); + exit(EXIT_FAILURE); + } + + /* free fd's and memory inherited from parent */ + uloop_done(); + ubus_shutdown(data->ctx); + async_req_free(r); + fclose(stdin); + fclose(stdout); + fclose(stderr); + + BBF_INFO("{fork} Calling from subprocess"); + EXEC_CB(data, result); + + bbfdm_ctx_cleanup(u); + closelog(); + /* write result and exit */ + exit(EXIT_SUCCESS); + } + + // parent + BBF_INFO("Creating bbfdm(%d) sub process(%d) for path(%s)", getpid(), child, data->bbf_ctx.in_param); + r->result = result; + r->ctx = data->ctx; + r->process.pid = child; + r->process.cb = async_complete_cb; + r->is_operate = is_operate; + uloop_process_add(&r->process); + ubus_defer_request(data->ctx, data->req, &r->req); + return 0; + +err_out: + if (r) + async_req_free(r); + + if (result) + munmap(result, DEF_IPC_DATA_LEN); + + return UBUS_STATUS_UNKNOWN_ERROR; +} + +static bool is_object_schema_update_available(struct bbfdm_context *u) +{ + bool ret = false; + LIST_HEAD(paths_list); + bbfdm_data_t data = { + .ctx = 0, + .req = 0, + .is_raw = true, + .plist = &paths_list, + .bbf_ctx.nextlevel = false, + .bbf_ctx.iscommand = true, + .bbf_ctx.isevent = true, + .bbf_ctx.isinfo = true, + .bbf_ctx.dm_type = BBFDM_USP + }; + + int old_schema_len = u->schema_len; + + // If new parameter gets added it would be a minimum tuple of three params + int min_len = 100; + + add_path_list(ROOT_NODE, &paths_list); + int new_schema_len = bbfdm_get_supported_dm(&data); + if (new_schema_len == 0) { + BBF_WARNING("Failed to get schema"); + free_path_list(&paths_list); + return ret; + } + + if (new_schema_len - old_schema_len > min_len) { + BBF_DEBUG("DM Schema update available old:new[%d:%d]", old_schema_len, new_schema_len); + if (old_schema_len != 0) { + ret = true; + } + } + + free_path_list(&paths_list); + + return ret; +} + +static const struct blobmsg_policy dm_get_policy[] = { + [DM_GET_PATH] = { .name = "path", .type = BLOBMSG_TYPE_STRING }, + [DM_GET_PATHS] = { .name = "paths", .type = BLOBMSG_TYPE_ARRAY }, + [DM_GET_MAXDEPTH] = { .name = "maxdepth", .type = BLOBMSG_TYPE_INT32 }, + [DM_GET_OPTIONAL] = { .name = "optional", .type = BLOBMSG_TYPE_TABLE}, +}; + +static int bbfdm_get_handler(struct ubus_context *ctx, struct ubus_object *obj __attribute__((unused)), + struct ubus_request_data *req, const char *method __attribute__((unused)), + struct blob_attr *msg) +{ + struct blob_attr *tb[__DM_GET_MAX]; + LIST_HEAD(paths_list); + bbfdm_data_t data; + uint8_t maxdepth = 0; + bool is_subprocess_needed = false; + struct bbfdm_context *u; + + u = container_of(ctx, struct bbfdm_context, ubus_ctx); + if (u == NULL) { + BBF_ERR("Failed to get the bbfdm context"); + return UBUS_STATUS_UNKNOWN_ERROR; + } + + memset(&data, 0, sizeof(bbfdm_data_t)); + + if (blobmsg_parse(dm_get_policy, __DM_GET_MAX, tb, blob_data(msg), blob_len(msg))) { + BBF_ERR("Failed to parse blob"); + return UBUS_STATUS_UNKNOWN_ERROR; + } + + if (!(tb[DM_GET_PATH]) && !(tb[DM_GET_PATHS])) + return UBUS_STATUS_INVALID_ARGUMENT; + + if (tb[DM_GET_PATH]) { + char *path = blobmsg_get_string(tb[DM_GET_PATH]); + add_path_list(path, &paths_list); + is_subprocess_needed = is_subprocess_required(u->config.subprocess_level, path); + } + + if (tb[DM_GET_PATHS]) { + struct blob_attr *paths = tb[DM_GET_PATHS]; + struct blob_attr *path = NULL; + size_t rem; + + blobmsg_for_each_attr(path, paths, rem) { + char *path_str = blobmsg_get_string(path); + + add_path_list(path_str, &paths_list); + if (!is_subprocess_needed) + is_subprocess_needed = is_subprocess_required(u->config.subprocess_level, path_str); + } + } + + if (tb[DM_GET_MAXDEPTH]) + maxdepth = blobmsg_get_u32(tb[DM_GET_MAXDEPTH]); + + data.ctx = ctx; + data.req = req; + data.plist = &paths_list; + data.depth = maxdepth; + + fill_optional_data(&data, tb[DM_GET_OPTIONAL]); + + if (is_subprocess_needed) { + BBF_INFO("Creating subprocess for get method"); + bbfdm_start_deferred(&data, bbfdm_get_value, false); + } else { + bbfdm_get_value(&data, NULL); + } + + free_path_list(&paths_list); + return 0; +} + +static const struct blobmsg_policy dm_schema_policy[] = { + [DM_SCHEMA_PATH] = { .name = "path", .type = BLOBMSG_TYPE_STRING }, + [DM_SCHEMA_PATHS] = { .name = "paths", .type = BLOBMSG_TYPE_ARRAY }, + [DM_SCHEMA_FIRST_LEVEL] = { .name = "first_level", .type = BLOBMSG_TYPE_BOOL}, + [DM_SCHEMA_OPTIONAL] = { .name = "optional", .type = BLOBMSG_TYPE_TABLE}, +}; + +static int bbfdm_schema_handler(struct ubus_context *ctx, struct ubus_object *obj __attribute__((unused)), + struct ubus_request_data *req, const char *method __attribute__((unused)), + struct blob_attr *msg) +{ + struct blob_attr *tb[__DM_SCHEMA_MAX]; + LIST_HEAD(paths_list); + bbfdm_data_t data; + struct bbfdm_context *u; + + u = container_of(ctx, struct bbfdm_context, ubus_ctx); + if (u == NULL) { + BBF_ERR("Failed to get the bbfdm context"); + return UBUS_STATUS_UNKNOWN_ERROR; + } + + memset(&data, 0, sizeof(bbfdm_data_t)); + + if (blobmsg_parse(dm_schema_policy, __DM_SCHEMA_MAX, tb, blob_data(msg), blob_len(msg))) { + BBF_ERR("Failed to parse blob"); + return UBUS_STATUS_UNKNOWN_ERROR; + } + + if (!(tb[DM_SCHEMA_PATH]) && !(tb[DM_SCHEMA_PATHS])) + return UBUS_STATUS_INVALID_ARGUMENT; + + if (tb[DM_SCHEMA_PATH]) { + char *path = blobmsg_get_string(tb[DM_SCHEMA_PATH]); + + add_path_list(path, &paths_list); + } + + if (tb[DM_SCHEMA_PATHS]) { + struct blob_attr *paths = tb[DM_GET_PATHS]; + struct blob_attr *path = NULL; + size_t rem; + + blobmsg_for_each_attr(path, paths, rem) { + char *path_str = blobmsg_get_string(path); + + add_path_list(path_str, &paths_list); + } + } + + fill_optional_data(&data, tb[DM_SCHEMA_OPTIONAL]); + + unsigned int dm_type = data.bbf_ctx.dm_type; + + data.ctx = ctx; + data.req = req; + data.bbf_ctx.nextlevel = (tb[DM_SCHEMA_FIRST_LEVEL]) ? blobmsg_get_bool(tb[DM_SCHEMA_FIRST_LEVEL]) : false; + data.bbf_ctx.iscommand = (dm_type == BBFDM_CWMP) ? false : true; + data.bbf_ctx.isevent = (dm_type == BBFDM_CWMP) ? false : true; + data.bbf_ctx.isinfo = (dm_type == BBFDM_CWMP) ? false : true; + data.plist = &paths_list; + +#ifdef BBF_SCHEMA_FULL_TREE + data.bbf_ctx.isinfo = true; + bbfdm_get_supported_dm(&data); +#else + if (dm_type == BBFDM_CWMP) + bbfdm_get_names(&data); + else + bbfdm_get_supported_dm(&data); +#endif + + free_path_list(&paths_list); + return 0; +} + +static const struct blobmsg_policy dm_instances_policy[] = { + [DM_INSTANCES_PATH] = { .name = "path", .type = BLOBMSG_TYPE_STRING }, + [DM_INSTANCES_PATHS] = { .name = "paths", .type = BLOBMSG_TYPE_ARRAY }, + [DM_INSTANCES_FIRST_LEVEL] = { .name = "first_level", .type = BLOBMSG_TYPE_BOOL }, + [DM_INSTANCES_OPTIONAL] = { .name = "optional", .type = BLOBMSG_TYPE_TABLE }, +}; + +static int bbfdm_instances_handler(struct ubus_context *ctx, struct ubus_object *obj __attribute__((unused)), + struct ubus_request_data *req, const char *method __attribute__((unused)), + struct blob_attr *msg) +{ + struct blob_attr *tb[__DM_INSTANCES_MAX]; + LIST_HEAD(paths_list); + bbfdm_data_t data; + + memset(&data, 0, sizeof(bbfdm_data_t)); + + if (blobmsg_parse(dm_instances_policy, __DM_INSTANCES_MAX, tb, blob_data(msg), blob_len(msg))) { + BBF_ERR("Failed to parse blob"); + return UBUS_STATUS_UNKNOWN_ERROR; + } + + if (!(tb[DM_INSTANCES_PATH]) && !(tb[DM_INSTANCES_PATHS])) + return UBUS_STATUS_INVALID_ARGUMENT; + + if (tb[DM_INSTANCES_PATH]) { + char *path = blobmsg_get_string(tb[DM_INSTANCES_PATH]); + add_path_list(path, &paths_list); + } + + if (tb[DM_INSTANCES_PATHS]) { + struct blob_attr *paths = tb[DM_INSTANCES_PATHS]; + struct blob_attr *path = NULL; + size_t rem; + + blobmsg_for_each_attr(path, paths, rem) { + char *path_str = blobmsg_get_string(path); + + add_path_list(path_str, &paths_list); + } + } + + data.ctx = ctx; + data.req = req; + data.bbf_ctx.nextlevel = (tb[DM_INSTANCES_FIRST_LEVEL]) ? blobmsg_get_bool(tb[DM_INSTANCES_FIRST_LEVEL]) : false; + data.plist = &paths_list; + + fill_optional_data(&data, tb[DM_INSTANCES_OPTIONAL]); + + bbfdm_get_instances(&data); + + free_path_list(&paths_list); + return 0; +} + +static const struct blobmsg_policy dm_set_policy[] = { + [DM_SET_PATH] = { .name = "path", .type = BLOBMSG_TYPE_STRING }, + [DM_SET_VALUE] = { .name = "value", .type = BLOBMSG_TYPE_STRING }, + [DM_SET_OBJ_PATH] = { .name = "obj_path", .type = BLOBMSG_TYPE_TABLE }, + [DM_SET_OPTIONAL] = { .name = "optional", .type = BLOBMSG_TYPE_TABLE }, +}; + +int bbfdm_set_handler(struct ubus_context *ctx, struct ubus_object *obj, + struct ubus_request_data *req, const char *method, + struct blob_attr *msg) +{ + struct blob_attr *tb[__DM_SET_MAX] = {NULL}; + char path[PATH_MAX] = {'\0'}; + bbfdm_data_t data; + int fault = 0; + LIST_HEAD(pv_list); + + memset(&data, 0, sizeof(bbfdm_data_t)); + + if (blobmsg_parse(dm_set_policy, __DM_SET_MAX, tb, blob_data(msg), blob_len(msg))) { + BBF_ERR("Failed to parse blob"); + return UBUS_STATUS_UNKNOWN_ERROR; + } + + if (!tb[DM_SET_PATH]) + return UBUS_STATUS_INVALID_ARGUMENT; + + if (!tb[DM_SET_VALUE] && !tb[DM_SET_OBJ_PATH]) + return UBUS_STATUS_INVALID_ARGUMENT; + + snprintf(path, PATH_MAX, "%s", (char *)blobmsg_data(tb[DM_SET_PATH])); + + fill_optional_data(&data, tb[DM_SET_OPTIONAL]); + + BBF_INFO("ubus method|%s|, name|%s|, path(%s)", method, obj->name, path); + + blob_buf_init(&data.bb, 0); + bbf_init(&data.bbf_ctx); + + data.ctx = ctx; + data.bbf_ctx.in_param = path; + + fault = fill_pvlist_set(&data, path, tb[DM_SET_VALUE] ? blobmsg_get_string(tb[DM_SET_VALUE]) : NULL, tb[DM_SET_OBJ_PATH], &pv_list); + if (fault) { + BBF_ERR("Fault in fill pvlist set path |%s| : |%d|", data.bbf_ctx.in_param, fault); + fill_err_code_array(&data, fault); + goto end; + } + + if (list_empty(&pv_list)) { + BBF_ERR("Fault in fill pvlist set path |%s| : |list is empty|", data.bbf_ctx.in_param); + fill_err_code_array(&data, USP_FAULT_INTERNAL_ERROR); + fault = USP_FAULT_INTERNAL_ERROR; + goto end; + } + + data.plist = &pv_list; + + fault = bbfdm_set_value(&data); + +end: + if ((data.bbf_ctx.dm_type == BBFDM_BOTH) && (dm_is_micro_service() == false)) { + bbf_entry_services(data.bbf_ctx.dm_type, (!fault) ? true : false, true); + } + + bbf_cleanup(&data.bbf_ctx); + free_pv_list(&pv_list); + + ubus_send_reply(ctx, req, data.bb.head); + blob_buf_free(&data.bb); + + return 0; +} + +static const struct blobmsg_policy dm_operate_policy[__DM_OPERATE_MAX] = { + [DM_OPERATE_COMMAND] = { .name = "command", .type = BLOBMSG_TYPE_STRING }, + [DM_OPERATE_COMMAND_KEY] = { .name = "command_key", .type = BLOBMSG_TYPE_STRING }, + [DM_OPERATE_INPUT] = { .name = "input", .type = BLOBMSG_TYPE_TABLE }, + [DM_OPERATE_OPTIONAL] = { .name = "optional", .type = BLOBMSG_TYPE_TABLE }, +}; + +static int bbfdm_operate_handler(struct ubus_context *ctx, struct ubus_object *obj __attribute__((unused)), + struct ubus_request_data *req, const char *method __attribute__((unused)), + struct blob_attr *msg) +{ + struct blob_attr *tb[__DM_OPERATE_MAX] = {NULL}; + char path[PATH_MAX] = {0}; + char *str = NULL; + bbfdm_data_t data; + + memset(&data, 0, sizeof(bbfdm_data_t)); + + if (blobmsg_parse(dm_operate_policy, __DM_OPERATE_MAX, tb, blob_data(msg), blob_len(msg))) { + BBF_ERR("Failed to parse blob"); + return UBUS_STATUS_UNKNOWN_ERROR; + } + + if (!(tb[DM_OPERATE_COMMAND])) + return UBUS_STATUS_INVALID_ARGUMENT; + + snprintf(path, PATH_MAX, "%s", (char *)blobmsg_data(tb[DM_OPERATE_COMMAND])); + + data.ctx = ctx; + data.req = req; + data.bbf_ctx.in_param = path; + data.bbf_ctx.linker = tb[DM_OPERATE_COMMAND_KEY] ? blobmsg_get_string(tb[DM_OPERATE_COMMAND_KEY]) : ""; + + if (tb[DM_OPERATE_INPUT]) { + str = blobmsg_format_json(tb[DM_OPERATE_INPUT], true); + data.bbf_ctx.in_value = str; + } + + fill_optional_data(&data, tb[DM_OPERATE_OPTIONAL]); + + BBF_INFO("ubus method|%s|, name|%s|, path(%s)", method, obj->name, data.bbf_ctx.in_param); + + if (is_sync_operate_cmd(&data)) { + bbfdm_operate_cmd(&data, NULL); + } else { + cancel_instance_refresh_timer(ctx); + bbfdm_start_deferred(&data, bbfdm_operate_cmd, true); + } + + FREE(str); + return 0; +} + +static const struct blobmsg_policy dm_add_policy[] = { + [DM_ADD_PATH] = { .name = "path", .type = BLOBMSG_TYPE_STRING }, + [DM_ADD_OBJ_PATH] = { .name = "obj_path", .type = BLOBMSG_TYPE_TABLE }, + [DM_ADD_OPTIONAL] = { .name = "optional", .type = BLOBMSG_TYPE_TABLE }, +}; + +int bbfdm_add_handler(struct ubus_context *ctx, struct ubus_object *obj, + struct ubus_request_data *req, const char *method, + struct blob_attr *msg) +{ + struct blob_attr *tb[__DM_ADD_MAX]; + char path[PATH_MAX]; + bbfdm_data_t data; + int fault = 0; + + memset(&data, 0, sizeof(bbfdm_data_t)); + + if (blobmsg_parse(dm_add_policy, __DM_ADD_MAX, tb, blob_data(msg), blob_len(msg))) { + BBF_ERR("Failed to parse blob"); + return UBUS_STATUS_UNKNOWN_ERROR; + } + + if (!tb[DM_ADD_PATH]) + return UBUS_STATUS_INVALID_ARGUMENT; + + snprintf(path, PATH_MAX, "%s", (char *)blobmsg_data(tb[DM_ADD_PATH])); + + data.ctx = ctx; + data.bbf_ctx.in_param = path; + + fill_optional_data(&data, tb[DM_ADD_OPTIONAL]); + + BBF_INFO("ubus method|%s|, name|%s|, path(%s)", method, obj->name, data.bbf_ctx.in_param); + + blob_buf_init(&data.bb, 0); + bbf_init(&data.bbf_ctx); + + fault = create_add_response(&data); + if (fault) { + BBF_ERR("Fault in add path |%s|", data.bbf_ctx.in_param); + goto end; + } + + if (tb[DM_ADD_OBJ_PATH]) { + LIST_HEAD(pv_list); + + snprintf(path, PATH_MAX, "%s%s.", (char *)blobmsg_data(tb[DM_ADD_PATH]), data.bbf_ctx.addobj_instance); + + fault = fill_pvlist_set(&data, path, NULL, tb[DM_ADD_OBJ_PATH], &pv_list); + if (fault) { + BBF_ERR("Fault in fill pvlist set path |%s|", path); + fill_err_code_array(&data, USP_FAULT_INTERNAL_ERROR); + free_pv_list(&pv_list); + goto end; + } + + data.plist = &pv_list; + + bbfdm_set_value(&data); + + free_pv_list(&pv_list); + } + +end: + if ((data.bbf_ctx.dm_type == BBFDM_BOTH) && (dm_is_micro_service() == false)) { + bbf_entry_services(data.bbf_ctx.dm_type, (!fault) ? true : false, false); + } + + bbf_cleanup(&data.bbf_ctx); + + ubus_send_reply(ctx, req, data.bb.head); + blob_buf_free(&data.bb); + + return 0; +} + +static const struct blobmsg_policy dm_del_policy[] = { + [DM_DEL_PATH] = { .name = "path", .type = BLOBMSG_TYPE_STRING }, + [DM_DEL_PATHS] = { .name = "paths", .type = BLOBMSG_TYPE_ARRAY }, + [DM_DEL_OPTIONAL] = { .name = "optional", .type = BLOBMSG_TYPE_TABLE }, +}; + +int bbfdm_del_handler(struct ubus_context *ctx, struct ubus_object *obj, + struct ubus_request_data *req, const char *method, + struct blob_attr *msg) +{ + struct blob_attr *tb[__DM_DEL_MAX]; + LIST_HEAD(paths_list); + bbfdm_data_t data; + int fault = 0; + + memset(&data, 0, sizeof(bbfdm_data_t)); + + if (blobmsg_parse(dm_del_policy, __DM_DEL_MAX, tb, blob_data(msg), blob_len(msg))) { + BBF_ERR("Failed to parse blob"); + return UBUS_STATUS_UNKNOWN_ERROR; + } + + if (!tb[DM_DEL_PATH] && !tb[DM_DEL_PATHS]) + return UBUS_STATUS_INVALID_ARGUMENT; + + if (tb[DM_DEL_PATH]) { + char *path = blobmsg_get_string(tb[DM_DEL_PATH]); + add_path_list(path, &paths_list); + } + + if (tb[DM_DEL_PATHS]) { + struct blob_attr *paths = tb[DM_DEL_PATHS]; + struct blob_attr *path = NULL; + size_t rem; + + blobmsg_for_each_attr(path, paths, rem) { + char *path_str = blobmsg_get_string(path); + + add_path_list(path_str, &paths_list); + } + } + + data.ctx = ctx; + data.plist = &paths_list; + + fill_optional_data(&data, tb[DM_DEL_OPTIONAL]); + + BBF_INFO("ubus method|%s|, name|%s|", method, obj->name); + + blob_buf_init(&data.bb, 0); + bbf_init(&data.bbf_ctx); + + data.bbf_ctx.in_param = tb[DM_DEL_PATH] ? blobmsg_get_string(tb[DM_DEL_PATH]) : ""; + + fault = create_del_response(&data); + + if ((data.bbf_ctx.dm_type == BBFDM_BOTH) && (dm_is_micro_service() == false)) { + bbf_entry_services(data.bbf_ctx.dm_type, (!fault) ? true : false, true); + } + + bbf_cleanup(&data.bbf_ctx); + free_path_list(&paths_list); + + ubus_send_reply(ctx, req, data.bb.head); + blob_buf_free(&data.bb); + + return 0; +} + +enum { + BBF_SERVICE_CMD, + BBF_SERVICE_NAME, + BBF_SERVICE_PARENT_DM, + BBF_SERVICE_OBJECTS, + __BBF_SERVICE_MAX, +}; + +static const struct blobmsg_policy service_policy[] = { + [BBF_SERVICE_CMD] = { .name = "cmd", .type = BLOBMSG_TYPE_STRING }, + [BBF_SERVICE_NAME] = { .name = "name", .type = BLOBMSG_TYPE_STRING }, + [BBF_SERVICE_PARENT_DM] = { .name = "parent_dm", .type = BLOBMSG_TYPE_STRING }, + [BBF_SERVICE_OBJECTS] = { .name = "objects", .type = BLOBMSG_TYPE_ARRAY }, +}; + +static void service_list(struct blob_buf *bb) +{ + void *array; + + array = blobmsg_open_array(bb, "supported_cmd"); + blobmsg_add_string(bb, NULL, "register"); + blobmsg_add_string(bb, NULL, "list"); + blobmsg_close_array(bb, array); + + array = blobmsg_open_array(bb, "registered_service"); + get_list_of_registered_service(&head_registered_service, bb); + blobmsg_close_array(bb, array); +} + +static int bbfdm_service_handler(struct ubus_context *ctx, struct ubus_object *obj, + struct ubus_request_data *req __attribute__((unused)), const char *method, + struct blob_attr *msg) +{ + struct blob_attr *tb[__BBF_SERVICE_MAX] = {NULL}; + struct blob_buf bb; + struct bbfdm_context *u; + + u = container_of(ctx, struct bbfdm_context, ubus_ctx); + if (u == NULL) { + BBF_ERR("Failed to get the bbfdm context"); + return 0; + } + + memset(&bb, 0, sizeof(struct blob_buf)); + blob_buf_init(&bb, 0); + + if (blobmsg_parse(service_policy, __BBF_SERVICE_MAX, tb, blob_data(msg), blob_len(msg))) { + service_list(&bb); + goto end; + } + + BBF_INFO("ubus method|%s|, name|%s|", method, obj->name); + + if (dm_is_micro_service() == true) { // It's a micro-service instance + blobmsg_add_string(&bb, "error", "Its not allowed to register a micro-service for another micro-service!!"); + goto end; + } + + if (!tb[BBF_SERVICE_CMD]) { + service_list(&bb); + goto end; + } + + char *srv_cmd = blobmsg_get_string(tb[BBF_SERVICE_CMD]); + + if (is_str_eq(srv_cmd, "register")) { + + if (!tb[BBF_SERVICE_NAME]) { + blobmsg_add_string(&bb, "error", "service name should be defined!!"); + goto end; + } + + if (!tb[BBF_SERVICE_PARENT_DM]) { + blobmsg_add_string(&bb, "error", "service parent dm should be defined!!"); + goto end; + } + + if (!tb[BBF_SERVICE_OBJECTS]) { + blobmsg_add_string(&bb, "error", "service objects should be defined!!"); + goto end; + } + + char *srv_name = blobmsg_get_string(tb[BBF_SERVICE_NAME]); + char *srv_parent_dm = blobmsg_get_string(tb[BBF_SERVICE_PARENT_DM]); + bool res = true; + + if (tb[BBF_SERVICE_OBJECTS]) { + struct blob_attr *objs = tb[BBF_SERVICE_OBJECTS]; + struct blob_attr *attr_obj = NULL; + size_t rem; + + blobmsg_for_each_attr(attr_obj, objs, rem) { + char *srv_obj = blobmsg_get_string(attr_obj); + res |= load_service(DEAMON_DM_ROOT_OBJ, &head_registered_service, srv_name, srv_parent_dm, srv_obj); + } + } else { + res = false; + } + + blobmsg_add_u8(&bb, "status", res); + run_schema_updater(u); + } else { + service_list(&bb); + } + +end: + ubus_send_reply(ctx, req, bb.head); + blob_buf_free(&bb); + + return 0; +} + +enum { + BBF_NOTIFY_NAME, + BBF_NOTIFY_PRAMS, + __BBF_NOTIFY_MAX, +}; + +static const struct blobmsg_policy dm_notify_event_policy[] = { + [BBF_NOTIFY_NAME] = { .name = "name", .type = BLOBMSG_TYPE_STRING }, + [BBF_NOTIFY_PRAMS] = { .name = "input", .type = BLOBMSG_TYPE_ARRAY }, +}; + +static int bbfdm_notify_event(struct ubus_context *ctx, struct ubus_object *obj, + struct ubus_request_data *req __attribute__((unused)), const char *method, + struct blob_attr *msg) +{ + struct blob_attr *tb[__BBF_NOTIFY_MAX] = {NULL}; + char method_name[256] = {0}; + struct bbfdm_context *u; + + u = container_of(ctx, struct bbfdm_context, ubus_ctx); + if (u == NULL) { + BBF_ERR("failed to get the bbfdm context"); + return UBUS_STATUS_UNKNOWN_ERROR; + } + + if (blobmsg_parse(dm_notify_event_policy, __BBF_NOTIFY_MAX, tb, blob_data(msg), blob_len(msg))) { + BBF_ERR("Failed to parse blob"); + return UBUS_STATUS_UNKNOWN_ERROR; + } + + if (!tb[BBF_NOTIFY_NAME]) + return UBUS_STATUS_INVALID_ARGUMENT; + + BBF_INFO("ubus method|%s|, name|%s|", method, obj->name); + snprintf(method_name, sizeof(method_name), "%s.%s", DM_STRLEN(u->config.out_root_obj) ? u->config.out_root_obj : u->config.out_name, BBF_EVENT_NAME); + ubus_send_event(ctx, method_name, msg); + + return 0; +} + +static struct ubus_method bbf_methods[] = { + UBUS_METHOD("get", bbfdm_get_handler, dm_get_policy), + UBUS_METHOD("schema", bbfdm_schema_handler, dm_schema_policy), + UBUS_METHOD("instances", bbfdm_instances_handler, dm_instances_policy), + UBUS_METHOD("set", bbfdm_set_handler, dm_set_policy), + UBUS_METHOD("operate", bbfdm_operate_handler, dm_operate_policy), + UBUS_METHOD("add", bbfdm_add_handler, dm_add_policy), + UBUS_METHOD("del", bbfdm_del_handler, dm_del_policy), + UBUS_METHOD("service", bbfdm_service_handler, service_policy), + UBUS_METHOD("notify_event", bbfdm_notify_event, dm_notify_event_policy), +}; + +static struct ubus_object_type bbf_type = UBUS_OBJECT_TYPE("", bbf_methods); + +static struct ubus_object bbf_object = { + .name = "", + .type = &bbf_type, + .methods = bbf_methods, + .n_methods = ARRAY_SIZE(bbf_methods) +}; + +static void run_schema_updater(struct bbfdm_context *u) +{ + bool ret; + char method_name[256] = {0}; + + ret = is_object_schema_update_available(u); + if (ret && (dm_is_micro_service() == false)) { + struct blob_buf bb; + + memset(&bb, 0, sizeof(struct blob_buf)); + BBF_INFO("Schema update available"); + snprintf(method_name, sizeof(method_name), "%s.%s", u->config.out_name, BBF_UPDATE_SCHEMA_EVENT); + blob_buf_init(&bb, 0); + ubus_send_event(&u->ubus_ctx, method_name, bb.head); + blob_buf_free(&bb); + } +} + +static void broadcast_add_del_event(struct ubus_context *ctx, const char *method, struct list_head *inst, bool is_add) +{ + struct blob_buf bb; + struct pathNode *ptr; + char method_name[40]; + void *a; + + if (list_empty(inst)) { + return; + } + + memset(&bb, 0, sizeof(struct blob_buf)); + blob_buf_init(&bb, 0); + + a = blobmsg_open_array(&bb, "instances"); + list_for_each_entry(ptr, inst, list) { + blobmsg_add_string(&bb, NULL, ptr->path); + BBF_DEBUG("#%s:: %s, method %s #", (is_add)?"Add":"Del", ptr->path, method); + } + blobmsg_close_array(&bb, a); + + snprintf(method_name, sizeof(method_name), "%s.%s", method, is_add ? BBF_ADD_EVENT : BBF_DEL_EVENT); + + if (is_add) + ubus_send_event(ctx, method_name, bb.head); + else + ubus_send_event(ctx, method_name, bb.head); + + blob_buf_free(&bb); +} + +static void update_instances_list(struct list_head *inst) +{ + int ret; + struct dmctx bbf_ctx = { + .in_param = ROOT_NODE, + .nextlevel = false, + .disable_mservice_browse = true, + .dm_type = BBFDM_BOTH + }; + + bbf_init(&bbf_ctx); + + ret = bbfdm_cmd_exec(&bbf_ctx, BBF_INSTANCES); + if (ret == 0) { + struct blob_attr *cur = NULL; + size_t rem = 0; + + // Apply all bbfdm changes + dmuci_commit_bbfdm(); + + blobmsg_for_each_attr(cur, bbf_ctx.bb.head, rem) { + struct blob_attr *tb[1] = {0}; + const struct blobmsg_policy p[1] = { + { "path", BLOBMSG_TYPE_STRING } + }; + + blobmsg_parse(p, 1, tb, blobmsg_data(cur), blobmsg_len(cur)); + + char *name = (tb[0]) ? blobmsg_get_string(tb[0]) : ""; + + add_path_list(name, inst); + } + } else { + BBF_WARNING("Failed to get instances, err code %d", ret); + } + + bbf_cleanup(&bbf_ctx); +} + +static void instance_compare_publish(struct bbfdm_context *daemon_ctx) +{ + struct pathNode *ptr; + LIST_HEAD(inst_list); + struct list_head *new_inst, *old_inst; + const char *method; + + new_inst = &daemon_ctx->instances; + old_inst = &daemon_ctx->old_instances; + + method = DM_STRLEN(daemon_ctx->config.out_root_obj) ? daemon_ctx->config.out_root_obj : daemon_ctx->config.out_name; + list_for_each_entry(ptr, old_inst, list) { + if (!present_in_path_list(new_inst, ptr->path)) { + add_path_list(ptr->path, &inst_list); + } + } + broadcast_add_del_event(&daemon_ctx->ubus_ctx, method, &inst_list, false); + free_path_list(&inst_list); + + list_for_each_entry(ptr, new_inst, list) { + if (!present_in_path_list(old_inst, ptr->path)) { + add_path_list(ptr->path, &inst_list); + } + } + broadcast_add_del_event(&daemon_ctx->ubus_ctx, method, &inst_list, true); + free_path_list(&inst_list); +} + +static void periodic_instance_updater(struct uloop_timeout *t) +{ + struct bbfdm_context *u; + + u = container_of(t, struct bbfdm_context, instance_timer); + if (u == NULL) { + BBF_ERR("Failed to get the bbfdm context"); + return; + } + + if (list_empty(&u->instances)) { + if (!list_empty(&u->old_instances)) { + list_splice_init(&u->old_instances, &u->instances); + } else { + update_instances_list(&u->instances); + return; + } + } + + free_path_list(&u->old_instances); + list_splice_init(&u->instances, &u->old_instances); + + update_instances_list(&u->instances); + if (!list_empty(&u->instances) && !list_empty(&u->old_instances)) { + BBF_INFO("Comparing instances ..."); + instance_compare_publish(u); + } +} + +static int register_service(struct ubus_context *ctx) +{ + struct blob_buf bb = {0}; + uint32_t ubus_id; + struct bbfdm_context *u; + + u = container_of(ctx, struct bbfdm_context, ubus_ctx); + if (u == NULL) { + BBF_ERR("failed to get the bbfdm context"); + return false; + } + // check if object already present + int ret = ubus_lookup_id(ctx, u->config.out_root_obj, &ubus_id); + if (ret != 0) + return ret; + + memset(&bb, 0, sizeof(struct blob_buf)); + blob_buf_init(&bb, 0); + + blobmsg_add_string(&bb, "cmd", "register"); + blobmsg_add_string(&bb, "name", u->config.out_name); + blobmsg_add_string(&bb, "parent_dm", u->config.out_parent_dm); + + void *arr = blobmsg_open_array(&bb, "objects"); + for (int i = 0; i < MAX_OBJS && DM_STRLEN(u->config.out_objects[i]) != 0; i++) + blobmsg_add_string(&bb, NULL, u->config.out_objects[i]); + blobmsg_close_array(&bb, arr); + + ubus_invoke(ctx, ubus_id, "service", bb.head, NULL, NULL, 5000); + blob_buf_free(&bb); + + return 0; +} + +static int _parse_daemon_config_options(bbfdm_config_t *config, json_object *daemon_obj) +{ + char *opt_val = NULL; + + if (!config || !daemon_obj) { + fprintf(stderr, "Invalid input options \n"); + return -1; + } + + opt_val = dmjson_get_value(daemon_obj, 2, "config", "loglevel"); + if (DM_STRLEN(opt_val)) { + int log_level = (int) strtoul(opt_val, NULL, 10); + bbfdm_ubus_set_log_level(log_level); + } else { + bbfdm_ubus_set_log_level(LOG_ERR); + } + + opt_val = dmjson_get_value(daemon_obj, 2, "config", "subprocess_level"); + if (DM_STRLEN(opt_val)) { + config->subprocess_level = (unsigned int) strtoul(opt_val, NULL, 10); + } else { + config->subprocess_level = 0; + } + return 0; +} + +static int _parse_daemon_input_options(bbfdm_config_t *config, json_object *daemon_obj) +{ + char *opt_val = NULL; + + if (!config || !daemon_obj) { + fprintf(stderr, "Invalid input options \n"); + return -1; + } + + opt_val = dmjson_get_value(daemon_obj, 2, "input", "plugin_dir"); + if (DM_STRLEN(opt_val)) { + strncpyt(config->in_plugin_dir, opt_val, sizeof(config->in_plugin_dir)); + } else if(dm_is_micro_service() == false) { + strncpyt(config->in_plugin_dir, BBFDM_DEFAULT_PLUGINS_PATH, sizeof(config->in_plugin_dir)); + } + + opt_val = dmjson_get_value(daemon_obj, 2, "input", "name"); + if (DM_STRLEN(opt_val)) { + strncpyt(config->in_name, opt_val, sizeof(config->in_name)); + + opt_val = strrchr(opt_val, '/'); + if (opt_val) { + strncpyt(config->service_name, opt_val + 1, sizeof(config->service_name)); + } + } else if (dm_is_micro_service() == false) { // default value for main process + snprintf(config->in_name, sizeof(config->in_name), "%s/libbbfdm.so", BBFDM_DEFAULT_MODULES_PATH); + strncpyt(config->service_name, BBFDM_DEFAULT_UBUS_OBJ, sizeof(config->service_name)); + } + return 0; +} + +static int _fill_daemon_input_option(bbfdm_config_t *config, char *sname) +{ + char opt_val[MAX_DM_PATH] = {0}; + + if (!config || !sname || strlen(sname) == 0) { + fprintf(stderr, "Invalid input options for service name \n"); + return -1; + } + + strncpyt(config->service_name, sname, sizeof(config->service_name)); + + // check if the service plugin is DotSO plugin + snprintf(opt_val, MAX_DM_PATH, "%s/%s.so", BBFDM_DEFAULT_MICROSERVICE_MODULE_PATH, sname); + if (!file_exists(opt_val)) { + snprintf(opt_val, MAX_DM_PATH, "%s/%s.json", BBFDM_DEFAULT_MICROSERVICE_MODULE_PATH, sname); + } + + if (!file_exists(opt_val)) { + fprintf(stderr, "Failed to load service plugin %s opt_val=%s\n", sname, opt_val); + return -1; + } + + strncpyt(config->in_name, opt_val, sizeof(config->in_name)); + + snprintf(opt_val, MAX_DM_PATH, "%s/%s", BBFDM_DEFAULT_MICROSERVICE_MODULE_PATH, sname); + if (folder_exists(opt_val)) { + strncpyt(config->in_plugin_dir, opt_val, sizeof(config->in_plugin_dir)); + } + + return 0; +} + +static int _parse_daemon_output_options(bbfdm_config_t *config, json_object *daemon_obj) +{ + char *opt_val = NULL; + + if (!config || !daemon_obj) { + fprintf(stderr, "Invalid input options \n"); + return -1; + } + + opt_val = dmjson_get_value(daemon_obj, 2, "output", "root_obj"); + if (DM_STRLEN(opt_val)) { + strncpyt(config->out_root_obj, opt_val, sizeof(config->out_root_obj)); + } else if (dm_is_micro_service() == true) { // for main process, there is no root obj + strncpyt(config->out_root_obj, BBFDM_DEFAULT_UBUS_OBJ, sizeof(config->out_root_obj)); + } + + opt_val = dmjson_get_value(daemon_obj, 2, "output", "name"); + if (strlen(opt_val)) { + snprintf(config->out_name, sizeof(config->out_name), "%s%s%s", + dm_is_micro_service() ? config->out_root_obj : opt_val, + dm_is_micro_service() ? "." : "", + dm_is_micro_service() ? opt_val : ""); + } else { + snprintf(config->out_name, sizeof(config->out_name), "%s", dm_is_micro_service() ? "" : BBFDM_DEFAULT_UBUS_OBJ); + } + + return 0; +} + +static int _parse_daemon_internal_data_model(bbfdm_config_t *config) +{ + char opt_val[MAX_DM_PATH] = {0}; + + if (!config || !strlen(config->service_name)) + return -1; + + strncpyt(config->in_name, "internal_dm.so", sizeof(config->in_name)); + + snprintf(opt_val, MAX_DM_PATH, "%s/%s", BBFDM_DEFAULT_MICROSERVICE_MODULE_PATH, config->service_name); + if (folder_exists(opt_val)) { + strncpyt(config->in_plugin_dir, opt_val, sizeof(config->in_plugin_dir)); + } + + strncpyt(config->out_root_obj, BBFDM_DEFAULT_UBUS_OBJ, sizeof(config->out_root_obj)); + + return 0; +} + +static int bbfdm_load_deamon_config(bbfdm_config_t *config) +{ + json_object *json_obj = NULL; + char json_path[MAX_DM_PATH] = {0}; + int err = 0; + + if (INTERNAL_ROOT_TREE) { // internal data model + return _parse_daemon_internal_data_model(config); + } + + if (dm_is_micro_service() == false) { // Main daemon + strncpyt(json_path, BBFDM_JSON_INPUT, MAX_DM_PATH); + } else { // Micro-services + snprintf(json_path, MAX_DM_PATH, "%s/%s.json", BBFDM_DEFAULT_MICROSERVICE_INPUT_PATH, config->service_name); + } + + json_obj = json_object_from_file(json_path); + if (!json_obj) { + fprintf(stderr, "Failed to read input %s file \n", json_path); + return -1; + } + + json_object *daemon_obj = dmjson_get_obj(json_obj, 1, "daemon"); + if (!daemon_obj) { + err = -1; + goto exit; + } + + _parse_daemon_config_options(config, daemon_obj); + + char *opt_val = dmjson_get_value(daemon_obj, 1, "service_name"); + if (strlen(opt_val)) { + err = _fill_daemon_input_option(config, opt_val); + } else { + err = _parse_daemon_input_options(config, daemon_obj); + } + + if (err == -1) { + goto exit; + } + + _parse_daemon_output_options(config, daemon_obj); + + json_object_put(json_obj); + return err; +exit: + if (json_obj) { + json_object_put(json_obj); + } + + return err; +} + +static int bbfdm_regiter_ubus(struct ubus_context *ctx) +{ + int ret; + struct bbfdm_context *u; + + u = container_of(ctx, struct bbfdm_context, ubus_ctx); + if (u == NULL) { + BBF_ERR("failed to get the bbfdm context"); + return -1; + } + + bbf_object.name = u->config.out_name; + bbf_object.type->name = u->config.out_name; + if (dm_is_micro_service()) { + bbf_object.n_methods = bbf_object.n_methods - 2; + bbf_object.type->n_methods = bbf_object.n_methods; + ret = ubus_add_object(ctx, &bbf_object); + } else { + ret = ubus_add_object(ctx, &bbf_object); + } + return ret; +} + +static void lookup_event_cb(struct ubus_context *ctx, + struct ubus_event_handler *ev __attribute__((unused)), + const char *type, struct blob_attr *msg) +{ + const struct blobmsg_policy policy = { + "path", BLOBMSG_TYPE_STRING + }; + struct blob_attr *attr; + const char *path; + struct bbfdm_context *u; + + u = container_of(ctx, struct bbfdm_context, ubus_ctx); + if (u == NULL) { + BBF_ERR("failed to get the bbfdm context"); + return; + } + + if (type && strcmp(type, "ubus.object.add") != 0) + return; + + blobmsg_parse(&policy, 1, &attr, blob_data(msg), blob_len(msg)); + + if (!attr) + return; + + path = blobmsg_data(attr); + if (path && strcmp(path, u->config.out_root_obj) == 0) { + // register micro-service + register_service(ctx); + } +} + +void register_instance_refresh_timer(struct ubus_context *ctx, int start_in) +{ + struct bbfdm_context *u; + + u = container_of(ctx, struct bbfdm_context, ubus_ctx); + if (u == NULL) { + BBF_ERR("Failed to get the bbfdm context"); + return; + } + + if (start_in >= 0) { + BBF_INFO("Register instance refresh timer in %d ms...", start_in); + u->instance_timer.cb = periodic_instance_updater; + uloop_timeout_set(&u->instance_timer, start_in); + } +} + +void cancel_instance_refresh_timer(struct ubus_context *ctx) +{ + struct bbfdm_context *u; + + u = container_of(ctx, struct bbfdm_context, ubus_ctx); + if (u == NULL) { + BBF_ERR("Failed to get the bbfdm context"); + return; + } + + BBF_DEBUG("Cancelling Instance refresh timer"); + uloop_timeout_cancel(&u->instance_timer); +} + +static void bbf_config_change_cb(struct ubus_context *ctx, struct ubus_event_handler *ev, + const char *type, struct blob_attr *msg) +{ + (void)ev; + (void)ctx; + (void)msg; + + if (type && strcmp(type, "bbf.config.change") != 0) + return; + + BBF_INFO("Config updated, Scheduling instance refresh timers"); + + cancel_instance_refresh_timer(ctx); + register_instance_refresh_timer(ctx, 0); +} + +static void bbfdm_ctx_init(struct bbfdm_context *bbfdm_ctx) +{ + INIT_LIST_HEAD(&bbfdm_ctx->instances); + INIT_LIST_HEAD(&bbfdm_ctx->old_instances); + INIT_LIST_HEAD(&bbfdm_ctx->event_handlers); +} + +static int daemon_load_datamodel(struct bbfdm_context *daemon_ctx) +{ + int err = -1; + char *file_path = daemon_ctx->config.in_name; + + if (DM_STRLEN(file_path) == 0) { + BBF_ERR("Input type/name not supported or defined"); + return -1; + } + + char *ext = strrchr(file_path, '.'); + if (ext == NULL) { + BBF_ERR("Input file without extension"); + } else if (strcasecmp(ext, ".json") == 0) { + BBF_INFO("Loading JSON plugin %s", file_path); + err = load_json_plugin(&loaded_json_files, &json_list, &json_memhead, file_path, &daemon_ctx->config, &DEAMON_DM_ROOT_OBJ); + } else if (strcasecmp(ext, ".so") == 0) { + BBF_INFO("Loading DotSo plugin %s", file_path); + err = load_dotso_plugin(&deamon_lib_handle, file_path, &daemon_ctx->config, &DEAMON_DM_ROOT_OBJ); + } else { + BBF_ERR("Input type %s not supported", ext); + } + + if (!err) { + BBF_INFO("Loading sub-modules %s", daemon_ctx->config.in_plugin_dir); + bbf_global_init(DEAMON_DM_ROOT_OBJ, daemon_ctx->config.in_plugin_dir); + } else { + BBF_ERR("Failed loading %s", file_path); + } + + if (DM_STRLEN(daemon_ctx->config.out_name) == 0) { + BBF_ERR("output name not defined"); + return -1; + } + + if (dm_is_micro_service()) { + if (DM_STRLEN(daemon_ctx->config.out_parent_dm) == 0) { + BBF_ERR("output parent dm not defined"); + return -1; + } + + if (DM_STRLEN(daemon_ctx->config.out_objects[0]) == 0) { + BBF_ERR("output objects is not defined"); + return -1; + } + + if (DM_STRLEN(daemon_ctx->config.out_root_obj) == 0) { + BBF_ERR("output root obj not defined"); + return -1; + } + + if (DM_STRLEN(daemon_ctx->config.out_name) == 0) { + BBF_ERR("output name obj not defined"); + return -1; + } + } + + return err; +} + +static struct ubus_event_handler add_event = { .cb = lookup_event_cb }; +static struct ubus_event_handler config_change_handler = { .cb = bbf_config_change_cb }; + +int bbfdm_ubus_regiter_init(struct bbfdm_context *bbfdm_ctx) +{ + int err = 0; + + err = ubus_connect_ctx(&bbfdm_ctx->ubus_ctx, NULL); + if (err != UBUS_STATUS_OK) { + fprintf(stderr, "Failed to connect to ubus"); + return err; + } + + uloop_init(); + ubus_add_uloop(&bbfdm_ctx->ubus_ctx); + + bbfdm_ctx_init(bbfdm_ctx); + + err = bbfdm_load_deamon_config(&bbfdm_ctx->config); + if (err) { + fprintf(stderr, "Failed to load %s deamon config\n", bbfdm_ctx->config.service_name); + return err; + } + + err = daemon_load_datamodel(bbfdm_ctx); + if (err) { + BBF_ERR("Failed to load datamodel"); + return err; + } + + err = bbfdm_regiter_ubus(&bbfdm_ctx->ubus_ctx); + if (err != UBUS_STATUS_OK) + return -1; + + run_schema_updater(bbfdm_ctx); + register_instance_refresh_timer(&bbfdm_ctx->ubus_ctx, 1000); + + err = register_events_to_ubus(&bbfdm_ctx->ubus_ctx, &bbfdm_ctx->event_handlers); + if (err != 0) + return err; + + err = ubus_register_event_handler(&bbfdm_ctx->ubus_ctx, &config_change_handler, "bbf.config.change"); + if (err != 0) + return err; + + if (dm_is_micro_service() == true) { + // Register the micro-service + register_service(&bbfdm_ctx->ubus_ctx); + + // If the micro-service is not registered, listen for "ubus.object.add" event + // and register the micro-service using event handler for it + err = ubus_register_event_handler(&bbfdm_ctx->ubus_ctx, &add_event, "ubus.object.add"); + if (err != 0) + return err; + } + + return 0; +} + +int bbfdm_ubus_regiter_free(struct bbfdm_context *bbfdm_ctx) +{ + free_ubus_event_handler(&bbfdm_ctx->ubus_ctx, &bbfdm_ctx->event_handlers); + bbfdm_ctx_cleanup(bbfdm_ctx); + uloop_done(); + ubus_shutdown(&bbfdm_ctx->ubus_ctx); + + return 0; +} + +void bbfdm_ubus_set_service_name(struct bbfdm_context *bbfdm_ctx, const char *srv_name) +{ + strncpyt(bbfdm_ctx->config.service_name, srv_name, sizeof(bbfdm_ctx->config.service_name)); + dm_set_micro_service(); +} + +void bbfdm_ubus_set_log_level(int log_level) +{ + setlogmask(LOG_UPTO(log_level)); +} + +void bbfdm_ubus_load_data_model(DM_MAP_OBJ *DynamicObj) +{ + INTERNAL_ROOT_TREE = DynamicObj; +} diff --git a/bbfdmd/ubus/bbfdmd.h b/libbbfdm-ubus/bbfdm-ubus.h similarity index 75% rename from bbfdmd/ubus/bbfdmd.h rename to libbbfdm-ubus/bbfdm-ubus.h index 5e0154b9f2ad742e09748d125d7d0da98b757f24..e4876013a5e3617c92386b145b1276c90c2acdf5 100644 --- a/bbfdmd/ubus/bbfdmd.h +++ b/libbbfdm-ubus/bbfdm-ubus.h @@ -1,14 +1,21 @@ -#ifndef BBFDMD_H -#define BBFDMD_H +#ifndef BBFDM_UBUS_H +#define BBFDM_UBUS_H #include <libubus.h> #include <libubox/blobmsg.h> #include <libubox/list.h> -#include "dmbbf.h" +#include <libbbfdm-api/dmbbf.h> +#define BBFDM_DEFAULT_MICROSERVICE_INPUT_PATH "/etc/bbfdm/micro_services" #define MAX_OBJS 5 +#ifndef DAEMON_JSON_INPUT +#define BBFDM_JSON_INPUT "/tmp/bbfdm/input.json" +#else +#define BBFDM_JSON_INPUT DAEMON_JSON_INPUT +#endif + struct bbfdm_async_req { struct ubus_context *ctx; struct ubus_request_data req; @@ -20,7 +27,6 @@ struct bbfdm_async_req { typedef struct bbfdm_config { int proto; // Protocol identifier, Possible values: { '0'<both>, '1'<cwmp>, '2'<usp> } int subprocess_level; // Subprocess level - uint8_t log_level; // Log level, Possible values: { '1', '2', '3', '4' } uint32_t refresh_time; // Refresh time char service_name[16]; // Service name for micro-service identification char in_type[32]; // Input type, Possible values: { 'JSON', 'DotSo' } @@ -66,4 +72,11 @@ typedef struct bbfdm_data { void register_instance_refresh_timer(struct ubus_context *ctx, int start_sec); void cancel_instance_refresh_timer(struct ubus_context *ctx); -#endif /* BBFDMD_H */ +int bbfdm_ubus_regiter_init(struct bbfdm_context *bbfdm_ctx); +int bbfdm_ubus_regiter_free(struct bbfdm_context *bbfdm_ctx); + +void bbfdm_ubus_set_service_name(struct bbfdm_context *bbfdm_ctx, const char *srv_name); +void bbfdm_ubus_set_log_level(int log_level); +void bbfdm_ubus_load_data_model(DM_MAP_OBJ *DynamicObj); + +#endif /* BBFDM_UBUS_H */ diff --git a/bbfdmd/ubus/common.c b/libbbfdm-ubus/common.c similarity index 78% rename from bbfdmd/ubus/common.c rename to libbbfdm-ubus/common.c index 61de3d3e1bfe992857a1a12728d26a12d12e1eb0..e0e2b212b3a8af7e99f8dd100fe4a6cd40f3147a 100644 --- a/bbfdmd/ubus/common.c +++ b/libbbfdm-ubus/common.c @@ -12,61 +12,6 @@ #include "common.h" #include "get_helper.h" -// Logging utilities -void set_debug_level(unsigned char level) -{ - gLogLevel = level; -} - -void print_error(const char *format, ...) -{ - va_list arglist; - - if (gLogLevel < 1) - return; - - va_start(arglist, format); - vsyslog(LOG_ERR, format, arglist); - va_end(arglist); -} - -void print_warning(const char *format, ...) -{ - va_list arglist; - - if (gLogLevel < 2) - return; - - va_start(arglist, format); - vsyslog(LOG_WARNING, format, arglist); - va_end(arglist); -} - -void print_info(const char *format, ...) -{ - va_list arglist; - - if (gLogLevel < 3) - return; - - va_start(arglist, format); - vsyslog(LOG_INFO, format, arglist); - va_end(arglist); -} - -void print_debug(const char *format, ...) -{ - va_list arglist; - - if (gLogLevel < 4) - return; - - va_start(arglist, format); - vsyslog(LOG_DEBUG, format, arglist); - va_end(arglist); -} - - bool is_str_eq(const char *s1, const char *s2) { if (strcmp(s1, s2) == 0) @@ -95,7 +40,7 @@ bool is_node_instance(char *path) bool ret = false; char *rb = NULL; - DEBUG("entry |%s|", path); + BBF_DEBUG("entry |%s|", path); if (!path) return false; @@ -138,7 +83,7 @@ bool validate_msglen(bbfdm_data_t *data) size_t data_len = blob_pad_len(data->bbf_ctx.bb.head); if (data_len >= DEF_IPC_DATA_LEN) { - ERR("Blob exceed max len(%zd), data len(%zd)", DEF_IPC_DATA_LEN, data_len); + BBF_ERR("Blob exceed max len(%d), data len(%zd)", DEF_IPC_DATA_LEN, data_len); blob_buf_free(&data->bbf_ctx.bb); blob_buf_init(&data->bbf_ctx.bb, 0); fill_err_code_table(data, FAULT_9002); diff --git a/bbfdmd/ubus/common.h b/libbbfdm-ubus/common.h similarity index 71% rename from bbfdmd/ubus/common.h rename to libbbfdm-ubus/common.h index 4721838efd1e34c8d1ebff36ee2d11c8d7302725..e439e427fd1ff470838e8eab602ed5bbc3468db4 100644 --- a/bbfdmd/ubus/common.h +++ b/libbbfdm-ubus/common.h @@ -15,8 +15,7 @@ #include <libubox/list.h> #include "dmcommon.h" - -#include "bbfdmd.h" +#include "bbfdm-ubus.h" #define STRINGIFY(x) #x #define TO_STR(x) STRINGIFY(x) @@ -43,34 +42,18 @@ #define GLOB_EXPR "[=><]+" extern DMOBJ *DEAMON_DM_ROOT_OBJ; +extern DM_MAP_OBJ *INTERNAL_ROOT_TREE; bool is_str_eq(const char *s1, const char *s2); bool is_node_instance(char *path); int count_delim(const char *path); -void set_debug_level(unsigned char level); -void print_error(const char *format, ...); -void print_warning(const char *format, ...); -void print_info(const char *format, ...); -void print_debug(const char *format, ...); bool get_boolean_string(char *value); bool validate_msglen(bbfdm_data_t *data); int get_dm_type(char *dm_type); int get_proto_type(const char *proto); -#define DEBUG(fmt, args...) \ - print_debug("[%s:%d]"fmt, __func__, __LINE__, ##args) - -#define INFO(fmt, args...) \ - print_info(fmt, ##args) - -#define ERR(fmt, args...) \ - print_error("[%s:%d] " fmt, __func__, __LINE__, ##args) - -#define WARNING(fmt, args...) \ - print_warning("[%s:%d] " fmt, __func__, __LINE__, ##args) - int get_resolved_paths(struct dmctx *bbf_ctx, char *qpath, struct list_head *resolved_paths); void strncpyt(char *dst, const char *src, size_t n); diff --git a/bbfdmd/ubus/events.c b/libbbfdm-ubus/events.c similarity index 95% rename from bbfdmd/ubus/events.c rename to libbbfdm-ubus/events.c index 09efd5a7eec81f7330145ae3f0e56e280f45daeb..bb62efb0bf0bce174a0c057767c9f1b3548c9b3d 100644 --- a/bbfdmd/ubus/events.c +++ b/libbbfdm-ubus/events.c @@ -12,7 +12,6 @@ #include "common.h" #include "events.h" #include "get_helper.h" -#include "bbfdmd.h" #include <libubus.h> static char *get_events_dm_path(struct list_head *ev_list, const char *event) @@ -38,7 +37,7 @@ static void bbfdm_event_handler(struct ubus_context *ctx, struct ubus_event_hand u = container_of(ctx, struct bbfdm_context, ubus_ctx); if (u == NULL) { - ERR("Failed to get the bbfdm context"); + BBF_ERR("Failed to get the bbfdm context"); return; } @@ -81,7 +80,7 @@ static void bbfdm_event_handler(struct ubus_context *ctx, struct ubus_event_hand snprintf(method_name, sizeof(method_name), "%s.%s", DM_STRLEN(u->config.out_root_obj) ? u->config.out_root_obj : u->config.out_name, BBF_EVENT_NAME); ubus_send_event(ctx, method_name, bbf_ctx.bb.head); - INFO("Event[%s], for [%s] sent", method_name, dm_path); + BBF_INFO("Event[%s], for [%s] sent", method_name, dm_path); register_instance_refresh_timer(ctx, 2000); @@ -99,7 +98,7 @@ static void add_ubus_event_handler(struct ubus_event_handler *ev, const char *ev node = (struct ev_handler_node *) malloc(sizeof(struct ev_handler_node)); if (!node) { - ERR("Out of memory!"); + BBF_ERR("Out of memory!"); return; } @@ -150,7 +149,7 @@ int register_events_to_ubus(struct ubus_context *ctx, struct list_head *ev_list) struct ubus_event_handler *ev = (struct ubus_event_handler *)malloc(sizeof(struct ubus_event_handler)); if (!ev) { - ERR("Out of memory!"); + BBF_ERR("Out of memory!"); err = -1; goto end; } @@ -159,7 +158,7 @@ int register_events_to_ubus(struct ubus_context *ctx, struct list_head *ev_list) ev->cb = bbfdm_event_handler; if (0 != ubus_register_event_handler(ctx, ev, event_name)) { - ERR("Failed to register: %s", event_name); + BBF_ERR("Failed to register: %s", event_name); err = -1; goto end; } diff --git a/bbfdmd/ubus/events.h b/libbbfdm-ubus/events.h similarity index 84% rename from bbfdmd/ubus/events.h rename to libbbfdm-ubus/events.h index f0c4569ec82f3b54a4e5e76a5f9a4d727b2821e0..056a5a792772432a1cda01332e9db94d56dcd09c 100644 --- a/bbfdmd/ubus/events.h +++ b/libbbfdm-ubus/events.h @@ -1,9 +1,6 @@ #ifndef EVENT_H #define EVENT_H -#include "bbfdmd.h" -#include "common.h" - int register_events_to_ubus(struct ubus_context *ctx, struct list_head *ev_list); void free_ubus_event_handler(struct ubus_context *ctx, struct list_head *ev_list); diff --git a/bbfdmd/ubus/get.c b/libbbfdm-ubus/get.c similarity index 96% rename from bbfdmd/ubus/get.c rename to libbbfdm-ubus/get.c index d8db2a685a9f3e2157336896e66d0a1afe0ff6d3..fb0ae5946d5c0b0657cb9ae40548ccadc05ff6b2 100644 --- a/bbfdmd/ubus/get.c +++ b/libbbfdm-ubus/get.c @@ -9,6 +9,7 @@ * See LICENSE file for license related information. */ +#include "common.h" #include "get.h" #include "get_helper.h" #include "pretty_print.h" @@ -101,7 +102,7 @@ static bool get_next_param(char *qPath, size_t *pos, char *param) break; } if (qPath[++i] != '.') { - ERR("No dot after search parameters"); + BBF_ERR("No dot after search parameters"); return false; } // skip the dot @@ -141,7 +142,7 @@ static bool is_present_in_datamodel(struct dmctx *bbf_ctx, char *path) size_t plen = 0, rem = 0; bool found = false; - DEBUG("path(%s)", path); + BBF_DEBUG("path(%s)", path); plen = DM_STRLEN(path); blobmsg_for_each_attr(cur, bbf_ctx->bb.head, rem) { @@ -255,7 +256,7 @@ static void handle_special_escape_sequence(char *value, char *buff, size_t buff_ } buff[j] = '\0'; - DEBUG("value(%s), new_value(%s)", value, buff); + BBF_DEBUG("value(%s), new_value(%s)", value, buff); } static bool handle_string(char *v1, char *v2, enum operation op, int *fault) @@ -542,7 +543,7 @@ static bool check_values(char *val_type, char *val1, char *val2, enum operation { bool result = false; - DEBUG("type(%s), val1(%s), Val2(%s), Oper(%d)", val_type, val1, val2, oper); + BBF_DEBUG("type(%s), val1(%s), Val2(%s), Oper(%d)", val_type, val1, val2, oper); switch (get_dm_type(val_type)) { case DMT_STRING: result = handle_string(val1, val2, oper, fault); @@ -648,7 +649,7 @@ static int solve_all_filters(struct dmctx *bbf_ctx, char *bPath, char *param, st LIST_HEAD(pv_local); LIST_HEAD(plist_local); - INFO("## Basepath(%s), param(%s)", bPath, param); + BBF_INFO("## Basepath(%s), param(%s)", bPath, param); // Use shorter list for rest of the operation blen = DM_STRLEN(bPath); @@ -682,7 +683,7 @@ static int solve_all_filters(struct dmctx *bbf_ctx, char *bPath, char *param, st if (ret != 0) break; - INFO("Filter Para(%s), oper(%d), Val(%s)", para, oper, value); + BBF_INFO("Filter Para(%s), oper(%d), Val(%s)", para, oper, value); if (match(para, "[*]+", 0, NULL)) ret = USP_FAULT_INVALID_TYPE; @@ -743,7 +744,7 @@ static int resolve_path(struct dmctx *bbf_ctx, char *qPath, size_t pos, struct l if (list_empty(resolved_plist)) return 0; - INFO("Entry Len :: %d & qPath :: %s", start, qPath); + BBF_INFO("Entry Len :: %zu & qPath :: %s", start, qPath); if (strchr(qPath+start, '.') != NULL) non_leaf = true; @@ -752,7 +753,7 @@ static int resolve_path(struct dmctx *bbf_ctx, char *qPath, size_t pos, struct l return USP_FAULT_INVALID_PATH_SYNTAX; plen = DM_STRLEN(param); - DEBUG("PARAM ::(%s) pos ::(%d)", param, start); + BBF_DEBUG("PARAM ::(%s) pos ::(%zu)", param, start); fault = 0; list_for_each_entry(ptr, resolved_plist, list) { @@ -804,7 +805,7 @@ int get_resolved_paths(struct dmctx *bbf_ctx, char *qpath, struct list_head *res size_t pos = 0; pos = strlen(bpath); - INFO("Base Path :: |%s| Pos :: |%d|", bpath, pos); + BBF_INFO("Base Path :: |%s| Pos :: |%zu|", bpath, pos); bbf_ctx->in_param = bpath; @@ -815,12 +816,12 @@ int get_resolved_paths(struct dmctx *bbf_ctx, char *qpath, struct list_head *res fault = resolve_path(bbf_ctx, qpath, pos, resolved_paths); } } else { - INFO("Not able to get base path"); + BBF_INFO("Not able to get base path"); fault = bbf_fault_map(bbf_ctx, FAULT_9005); } if (fault) - WARNING("qpath(%s), fault(%d)", qpath, fault); + BBF_WARNING("qpath(%s), fault(%d)", qpath, fault); return fault; } @@ -852,7 +853,7 @@ void bbfdm_get_value(bbfdm_data_t *data, void *output) data->bbf_ctx.in_param = pn->path; fill_err_code_table(data, fault); } else { - INFO("Preparing result for(%s)", pn->path); + BBF_INFO("Preparing result for(%s)", pn->path); data->bbf_ctx.in_param = pn->path; @@ -871,7 +872,7 @@ void bbfdm_get_value(bbfdm_data_t *data, void *output) blobmsg_close_array(&data->bb, array); if (!validate_msglen(data)) - ERR("IPC failed for path(%s)", data->bbf_ctx.in_param); + BBF_ERR("IPC failed for path(%s)", data->bbf_ctx.in_param); if (output) memcpy(output, data->bb.head, blob_pad_len(data->bb.head)); diff --git a/bbfdmd/ubus/get.h b/libbbfdm-ubus/get.h similarity index 93% rename from bbfdmd/ubus/get.h rename to libbbfdm-ubus/get.h index 66c78815b1e589bf55fcde5df5b5b2a8b95a1db9..af23291fd44421b32644100e734081f37d6c48c5 100644 --- a/bbfdmd/ubus/get.h +++ b/libbbfdm-ubus/get.h @@ -1,9 +1,6 @@ #ifndef GET_H #define GET_H -#include "bbfdmd.h" -#include "common.h" - enum { DM_GET_PATH, DM_GET_PATHS, diff --git a/bbfdmd/ubus/get_helper.c b/libbbfdm-ubus/get_helper.c similarity index 92% rename from bbfdmd/ubus/get_helper.c rename to libbbfdm-ubus/get_helper.c index 4619778cc4c5b419d6b3cf120c95caa0b63b41df..4719cb4623843e86cd76f5bc6bd3cda8ed17f87a 100644 --- a/bbfdmd/ubus/get_helper.c +++ b/libbbfdm-ubus/get_helper.c @@ -19,6 +19,7 @@ #include "pretty_print.h" DMOBJ *DEAMON_DM_ROOT_OBJ = NULL; +DM_MAP_OBJ *INTERNAL_ROOT_TREE = NULL; static jmp_buf gs_jump_location; static bool gs_jump_called_by_bbf = false; @@ -29,7 +30,7 @@ void handle_pending_signal(int sig) siglongjmp(gs_jump_location, 1); } - ERR("Exception [%d] not cause by bbf dm, exit with error", sig); + BBF_ERR("Exception [%d] not cause by bbf dm, exit with error", sig); exit(1); } @@ -44,10 +45,10 @@ int bbfdm_cmd_exec(struct dmctx *bbf_ctx, int cmd) gs_jump_called_by_bbf = true; fault = bbf_entry_method(bbf_ctx, cmd); } else { - ERR("PID [%ld]::Exception on [%d => %s]", getpid(), cmd, bbf_ctx->in_param); + BBF_ERR("PID [%d]::Exception on [%d => %s]", getpid(), cmd, bbf_ctx->in_param); fault = USP_FAULT_INTERNAL_ERROR; - if (is_micro_service) { - ERR("Micro-service PID [%ld]::Exception on [%d => %s]", getpid(), cmd, bbf_ctx->in_param); + if (dm_is_micro_service()) { + BBF_ERR("Micro-service PID [%d]::Exception on [%d => %s]", getpid(), cmd, bbf_ctx->in_param); exit(-1); } } @@ -55,7 +56,7 @@ int bbfdm_cmd_exec(struct dmctx *bbf_ctx, int cmd) gs_jump_called_by_bbf = false; if (fault) - WARNING("Fault [%d => %d => %s]", fault, cmd, bbf_ctx->in_param); + BBF_WARNING("Fault [%d => %d => %s]", fault, cmd, bbf_ctx->in_param); return fault; } @@ -104,7 +105,7 @@ void add_pv_list(char *para, char *val, char *type, struct list_head *pv_list) node = (struct pvNode *) malloc(sizeof(*node)); if (!node) { - ERR("Out of memory!"); + BBF_ERR("Out of memory!"); return; } @@ -138,7 +139,7 @@ void add_path_list(char *param, struct list_head *plist) node = (struct pathNode *)calloc(1, sizeof(*node)); if (!node) { - ERR("Out of memory!"); + BBF_ERR("Out of memory!"); return; } diff --git a/bbfdmd/ubus/get_helper.h b/libbbfdm-ubus/get_helper.h similarity index 98% rename from bbfdmd/ubus/get_helper.h rename to libbbfdm-ubus/get_helper.h index f6c219dc05a34a9b38937e01fe7e40a2f61f497d..6597c28f1bf29ddcdecc35c7834d57a70eb79bd3 100644 --- a/bbfdmd/ubus/get_helper.h +++ b/libbbfdm-ubus/get_helper.h @@ -1,7 +1,6 @@ #ifndef GET_HELPER_H #define GET_HELPER_H -#include "bbfdmd.h" #include "common.h" #include <libubus.h> diff --git a/bbfdmd/ubus/operate.c b/libbbfdm-ubus/operate.c similarity index 100% rename from bbfdmd/ubus/operate.c rename to libbbfdm-ubus/operate.c diff --git a/bbfdmd/ubus/operate.h b/libbbfdm-ubus/operate.h similarity index 85% rename from bbfdmd/ubus/operate.h rename to libbbfdm-ubus/operate.h index 0cc2ff042d03502b14af7b6b39ebf528de241887..e6d3187d83d39888c30d452732f84072e7f0a034 100644 --- a/bbfdmd/ubus/operate.h +++ b/libbbfdm-ubus/operate.h @@ -1,9 +1,6 @@ #ifndef OPERATE_H #define OPERATE_H -#include "bbfdmd.h" -#include "common.h" - enum { DM_OPERATE_COMMAND, DM_OPERATE_COMMAND_KEY, diff --git a/bbfdmd/ubus/plugin.c b/libbbfdm-ubus/plugin.c similarity index 84% rename from bbfdmd/ubus/plugin.c rename to libbbfdm-ubus/plugin.c index 7e1c19ccc5741a2da0bd4a98c02719cfd773da54..a085f1cc924e54ad1b3e64c8bfb4055a1e53f7d8 100644 --- a/bbfdmd/ubus/plugin.c +++ b/libbbfdm-ubus/plugin.c @@ -62,33 +62,38 @@ static void fill_dotso_micro_service_out_args(bbfdm_config_t *config, DMOBJ *ent int load_dotso_plugin(void **lib_handle, const char *file_path, bbfdm_config_t *config, DMOBJ **main_entry) { if (!lib_handle || !file_path || !strlen(file_path) || !main_entry) { - ERR("Input validation failed\n"); - return -1; - } - - void *handle = dlopen(file_path, RTLD_NOW|RTLD_LOCAL); - if (!handle) { - ERR("Plugin failed [%s]\n", dlerror()); + BBF_ERR("Input validation failed\n"); return -1; } dm_dynamic_initmem(&plugin_mem); + DM_MAP_OBJ *dynamic_obj = NULL; - *lib_handle = handle; + if (strcmp(file_path, "internal_dm.so") == 0) { + dynamic_obj = INTERNAL_ROOT_TREE; + } else { + void *handle = dlopen(file_path, RTLD_NOW|RTLD_LOCAL); + if (!handle) { + BBF_ERR("Plugin failed [%s]\n", dlerror()); + return -1; + } + + *lib_handle = handle; + + //Dynamic Object + *(void **) (&dynamic_obj) = dlsym(handle, "tDynamicObj"); + } - //Dynamic Object - DM_MAP_OBJ *dynamic_obj = NULL; - *(void **) (&dynamic_obj) = dlsym(handle, "tDynamicObj"); if (dynamic_obj) { uint8_t obj_num = find_number_of_objects(dynamic_obj); if (obj_num == 0) { - ERR("No Object defined in the required DotSo Plugin\n"); + BBF_ERR("No Object defined in the required DotSo Plugin\n"); return -1; } DMOBJ *dm_entryobj = (DMOBJ *)dm_dynamic_calloc(&plugin_mem, obj_num + 1, sizeof(DMOBJ)); if (dm_entryobj == NULL) { - ERR("No Memory exists\n"); + BBF_ERR("No Memory exists\n"); return -1; } @@ -99,12 +104,12 @@ int load_dotso_plugin(void **lib_handle, const char *file_path, bbfdm_config_t * unsigned int len = strlen(node_obj); if (strncmp(node_obj, ROOT_NODE, strlen(ROOT_NODE)) != 0 || node_obj[len-1] != '.') { - ERR("Object (%s) not valid\n", node_obj); + BBF_ERR("Object (%s) not valid\n", node_obj); return -1; } // Fill out arguments if it is running as micro-service - if (is_micro_service == true) + if (dm_is_micro_service() == true) fill_dotso_micro_service_out_args(config, dynamic_obj[i].root_obj, node_obj, &out_obj_idx); node_obj[len-1] = 0; @@ -118,7 +123,7 @@ int load_dotso_plugin(void **lib_handle, const char *file_path, bbfdm_config_t * *main_entry = dm_entryobj; } else { - ERR("Main entry not available"); + BBF_ERR("Main entry not available"); return -1; } @@ -159,13 +164,13 @@ int load_json_plugin(struct list_head *json_plugin, struct list_head *json_list, uint8_t idx = 0; if (!file_path || !strlen(file_path) || !main_entry) { - ERR("Entry validation failed ..."); + BBF_ERR("Entry validation failed ..."); return -1; } json_object *json_obj = json_object_from_file(file_path); if (!json_obj) { - ERR("Failed to parse json file (%s)", file_path); + BBF_ERR("Failed to parse json file (%s)", file_path); return -1; } @@ -181,12 +186,12 @@ int load_json_plugin(struct list_head *json_plugin, struct list_head *json_list, replace_str(key, "{BBF_VENDOR_PREFIX}", BBF_VENDOR_PREFIX, node_obj, sizeof(node_obj)); if (strlen(node_obj) == 0) { - ERR("ERROR: Can't get the node object\n"); + BBF_ERR("ERROR: Can't get the node object\n"); return -1; } if (strncmp(node_obj, ROOT_NODE, strlen(ROOT_NODE)) != 0 || node_obj[strlen(node_obj) - 1] != '.') { - ERR("ERROR: Object (%s) not valid\n", node_obj); + BBF_ERR("ERROR: Object (%s) not valid\n", node_obj); return -1; } @@ -195,19 +200,19 @@ int load_json_plugin(struct list_head *json_plugin, struct list_head *json_list, int obj_prefix_len = strlen(obj_prefix); if (obj_prefix_len == 0) { - ERR("ERROR: Obj prefix is empty for (%s) Object\n", node_obj); + BBF_ERR("ERROR: Obj prefix is empty for (%s) Object\n", node_obj); return -1; } char obj_name[64] = {0}; json_plugin_find_current_obj(node_obj, obj_name, sizeof(obj_name)); if (strlen(obj_name) == 0) { - ERR("ERROR: Obj name is empty for (%s) Object\n", node_obj); + BBF_ERR("ERROR: Obj name is empty for (%s) Object\n", node_obj); return -1; } // Fill out arguments if it is running as micro-service - if (is_micro_service == true) + if (dm_is_micro_service() == true) fill_json_micro_service_out_args(config, obj_prefix, obj_name, idx, ms_name, sizeof(ms_name)); // Remove '.' from object prefix @@ -216,7 +221,7 @@ int load_json_plugin(struct list_head *json_plugin, struct list_head *json_list, dm_entryobj = (DMOBJ *)dm_dynamic_realloc(json_memhead, dm_entryobj, (idx + 2) * sizeof(DMOBJ)); if (dm_entryobj == NULL) { - ERR("ERROR: No Memory exists\n"); + BBF_ERR("ERROR: No Memory exists\n"); return -1; } diff --git a/bbfdmd/ubus/plugin.h b/libbbfdm-ubus/plugin.h similarity index 100% rename from bbfdmd/ubus/plugin.h rename to libbbfdm-ubus/plugin.h diff --git a/bbfdmd/ubus/pretty_print.c b/libbbfdm-ubus/pretty_print.c similarity index 93% rename from bbfdmd/ubus/pretty_print.c rename to libbbfdm-ubus/pretty_print.c index 75f8d51c26b9cb23168b39c7b9aada9f83cbb045..d0f0fbda12ed119310af58d1e6735761cc4584f3 100644 --- a/bbfdmd/ubus/pretty_print.c +++ b/libbbfdm-ubus/pretty_print.c @@ -21,7 +21,7 @@ struct resultstack { static bool is_search_by_reference(char *path) { - DEBUG("Entry |%s|", path); + BBF_DEBUG("Entry |%s|", path); if (match(path, "[+]+", 0, NULL)) { size_t pindex = 0, bindex = 0; char *last_plus, *last_bracket; @@ -46,7 +46,7 @@ static bool is_search_by_reference(char *path) static bool is_res_required(char *str, size_t *start, size_t *len) { - DEBUG("Entry |%s|", str); + BBF_DEBUG("Entry |%s|", str); if (match(str, GLOB_CHAR, 0, NULL)) { size_t s_len, b_len, p_len; char *star, *b_start, *b_end, *plus; @@ -106,7 +106,7 @@ static size_t get_glob_len(char *path) char temp_name[MAX_DM_KEY_LEN] = {'\0'}; char *end = NULL; - DEBUG("Entry"); + BBF_DEBUG("Entry"); if (is_res_required(path, &m_index, &m_len)) { if (m_index <= MAX_DM_KEY_LEN) snprintf(temp_name, m_index, "%s", path); @@ -190,7 +190,7 @@ static void add_data_blob(struct blob_buf *bb, char *param, char *value, char *t if (param == NULL || value == NULL || type == NULL) return; - DEBUG("# Adding BLOB (%s)::(%s)", param, value); + BBF_DEBUG("# Adding BLOB (%s)::(%s)", param, value); switch (get_dm_type(type)) { case DMT_UNINT: blobmsg_add_u64(bb, param, (uint32_t)strtoul(value, NULL, 10)); @@ -230,7 +230,7 @@ static void free_result_list(struct list_head *head) static void free_result_node(struct resultstack *rnode) { if (rnode) { - DEBUG("## ResStack DEL(%s)", rnode->key); + BBF_DEBUG("## ResStack DEL(%s)", rnode->key); free(rnode->key); list_del(&rnode->list); free(rnode); @@ -243,13 +243,13 @@ static void add_result_node(struct list_head *rlist, char *key, char *cookie) rnode = (struct resultstack *) malloc(sizeof(*rnode)); if (!rnode) { - ERR("Out of memory!"); + BBF_ERR("Out of memory!"); return; } rnode->key = (key) ? strdup(key) : strdup(""); rnode->cookie = cookie; - DEBUG("## ResSTACK ADD (%s) ##", rnode->key); + BBF_DEBUG("## ResSTACK ADD (%s) ##", rnode->key); INIT_LIST_HEAD(&rnode->list); list_add(&rnode->list, rlist); @@ -362,7 +362,7 @@ void prepare_result_blob(struct blob_buf *bb, struct list_head *pv_list) pv = &sortedPV[i]; ptr = pv->param; if (list_empty(&result_stack)) { - DEBUG("stack empty Processing (%s)", ptr); + BBF_DEBUG("stack empty Processing (%s)", ptr); add_paths_to_stack(bb, pv->param, 0, pv, &result_stack); } else { bool is_done = false; @@ -373,12 +373,12 @@ void prepare_result_blob(struct blob_buf *bb, struct list_head *pv_list) len = DM_STRLEN(rnode->key); ptr = ptr + len; - DEBUG("GROUP (%s), ptr(%s), len(%d)", pv->param, ptr, len); + BBF_DEBUG("GROUP (%s), ptr(%s), len(%zu)", pv->param, ptr, len); add_paths_to_stack(bb, pv->param, len, pv, &result_stack); is_done = true; } else { // Get the latest entry before deleting it - DEBUG("DIFF GROUP pv(%s), param(%s)", pv->param, ptr); + BBF_DEBUG("DIFF GROUP pv(%s), param(%s)", pv->param, ptr); blobmsg_close_table(bb, rnode->cookie); free_result_node(rnode); if (list_empty(&result_stack)) { @@ -432,12 +432,12 @@ void prepare_pretty_result(uint8_t maxdepth, struct blob_buf *bb, struct dmctx * LIST_HEAD(pv_local); - DEBUG("################### DATA to PROCESS ##################"); + BBF_DEBUG("################### DATA to PROCESS ##################"); list_for_each_entry(iter, rslvd, list) { - DEBUG("## %s ##", iter->path); + BBF_DEBUG("## %s ##", iter->path); resulting(maxdepth, iter->path, bbf_ctx, &pv_local); } - DEBUG("######################################################"); + BBF_DEBUG("######################################################"); prepare_result_blob(bb, &pv_local); diff --git a/bbfdmd/ubus/pretty_print.h b/libbbfdm-ubus/pretty_print.h similarity index 100% rename from bbfdmd/ubus/pretty_print.h rename to libbbfdm-ubus/pretty_print.h diff --git a/bbfdmd/ubus/set.c b/libbbfdm-ubus/set.c similarity index 97% rename from bbfdmd/ubus/set.c rename to libbbfdm-ubus/set.c index 2cdbc76c0ab25bccb498aa30f35ce199765d2a6d..076cd3b0ff42ddcacd13a36711cba7a6fd60c04e 100644 --- a/bbfdmd/ubus/set.c +++ b/libbbfdm-ubus/set.c @@ -9,8 +9,8 @@ * See LICENSE file for license related information. */ -#include "set.h" #include "get_helper.h" +#include "set.h" #include <libubus.h> @@ -116,7 +116,7 @@ blob__table: snprintf(value, MAX_DM_VALUE, "%"PRIu64"", blobmsg_get_u64(attr)); break; default: - INFO("Unhandled set request type|%x|", blob_id(attr)); + BBF_INFO("Unhandled set request type|%x|", blob_id(attr)); return USP_FAULT_INVALID_ARGUMENT; } diff --git a/bbfdmd/ubus/set.h b/libbbfdm-ubus/set.h similarity index 88% rename from bbfdmd/ubus/set.h rename to libbbfdm-ubus/set.h index 5a69fe5a117132a1a800aaac797119596beac010..78fe9739abe553bbef74a84886485f4087581a8c 100644 --- a/bbfdmd/ubus/set.h +++ b/libbbfdm-ubus/set.h @@ -1,9 +1,6 @@ #ifndef SET_H #define SET_H -#include "bbfdmd.h" -#include "common.h" - enum { DM_SET_PATH, DM_SET_VALUE, diff --git a/test/files/tmp/bbfdm/input.json b/test/files/tmp/bbfdm/input.json index 6d2881c13ee78e6016ac5cc9595e8abcf90e60fb..ce96f7da63d184f27cde50d9d403bce80453ae8d 100755 --- a/test/files/tmp/bbfdm/input.json +++ b/test/files/tmp/bbfdm/input.json @@ -1,7 +1,7 @@ { "daemon": { "config": { - "loglevel": "4", + "loglevel": "3", "subprocess_level": "2" }, "input": {