Introduce bbf.config with C code

This commit is contained in:
Amin Ben Romdhane 2024-05-08 10:12:09 +02:00
parent 0d16ce491a
commit 40d22bedaf
14 changed files with 766 additions and 50 deletions

View file

@ -5,3 +5,22 @@ PROJECT(bbf C)
add_subdirectory(libbbfdm-api)
add_subdirectory(libbbfdm)
add_subdirectory(bbfdmd)
# Capture the environment variables
set(MY_CC "$ENV{CC}")
set(MY_CFLAGS "$ENV{CFLAGS}")
set(MY_LDFLAGS "$ENV{LDFLAGS}")
# Define a custom target to build the utilities using Makefile
add_custom_target(
build_utilities
COMMAND ${CMAKE_COMMAND} -E env
CC=${MY_CC}
CFLAGS=${MY_CFLAGS}
LDFLAGS=${MY_LDFLAGS}
make
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/utilities
)
# Make bbfdmd target depend on the build_utilities target
add_dependencies(bbfdmd build_utilities)

View file

@ -54,7 +54,6 @@ extern struct list_head json_memhead;
LIST_HEAD(head_registered_service);
static void cancel_periodic_timers(struct ubus_context *ctx);
static void run_schema_updater(struct bbfdm_context *u);
static void periodic_instance_updater(struct uloop_timeout *t);
@ -584,7 +583,7 @@ int bbfdm_set_handler(struct ubus_context *ctx, struct ubus_object *obj,
if (data.trans_id == 0) {
// Transaction-id is not defined so create an internal transaction
cancel_periodic_timers(ctx);
cancel_instance_refresh_timer(ctx);
trans_id = transaction_start(&data, "INT_SET", 0);
if (trans_id == 0) {
WARNING("Failed to get the lock for the transaction");
@ -710,7 +709,7 @@ int bbfdm_add_handler(struct ubus_context *ctx, struct ubus_object *obj,
if (data.trans_id == 0) {
// Transaction-id is not defined so create an internal transaction
cancel_periodic_timers(ctx);
cancel_instance_refresh_timer(ctx);
trans_id = transaction_start(&data, "INT_ADD", 0);
if (trans_id == 0) {
ERR("Failed to get the lock for the transaction");
@ -837,7 +836,7 @@ int bbfdm_del_handler(struct ubus_context *ctx, struct ubus_object *obj,
if (data.trans_id == 0) {
// Transaction-id is not defined so create an internal transaction
cancel_periodic_timers(ctx);
cancel_instance_refresh_timer(ctx);
trans_id = transaction_start(&data, "INT_DEL", 0);
if (trans_id == 0) {
WARNING("Failed to get the lock for the transaction");
@ -918,7 +917,6 @@ static int bbfdm_transaction_handler(struct ubus_context *ctx, struct ubus_objec
data.ctx = ctx;
if (is_str_eq(trans_cmd, "start")) {
cancel_periodic_timers(ctx);
ret = transaction_start(&data, "API", max_timeout);
if (ret) {
blobmsg_add_u8(&data.bb, "status", true);
@ -929,11 +927,9 @@ static int bbfdm_transaction_handler(struct ubus_context *ctx, struct ubus_objec
}
} else if (is_str_eq(trans_cmd, "commit")) {
ret = transaction_commit(&data, data.trans_id, is_service_restart);
register_instance_refresh_timer(ctx, 100);
blobmsg_add_u8(&data.bb, "status", (ret == 0));
} else if (is_str_eq(trans_cmd, "abort")) {
ret = transaction_abort(&data, data.trans_id);
register_instance_refresh_timer(ctx, 100);
blobmsg_add_u8(&data.bb, "status", (ret == 0));
} else if (is_str_eq(trans_cmd, "status")) {
transaction_status(&data.bb);
@ -1682,22 +1678,6 @@ static void lookup_event_cb(struct ubus_context *ctx,
}
}
static void cancel_periodic_timers(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_timer");
if (u->config.refresh_time != 0) {
uloop_timeout_cancel(&u->instance_timer);
}
}
void register_instance_refresh_timer(struct ubus_context *ctx, int start_in)
{
struct bbfdm_context *u;
@ -1722,6 +1702,36 @@ void register_instance_refresh_timer(struct ubus_context *ctx, int 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");
if (u->config.refresh_time != 0) {
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;
cancel_instance_refresh_timer(ctx);
register_instance_refresh_timer(ctx, 100);
}
static void bbfdm_ctx_init(struct bbfdm_context *bbfdm_ctx)
{
memset(bbfdm_ctx, 0, sizeof(struct bbfdm_context));
@ -1787,6 +1797,7 @@ static int daemon_load_datamodel(struct bbfdm_context *daemon_ctx)
}
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)
{
@ -1868,6 +1879,10 @@ int main(int argc, char **argv)
if (err != 0)
goto exit;
err = ubus_register_event_handler(&bbfdm_ctx.ubus_ctx, &config_change_handler, "bbf.config.change");
if (err != 0)
goto exit;
if (is_micro_service == true) { // It's a micro-service instance
char proc_name[32] = {0};
@ -1882,7 +1897,9 @@ int main(int argc, char **argv)
// If the micro-service is not registered, listen for "ubus.object.add" event
// and register the micro-service using event handler for it
ubus_register_event_handler(&bbfdm_ctx.ubus_ctx, &add_event, "ubus.object.add");
err = ubus_register_event_handler(&bbfdm_ctx.ubus_ctx, &add_event, "ubus.object.add");
if (err != 0)
goto exit;
}
INFO("Waiting on uloop....");

View file

@ -67,5 +67,6 @@ typedef struct bbfdm_data {
} bbfdm_data_t;
void register_instance_refresh_timer(struct ubus_context *ctx, int start_sec);
void cancel_instance_refresh_timer(struct ubus_context *ctx);
#endif /* BBFDMD_H */

View file

@ -75,6 +75,8 @@ static void bbfdm_event_handler(struct ubus_context *ctx, struct ubus_event_hand
if (ret)
goto end;
cancel_instance_refresh_timer(ctx);
struct dm_parameter *param = NULL;
struct blob_buf b = {0}, bb = {0};
char method_name[256] = {0};

View file

@ -33,13 +33,3 @@ FILE(GLOB libbbfdm-api_include_headers include/*.h)
INSTALL(FILES ${libbbfdm-api_include_headers}
DESTINATION usr/include
)
INSTALL(FILES scripts/bbf.secure
PERMISSIONS OWNER_EXECUTE
DESTINATION usr/libexec/rpcd
)
INSTALL(FILES scripts/bbf.config
PERMISSIONS OWNER_EXECUTE
DESTINATION usr/libexec/rpcd
)

View file

@ -448,12 +448,15 @@ void bbf_entry_restart_services(struct blob_buf *bb, bool restart_services)
if (bb) blobmsg_add_string(bb, NULL, pc->package);
if (restart_services) {
// Internal transaction: need to commit the changes
dmubus_call_set("uci", "commit", UBUS_ARGS{{"config", pc->package, String}}, 1);
}
}
if (restart_services)
if (restart_services) {
// Internal transaction: need to commit the changes
dmuci_commit_bbfdm();
}
free_all_list_package_change(&head_package_change);
}

View file

@ -36,23 +36,12 @@ INSTALL(DIRECTORY DESTINATION usr/libexec/rpcd)
FILE(GLOB scripts scripts/*)
FOREACH(script ${scripts})
IF(IS_DIRECTORY ${script})
INSTALL(DIRECTORY ${script}
DESTINATION usr/share/bbfdm/scripts
)
ELSE()
INSTALL(FILES ${script}
PERMISSIONS OWNER_EXECUTE
DESTINATION usr/share/bbfdm/scripts
)
ENDIF()
INSTALL(FILES ${script}
PERMISSIONS OWNER_EXECUTE
DESTINATION usr/share/bbfdm/scripts
)
ENDFOREACH()
INSTALL(FILES scripts/bbf.diag
PERMISSIONS OWNER_EXECUTE
DESTINATION usr/libexec/rpcd
)
string(REPLACE "," ";" VENDOR_LIST ${BBF_VENDOR_LIST})
foreach(VENDOR ${VENDOR_LIST})

25
utilities/Makefile Normal file
View file

@ -0,0 +1,25 @@
CC ?= gcc
PROG = bbf_configd
OBJS = src/ubus/bbf_config.o src/ubus/utils.o
PROG_CFLAGS = $(CFLAGS) -Wall -Werror
PROG_LDFLAGS = $(LDFLAGS)
PROG_LIBS += -luci -lubus -lubox -lblobmsg_json
INSTALL_DIR = /usr/sbin
%.o: %.c
$(CC) $(PROG_CFLAGS) $(FPIC) -c -o $@ $<
.PHONY: all clean install
all: $(PROG)
$(PROG): $(OBJS)
$(CC) $(PROG_LDFLAGS) -o $@ $^ $(PROG_LIBS)
clean:
rm -f $(PROG)
install: $(PROG)
install -m 0755 $(PROG) $(INSTALL_DIR)

View file

@ -77,6 +77,9 @@ case "$1" in
uci -q -c "${BBFDM_DMMAP_CONFIG}" -t "${BBFDM_DMMAP_SAVEDIR}" "$2" "${file_name}"
check_result "$?" "${file_name}" "$2"
done
# Send 'bbf.config.change' event to run refresh instances
ubus send bbf.config.change
echo '{ "status": "ok" }'
;;

View file

@ -0,0 +1,518 @@
/*
* bbf_config.c: bbf.config daemon
*
* Copyright (C) 2024 IOPSYS Software Solutions AB. All rights reserved.
*
* Author: Amin Ben Romdhane <amin.benromdhane@iopsys.eu>
*
* See LICENSE file for license related information.
*/
#include <stdio.h>
#include <unistd.h>
#include <syslog.h>
#include <libubox/blobmsg.h>
#include <libubox/uloop.h>
#include <libubus.h>
#include "utils.h"
#define TIME_TO_WAIT_FOR_RELOAD 5
#define MAX_PACKAGE_NUM 256
#define MAX_SERVICE_NUM 8
#define MAX_INSTANCE_NUM 32
#define NAME_LENGTH 64
#define DM_DMMAP_CONFIG "/etc/bbfdm/dmmap"
#define DM_DMMAP_SAVEDIR "/tmp/.bbfdm"
// Structure to represent an instance of a service
struct instance {
char name[NAME_LENGTH];
uint32_t pid;
bool is_running;
};
// Structure to represent a service
struct service {
char name[NAME_LENGTH];
bool has_instances;
struct instance instances[MAX_INSTANCE_NUM];
};
// Structure to represent a configuration package
struct config_package {
char name[NAME_LENGTH];
struct service services[MAX_SERVICE_NUM];
};
enum {
SERVICES_NAME,
__MAX
};
static const struct blobmsg_policy bbf_config_policy[] = {
[SERVICES_NAME] = { .name = "services", .type = BLOBMSG_TYPE_ARRAY },
};
static int find_config_idx(struct config_package *package, const char *config_name)
{
if (!config_name)
return -1;
for (int i = 0; i < MAX_PACKAGE_NUM; i++) {
if (strlen(package[i].name) == 0)
return -1;
if (strcmp(package[i].name, config_name) == 0)
return i;
}
return -1;
}
static int find_service_idx(struct service *services)
{
if (!services)
return -1;
for (int i = 0; i < MAX_SERVICE_NUM; i++) {
if (strlen(services[i].name) == 0)
return i;
}
return -1;
}
static int find_instance_idx(struct instance *instances, const char *instance_name)
{
if (!instances)
return -1;
for (int i = 0; i < MAX_INSTANCE_NUM; i++) {
if (instance_name && strcmp(instances[i].name, instance_name) == 0)
return i;
if (strlen(instances[i].name) == 0)
return i;
}
return -1;
}
static int handle_instances_service(const char *service_name, struct blob_attr *instances, struct config_package *package, unsigned int pkg_idx)
{
int srv_idx = find_service_idx(package[pkg_idx].services);
if (srv_idx < 0) // Returns if the number of services more than MAX_SERVICE_NUM
return -1;
strncpyt(package[pkg_idx].services[srv_idx].name, service_name, NAME_LENGTH);
package[pkg_idx].services[srv_idx].has_instances = (instances) ? true : false;
if (!instances)
return -1;
struct blob_attr *cur;
int rem;
int inst_idx = find_instance_idx(package[pkg_idx].services[srv_idx].instances, NULL);
if (inst_idx < 0) // Returns if the number of instances more than MAX_INSTANCE_NUM
return -1;
blobmsg_for_each_attr(cur, instances, rem) {
struct blob_attr *tb[2] = {0};
const struct blobmsg_policy p[2] = {
{ "running", BLOBMSG_TYPE_BOOL },
{ "pid", BLOBMSG_TYPE_INT32 }
};
blobmsg_parse(p, 2, tb, blobmsg_data(cur), blobmsg_len(cur));
strncpyt(package[pkg_idx].services[srv_idx].instances[inst_idx].name, blobmsg_name(cur), NAME_LENGTH);
package[pkg_idx].services[srv_idx].instances[inst_idx].is_running = (tb[0]) ? blobmsg_get_bool(tb[0]) : false;
package[pkg_idx].services[srv_idx].instances[inst_idx].pid = (tb[1]) ? blobmsg_get_u32(tb[1]) : false;
inst_idx++;
}
return 0;
}
static int handle_triggers_service(const char *service_name, struct blob_attr *triggers, struct blob_attr *instances, struct config_package *package, unsigned int *index)
{
struct blob_attr *cur;
int rem;
blobmsg_for_each_attr(cur, triggers, rem) {
struct blob_attr *_cur, *type = NULL, *script = NULL, *config = NULL, *name = NULL;
size_t _rem;
int i = 0;
if (blobmsg_type(cur) != BLOBMSG_TYPE_ARRAY)
continue;
blobmsg_for_each_attr(_cur, cur, _rem) {
switch (i++) {
case 0:
if (blobmsg_type(_cur) == BLOBMSG_TYPE_STRING)
type = _cur;
break;
case 1:
if (blobmsg_type(_cur) == BLOBMSG_TYPE_ARRAY)
script = _cur;
break;
}
}
if (!type || !script || strcmp(blobmsg_get_string(type), "config.change") != 0)
continue;
type = NULL;
i = 0;
blobmsg_for_each_attr(_cur, script, _rem) {
switch (i++) {
case 0:
if (blobmsg_type(_cur) == BLOBMSG_TYPE_STRING)
type = _cur;
break;
case 1:
if (blobmsg_type(_cur) == BLOBMSG_TYPE_ARRAY)
config = _cur;
break;
}
}
if (!type || !config || strcmp(blobmsg_get_string(type), "if") != 0)
continue;
type = NULL;
script = NULL;
i = 0;
blobmsg_for_each_attr(_cur, config, _rem) {
switch (i++) {
case 0:
if (blobmsg_type(_cur) == BLOBMSG_TYPE_STRING)
type = _cur;
break;
case 1:
if (blobmsg_type(_cur) == BLOBMSG_TYPE_STRING)
script = _cur;
break;
case 2:
if (blobmsg_type(_cur) == BLOBMSG_TYPE_STRING)
name = _cur;
break;
}
}
if (!type || !script || !name ||
strcmp(blobmsg_get_string(type), "eq") != 0 ||
strcmp(blobmsg_get_string(script), "package") != 0)
continue;
char *config_name = blobmsg_get_string(name);
int config_idx = find_config_idx(package, config_name);
unsigned int pkg_idx = (config_idx < 0) ? (*index)++ : config_idx;
strncpyt(package[pkg_idx].name, blobmsg_get_string(name), NAME_LENGTH);
handle_instances_service(service_name, instances, package, pkg_idx);
}
return 0;
}
static void _get_service_list_cb(struct ubus_request *req, int type, struct blob_attr *msg)
{
struct blob_attr *cur;
struct blob_attr *tb[2] = {0};
const struct blobmsg_policy p[2] = {
{ "triggers", BLOBMSG_TYPE_ARRAY },
{ "instances", BLOBMSG_TYPE_TABLE }
};
size_t rem;
unsigned int idx = 0;
if (!msg || !req)
return;
struct config_package *package = (struct config_package *)req->priv;
blobmsg_for_each_attr(cur, msg, rem) {
blobmsg_parse(p, 2, tb, blobmsg_data(cur), blobmsg_len(cur));
if (!tb[0])
continue;
handle_triggers_service(blobmsg_name(cur), tb[0], tb[1], package, &idx);
}
}
static void _get_specific_service_cb(struct ubus_request *req, int type, struct blob_attr *msg)
{
struct blob_attr *cur;
struct blob_attr *tb[1] = {0};
const struct blobmsg_policy p[1] = {
{ "instances", BLOBMSG_TYPE_TABLE }
};
size_t rem;
if (!msg || !req)
return;
struct config_package *package = (struct config_package *)req->priv;
blobmsg_for_each_attr(cur, msg, rem) {
blobmsg_parse(p, 1, tb, blobmsg_data(cur), blobmsg_len(cur));
handle_instances_service(blobmsg_name(cur), tb[0], package, 0);
}
}
static void fill_service_info(struct ubus_context *ctx, struct config_package *package, const char *name, bool verbose, ubus_data_handler_t callback)
{
struct blob_buf ubus_bb = {0};
blob_buf_init(&ubus_bb, 0);
if (name) blobmsg_add_string(&ubus_bb, "name", name);
blobmsg_add_u8(&ubus_bb, "verbose", verbose);
bbf_config_call(ctx, "service", "list", &ubus_bb, callback, (void *)package);
blob_buf_free(&ubus_bb);
}
static void validate_required_services(struct ubus_context *ctx, struct config_package *package, struct blob_attr *services)
{
struct blob_attr *service = NULL;
size_t rem = 0;
// Iterate through each service attribute
blobmsg_for_each_attr(service, services, rem) {
char *config_name = blobmsg_get_string(service);
// Find the index of the configuration package
int idx = find_config_idx(package, config_name);
if (idx < 0)
continue;
for (int j = 0; j < MAX_SERVICE_NUM && strlen(package[idx].services[j].name); j++) {
// Get configuration information for each service name
struct config_package new_package[1] = {0};
memset(new_package, 0, sizeof(struct config_package));
fill_service_info(ctx, new_package, package[idx].services[j].name, false, _get_specific_service_cb);
if (package[idx].services[j].has_instances != new_package[0].services[0].has_instances) {
// If the number of instances has changed, the service is correctly updated
continue; // Move to the next service
}
if (package[idx].services[j].has_instances == 0) {
// No instances to check, unsure if service is correctly updated
goto wait;
}
for (int t = 0; t < MAX_SERVICE_NUM && strlen(package[idx].services[j].instances[t].name); t++) {
// Find the index of the instance in the new package
int inst_idx = find_instance_idx(new_package[0].services[0].instances,
package[idx].services[j].instances[t].name);
if (inst_idx < 0) {
// Instance doesn't exist after reload, indicating a disabled instance
continue; // Move to the next service
}
if (package[idx].services[j].instances[t].is_running != new_package[0].services[0].instances[inst_idx].is_running) {
// Instance status changed after reload, service correctly updated
continue; // Move to the next service
}
if (package[idx].services[j].instances[t].pid != new_package[0].services[0].instances[inst_idx].pid) {
// Instance PID changed after reload, service correctly updated
continue; // Move to the next service
}
// Wait for a sufficient time to ensure services are reloaded
goto wait;
}
}
}
return;
wait:
// Wait to reload all required services
sleep(TIME_TO_WAIT_FOR_RELOAD);
}
static void send_bbf_config_change_event(struct ubus_context *ctx)
{
struct blob_buf bb = {0};
blob_buf_init(&bb, 0);
ubus_send_event(ctx, "bbf.config.change", bb.head);
blob_buf_free(&bb);
}
static int bbf_config_commit_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[__MAX];
struct blob_buf bb = {0};
struct config_package package[MAX_PACKAGE_NUM];
memset(package, 0, sizeof(struct config_package) * MAX_PACKAGE_NUM);
memset(&bb, 0, sizeof(struct blob_buf));
blob_buf_init(&bb, 0);
if (blobmsg_parse(bbf_config_policy, __MAX, tb, blob_data(msg), blob_len(msg))) {
blobmsg_add_string(&bb, "error", "Failed to parse blob");
goto end;
}
struct blob_attr *services = tb[SERVICES_NAME];
if (!services) {
blobmsg_add_string(&bb, "error", "Services array should be defined !!!");
goto end;
}
// Commit all uci dmmap changes
uci_apply_changes(DM_DMMAP_CONFIG, DM_DMMAP_SAVEDIR, true);
size_t arr_len = blobmsg_len(services);
if (arr_len) {
// Get all configs information before calling ubus call uci commit
fill_service_info(ctx, package, NULL, true, _get_service_list_cb);
// Commit uci config changes for the required configs
reload_services(ctx, services, true);
// Wait at least 2 seconds to reload the services
sleep(2);
// Check if the required services are really reloaded
validate_required_services(ctx, package, services);
// Send 'bbf.config.change' event to run refresh instances
send_bbf_config_change_event(ctx);
}
blobmsg_add_string(&bb, "status", "ok");
end:
ubus_send_reply(ctx, req, bb.head);
blob_buf_free(&bb);
return 0;
}
static int bbf_config_revert_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[__MAX];
struct blob_buf bb = {0};
memset(&bb, 0, sizeof(struct blob_buf));
blob_buf_init(&bb, 0);
if (blobmsg_parse(bbf_config_policy, __MAX, tb, blob_data(msg), blob_len(msg))) {
blobmsg_add_string(&bb, "error", "Failed to parse blob");
goto end;
}
struct blob_attr *services = tb[SERVICES_NAME];
if (!services) {
blobmsg_add_string(&bb, "error", "Services array should be defined !!!");
goto end;
}
// Revert all uci dmmap changes
uci_apply_changes(DM_DMMAP_CONFIG, DM_DMMAP_SAVEDIR, false);
size_t arr_len = blobmsg_len(services);
if (arr_len) {
// Revert uci config changes for the required configs
reload_services(ctx, services, false);
// Send 'bbf.config.change' event to run refresh instances
send_bbf_config_change_event(ctx);
}
blobmsg_add_string(&bb, "status", "ok");
end:
ubus_send_reply(ctx, req, bb.head);
blob_buf_free(&bb);
return 0;
}
static const struct ubus_method bbf_config_methods[] = {
UBUS_METHOD("commit", bbf_config_commit_handler, bbf_config_policy),
UBUS_METHOD("revert", bbf_config_revert_handler, bbf_config_policy),
};
static struct ubus_object_type bbf_config_object_type = UBUS_OBJECT_TYPE("bbf.config", bbf_config_methods);
static struct ubus_object bbf_config_object = {
.name = "bbf.config",
.type = &bbf_config_object_type,
.methods = bbf_config_methods,
.n_methods = ARRAY_SIZE(bbf_config_methods),
};
int main(int argc, char **argv)
{
struct ubus_context *uctx;
openlog("bbf.config", LOG_CONS | LOG_PID | LOG_NDELAY, LOG_LOCAL1);
uctx = ubus_connect(NULL);
if (uctx == NULL) {
printf("Can't create UBUS context");
return -1;
}
uloop_init();
ubus_add_uloop(uctx);
if (ubus_add_object(uctx, &bbf_config_object))
goto exit;
uloop_run();
exit:
uloop_done();
ubus_free(uctx);
closelog();
return 0;
}

125
utilities/src/ubus/utils.c Normal file
View file

@ -0,0 +1,125 @@
/*
* utils.c: common function for bbf.config daemon
*
* Copyright (C) 2024 IOPSYS Software Solutions AB. All rights reserved.
*
* Author: Amin Ben Romdhane <amin.benromdhane@iopsys.eu>
*
* See LICENSE file for license related information.
*/
#include <syslog.h>
#include <stdarg.h>
#include <libubus.h>
#include <uci.h>
#define DEFAULT_UBUS_TIMEOUT 5000
void dbg_printf(const char *format, ...)
{
va_list arglist;
va_start(arglist, format);
vsyslog(LOG_INFO, format, arglist);
va_end(arglist);
}
void strncpyt(char *dst, const char *src, size_t n)
{
if (dst == NULL || src == NULL)
return;
if (n > 1) {
strncpy(dst, src, n - 1);
dst[n - 1] = 0;
}
}
int bbf_config_call(struct ubus_context *ctx, const char *object, const char *method, struct blob_buf *data, ubus_data_handler_t callback, void *arg)
{
int fault = 0;
uint32_t id;
if (!ctx)
return -1;
fault = ubus_lookup_id(ctx, object, &id);
if (fault)
return -1;
fault = ubus_invoke(ctx, id, method, data ? data->head : NULL, callback, arg, DEFAULT_UBUS_TIMEOUT);
if (fault)
return -1;
return 0;
}
static void reload_service(struct ubus_context *ctx, const char *config_name, bool is_commit)
{
struct blob_buf bb = {0};
memset(&bb, 0, sizeof(struct blob_buf));
blob_buf_init(&bb, 0);
blobmsg_add_string(&bb, "config", config_name);
bbf_config_call(ctx, "uci", (is_commit) ? "commit" : "revert", &bb, NULL, NULL);
blob_buf_free(&bb);
}
void reload_services(struct ubus_context *ctx, struct blob_attr *services, bool is_commit)
{
struct blob_attr *service = NULL;
size_t rem = 0;
blobmsg_for_each_attr(service, services, rem) {
char *config_name = blobmsg_get_string(service);
reload_service(ctx, config_name, is_commit);
}
}
void uci_apply_changes(const char *conf_dir, const char *save_dir, bool is_commit)
{
struct uci_context *uci_ctx = NULL;
char **configs = NULL, **p = NULL;
struct uci_ptr ptr = {0};
uci_ctx = uci_alloc_context();
if (!uci_ctx) {
return;
}
if (conf_dir) {
uci_set_confdir(uci_ctx, conf_dir);
}
if (save_dir) {
uci_set_savedir(uci_ctx, save_dir);
}
if (uci_list_configs(uci_ctx, &configs) != UCI_OK) {
goto exit;
}
for (p = configs; p && *p; p++) {
if (uci_lookup_ptr(uci_ctx, &ptr, *p, true) != UCI_OK)
continue;
if (is_commit) {
if (uci_commit(uci_ctx, &ptr.p, false) != UCI_OK) {
continue;
}
} else {
if (uci_revert(uci_ctx, &ptr) != UCI_OK) {
continue;
}
}
}
free(configs);
exit:
uci_free_context(uci_ctx);
}

View file

@ -0,0 +1,24 @@
/*
* utils.c: common function for bbf.config daemon
*
* Copyright (C) 2024 IOPSYS Software Solutions AB. All rights reserved.
*
* Author: Amin Ben Romdhane <amin.benromdhane@iopsys.eu>
*
* See LICENSE file for license related information.
*/
#ifndef __UTILS_H__
#define __UTILS_H__
void dbg_printf(const char *format, ...);
void strncpyt(char *dst, const char *src, size_t n);
int bbf_config_call(struct ubus_context *ctx, const char *object, const char *method, struct blob_buf *data, ubus_data_handler_t callback, void *arg);
void uci_apply_changes(const char *conf_dir, const char *save_dir, bool is_commit);
void reload_services(struct ubus_context *ctx, struct blob_attr *services, bool is_commit);
#endif //__UTILS_H__