mirror of
https://dev.iopsys.eu/bbf/bbfdm.git
synced 2026-01-28 01:47:18 +01:00
370 lines
9.1 KiB
C
370 lines
9.1 KiB
C
/*
|
|
* 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 <stdarg.h>
|
|
#include <libubus.h>
|
|
#include <uci.h>
|
|
|
|
#include "utils.h"
|
|
|
|
#define DEFAULT_UBUS_TIMEOUT 5000
|
|
|
|
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;
|
|
}
|
|
}
|
|
|
|
bool file_exists(const char *path)
|
|
{
|
|
struct stat buffer;
|
|
|
|
if (!path)
|
|
return false;
|
|
|
|
return stat(path, &buffer) == 0;
|
|
}
|
|
|
|
static bool is_wifi_configs(const char *config_name, uint32_t *wifi_config_flags)
|
|
{
|
|
if (!config_name && !wifi_config_flags)
|
|
return false;
|
|
|
|
if (strcmp(config_name, "wireless") == 0) {
|
|
*wifi_config_flags |= WIRELESS_CONFIG;
|
|
return true;
|
|
}
|
|
|
|
if (strcmp(config_name, "mapcontroller") == 0) {
|
|
*wifi_config_flags |= MAPCONTROLLER_CONFIG;
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
int bbf_config_call(struct ubus_context *ctx, const char *object, const char *method, struct blob_buf *data, ubus_data_handler_t callback, void *arg)
|
|
{
|
|
int fault = 0;
|
|
uint32_t id;
|
|
|
|
if (!ctx) {
|
|
ULOG_ERR("Failed to execute 'bbf_config_call': 'ctx' is NULL.");
|
|
return -1;
|
|
}
|
|
|
|
fault = ubus_lookup_id(ctx, object, &id);
|
|
if (fault) {
|
|
ULOG_ERR("Failed to find UBUS object ID for '%s'. Error code: %d", object, fault);
|
|
return -1;
|
|
}
|
|
|
|
fault = ubus_invoke(ctx, id, method, data ? data->head : NULL, callback, arg, DEFAULT_UBUS_TIMEOUT);
|
|
if (fault) {
|
|
ULOG_ERR("UBUS invoke failed for method '%s' on object '%s'. Error code: %d", method, object, 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};
|
|
|
|
if (!ctx || !config_name) {
|
|
ULOG_ERR("Failed to reload service: 'ctx' or 'config_name' is NULL");
|
|
return;
|
|
}
|
|
|
|
memset(&bb, 0, sizeof(struct blob_buf));
|
|
|
|
blob_buf_init(&bb, 0);
|
|
|
|
blobmsg_add_string(&bb, "config", config_name);
|
|
|
|
int result = bbf_config_call(ctx, "uci", (is_commit) ? "commit" : "revert", &bb, NULL, NULL);
|
|
if (result != 0) {
|
|
ULOG_ERR("Failed to %s configuration '%s'", (is_commit ? "commit" : "revert"), config_name);
|
|
} else {
|
|
ULOG_DEBUG("Successfully executed %s on configuration '%s'.", (is_commit ? "commit" : "revert"), config_name);
|
|
}
|
|
|
|
blob_buf_free(&bb);
|
|
}
|
|
|
|
void reload_specified_services(struct ubus_context *ctx, const char *conf_dir, const char *save_dir, struct blob_attr *services,
|
|
bool is_commit, bool reload, uint32_t *wifi_config_flags)
|
|
{
|
|
struct uci_context *uci_ctx = NULL;
|
|
struct blob_attr *service = NULL;
|
|
size_t rem = 0;
|
|
|
|
uci_ctx = uci_alloc_context();
|
|
if (!uci_ctx) {
|
|
ULOG_ERR("Failed to allocate UCI context");
|
|
return;
|
|
}
|
|
|
|
if (conf_dir) {
|
|
ULOG_DEBUG("Setting UCI configuration directory to '%s'", conf_dir);
|
|
uci_set_confdir(uci_ctx, conf_dir);
|
|
}
|
|
|
|
if (save_dir) {
|
|
ULOG_DEBUG("Setting UCI save directory to '%s'", save_dir);
|
|
uci_set_savedir(uci_ctx, save_dir);
|
|
}
|
|
|
|
ULOG_DEBUG("Processing services list...");
|
|
blobmsg_for_each_attr(service, services, rem) {
|
|
struct uci_ptr ptr = {0};
|
|
|
|
char *config_name = blobmsg_get_string(service);
|
|
|
|
ULOG_DEBUG("Looking up UCI configuration for service '%s'", config_name);
|
|
|
|
if (uci_lookup_ptr(uci_ctx, &ptr, config_name, true) != UCI_OK) {
|
|
ULOG_ERR("Failed to lookup UCI pointer for service '%s'. Skipping", config_name);
|
|
continue;
|
|
}
|
|
|
|
if (is_commit) {
|
|
ULOG_DEBUG("Committing UCI changes for service '%s'", config_name);
|
|
if (uci_commit(uci_ctx, &ptr.p, false) != UCI_OK) {
|
|
ULOG_ERR("Failed to commit UCI changes for service '%s'", config_name);
|
|
continue;
|
|
}
|
|
} else {
|
|
ULOG_DEBUG("Reverting UCI changes for service '%s'", config_name);
|
|
if (uci_revert(uci_ctx, &ptr) != UCI_OK) {
|
|
ULOG_ERR("Failed to revert UCI changes for service '%s'", config_name);
|
|
continue;
|
|
}
|
|
}
|
|
|
|
if (reload) {
|
|
if (is_wifi_configs(config_name, wifi_config_flags))
|
|
continue;
|
|
|
|
ULOG_INFO("Reloading service '%s'", config_name);
|
|
reload_service(ctx, config_name, is_commit);
|
|
}
|
|
}
|
|
|
|
ULOG_DEBUG("Freeing UCI context");
|
|
uci_free_context(uci_ctx);
|
|
}
|
|
|
|
void reload_all_services(struct ubus_context *ctx, const char *conf_dir, const char *save_dir,
|
|
bool is_commit, bool reload, uint32_t *wifi_config_flags)
|
|
{
|
|
struct uci_context *uci_ctx = NULL;
|
|
char **configs = NULL, **p = NULL;
|
|
|
|
uci_ctx = uci_alloc_context();
|
|
if (!uci_ctx) {
|
|
ULOG_ERR("Failed to allocate UCI context");
|
|
return;
|
|
}
|
|
|
|
if (conf_dir) {
|
|
ULOG_DEBUG("Setting UCI configuration directory to '%s'", conf_dir);
|
|
uci_set_confdir(uci_ctx, conf_dir);
|
|
}
|
|
|
|
if (save_dir) {
|
|
ULOG_DEBUG("Setting UCI save directory to '%s'", save_dir);
|
|
uci_set_savedir(uci_ctx, save_dir);
|
|
}
|
|
|
|
if (uci_list_configs(uci_ctx, &configs) != UCI_OK) {
|
|
ULOG_ERR("Failed to list UCI configurations");
|
|
goto exit;
|
|
}
|
|
|
|
ULOG_DEBUG("Processing all configurations...");
|
|
for (p = configs; p && *p; p++) {
|
|
struct uci_ptr ptr = {0};
|
|
|
|
ULOG_DEBUG("Looking up UCI configuration for '%s'", *p);
|
|
|
|
if (uci_lookup_ptr(uci_ctx, &ptr, *p, true) != UCI_OK) {
|
|
ULOG_ERR("Failed to lookup UCI pointer for config '%s'. Skipping", *p);
|
|
continue;
|
|
}
|
|
|
|
if (uci_list_empty(&ptr.p->saved_delta)) {
|
|
ULOG_DEBUG("No changes detected in config '%s'. Skipping", *p);
|
|
continue;
|
|
}
|
|
|
|
if (is_commit) {
|
|
ULOG_DEBUG("Committing UCI changes for config '%s'", *p);
|
|
if (uci_commit(uci_ctx, &ptr.p, false) != UCI_OK) {
|
|
ULOG_ERR("Failed to commit changes for config '%s'", *p);
|
|
continue;
|
|
}
|
|
} else {
|
|
ULOG_DEBUG("Reverting UCI changes for config '%s'", *p);
|
|
if (uci_revert(uci_ctx, &ptr) != UCI_OK) {
|
|
ULOG_ERR("Failed to revert changes for config '%s'", *p);
|
|
continue;
|
|
}
|
|
}
|
|
|
|
if (reload) {
|
|
if (is_wifi_configs(*p, wifi_config_flags))
|
|
continue;
|
|
|
|
ULOG_INFO("Reloading service for config '%s'", *p);
|
|
reload_service(ctx, *p, is_commit);
|
|
}
|
|
}
|
|
|
|
FREE(configs);
|
|
|
|
exit:
|
|
uci_free_context(uci_ctx);
|
|
}
|
|
|
|
void wifi_reload_handler_script(uint32_t wifi_config_flags)
|
|
{
|
|
#define WIFI_CONFIG_RELOAD_SCRIPT "/etc/wifidmd/bbf_config_reload.sh"
|
|
char cmd[512] = {0};
|
|
|
|
if (!file_exists(WIFI_CONFIG_RELOAD_SCRIPT))
|
|
return;
|
|
|
|
snprintf(cmd, sizeof(cmd), "sh %s '{\"wireless\":\"%d\",\"mapcontroller\":\"%d\"}'",
|
|
WIFI_CONFIG_RELOAD_SCRIPT,
|
|
wifi_config_flags & WIRELESS_CONFIG ? 1 : 0,
|
|
wifi_config_flags & MAPCONTROLLER_CONFIG ? 1 : 0);
|
|
|
|
FILE *pp = popen(cmd, "r"); // flawfinder: ignore
|
|
if (pp) {
|
|
pclose(pp);
|
|
}
|
|
}
|
|
|
|
void uci_apply_changes(const char *conf_dir, const char *save_dir, bool is_commit)
|
|
{
|
|
struct uci_context *uci_ctx = NULL;
|
|
char **configs = NULL, **p = NULL;
|
|
|
|
uci_ctx = uci_alloc_context();
|
|
if (!uci_ctx) {
|
|
ULOG_ERR("Failed to allocate UCI context");
|
|
return;
|
|
}
|
|
|
|
if (conf_dir) {
|
|
ULOG_DEBUG("Setting UCI configuration directory to '%s'", conf_dir);
|
|
uci_set_confdir(uci_ctx, conf_dir);
|
|
}
|
|
|
|
if (save_dir) {
|
|
ULOG_DEBUG("Setting UCI save directory to '%s'", save_dir);
|
|
uci_set_savedir(uci_ctx, save_dir);
|
|
}
|
|
|
|
if (uci_list_configs(uci_ctx, &configs) != UCI_OK) {
|
|
ULOG_ERR("Failed to list UCI configurations");
|
|
goto exit;
|
|
}
|
|
|
|
ULOG_DEBUG("Applying changes to all configurations...");
|
|
for (p = configs; p && *p; p++) {
|
|
struct uci_ptr ptr = {0};
|
|
|
|
ULOG_DEBUG("Looking up UCI configuration for '%s'", *p);
|
|
|
|
if (uci_lookup_ptr(uci_ctx, &ptr, *p, true) != UCI_OK) {
|
|
ULOG_ERR("Failed to lookup UCI pointer for config '%s'. Skipping", *p);
|
|
continue;
|
|
}
|
|
|
|
if (is_commit) {
|
|
ULOG_DEBUG("Committing changes for config '%s'", *p);
|
|
if (uci_commit(uci_ctx, &ptr.p, false) != UCI_OK) {
|
|
ULOG_ERR("Failed to commit changes for config '%s'", *p);
|
|
continue;
|
|
}
|
|
} else {
|
|
ULOG_DEBUG("Reverting changes for config '%s'", *p);
|
|
if (uci_revert(uci_ctx, &ptr) != UCI_OK) {
|
|
ULOG_ERR("Failed to revert changes for config '%s'", *p);
|
|
continue;
|
|
}
|
|
}
|
|
}
|
|
|
|
FREE(configs);
|
|
|
|
exit:
|
|
uci_free_context(uci_ctx);
|
|
}
|
|
|
|
void uci_config_changes(const char *conf_dir, const char *save_dir, struct blob_buf *bb)
|
|
{
|
|
struct uci_context *uci_ctx = NULL;
|
|
char **configs = NULL, **p = NULL;
|
|
|
|
uci_ctx = uci_alloc_context();
|
|
if (!uci_ctx) {
|
|
ULOG_ERR("Failed to allocate UCI context");
|
|
return;
|
|
}
|
|
|
|
if (conf_dir) {
|
|
ULOG_DEBUG("Setting UCI configuration directory to '%s'", conf_dir);
|
|
uci_set_confdir(uci_ctx, conf_dir);
|
|
}
|
|
|
|
if (save_dir) {
|
|
ULOG_DEBUG("Setting UCI save directory to '%s'", save_dir);
|
|
uci_set_savedir(uci_ctx, save_dir);
|
|
}
|
|
|
|
if (uci_list_configs(uci_ctx, &configs) != UCI_OK) {
|
|
ULOG_ERR("Failed to list UCI configurations");
|
|
goto exit;
|
|
}
|
|
|
|
ULOG_DEBUG("Identifying configurations with unsaved changes...");
|
|
for (p = configs; p && *p; p++) {
|
|
struct uci_ptr ptr = {0};
|
|
|
|
ULOG_DEBUG("Looking up UCI configuration for '%s'", *p);
|
|
|
|
if (uci_lookup_ptr(uci_ctx, &ptr, *p, true) != UCI_OK) {
|
|
ULOG_ERR("Failed to lookup UCI pointer for config '%s'. Skipping.", *p);
|
|
continue;
|
|
}
|
|
|
|
if (uci_list_empty(&ptr.p->saved_delta)) {
|
|
ULOG_DEBUG("No unsaved changes in config '%s'. Skipping", *p);
|
|
continue;
|
|
}
|
|
|
|
ULOG_INFO("Unsaved changes detected in config '%s', adding to blob buffer", *p);
|
|
blobmsg_add_string(bb, NULL, *p);
|
|
}
|
|
|
|
FREE(configs);
|
|
|
|
exit:
|
|
uci_free_context(uci_ctx);
|
|
}
|