diff --git a/src/Makefile b/src/Makefile index 1ab5a524c5f0d94fda8e46d1e508955db7f1b2ff..a8d795b6fb725f0e97592a9ed898f1d5923f1cb3 100644 --- a/src/Makefile +++ b/src/Makefile @@ -27,11 +27,6 @@ OBJS += supported_dm.o PROG_CFLAGS += -DSYSMNGR_SUPPORTED_DATA_MODEL endif -ifeq ($(SYSMNGR_FIRMWARE_IMAGE),y) -OBJS += fw_images.o -PROG_CFLAGS += -DSYSMNGR_FIRMWARE_IMAGE -endif - ifeq ($(SYSMNGR_REBOOTS),y) OBJS += reboots.o PROG_CFLAGS += -DSYSMNGR_REBOOTS @@ -46,6 +41,19 @@ ifeq ($(SYSMNGR_VENDOR_EXTENSIONS),y) PROG_CFLAGS += -DSYSMNGR_VENDOR_EXTENSIONS endif +ifneq ($(filter y,$(SYSMNGR_FIRMWARE_IMAGE) $(SYSMNGR_FWBANK_UBUS_SUPPORT)),) +OBJS += fwbank.o +endif + +ifeq ($(SYSMNGR_FIRMWARE_IMAGE),y) +OBJS += fw_images.o +PROG_CFLAGS += -DSYSMNGR_FIRMWARE_IMAGE +endif + +ifeq ($(SYSMNGR_FWBANK_UBUS_SUPPORT),y) +PROG_CFLAGS += -DSYSMNGR_FWBANK_UBUS_SUPPORT +endif + .PHONY: all clean %.o: %.c diff --git a/src/deviceinfo.c b/src/deviceinfo.c index 34c935b990d222bab188ac78f7544a39321c2d85..d1e18c934086453ff361ea7309d918636cbaa727 100644 --- a/src/deviceinfo.c +++ b/src/deviceinfo.c @@ -251,7 +251,7 @@ DMOBJ tDeviceInfoObj[] = { #endif #ifdef SYSMNGR_FIRMWARE_IMAGE -{"FirmwareImage", &DMREAD, NULL, NULL, "file:/usr/libexec/rpcd/fwbank", browseDeviceInfoFirmwareImageInst, NULL, NULL, NULL, tDeviceInfoFirmwareImageParams, NULL, BBFDM_BOTH}, +{"FirmwareImage", &DMREAD, NULL, NULL, fw_image_dependency, browseDeviceInfoFirmwareImageInst, NULL, NULL, NULL, tDeviceInfoFirmwareImageParams, NULL, BBFDM_BOTH}, #endif #ifdef SYSMNGR_REBOOTS diff --git a/src/fw_images.c b/src/fw_images.c index 9b166a6b27b73ab5c0b3c6d4b3057ac2672028a0..6fd8daa52ae3e8e0d938fab053dcbe5088bf8b40 100644 --- a/src/fw_images.c +++ b/src/fw_images.c @@ -10,6 +10,7 @@ */ #include "utils.h" +#include "fwbank.h" #define MAX_TIME_WINDOW 5 @@ -21,6 +22,105 @@ struct sysupgrade_ev_data { /************************************************************* * COMMON FUNCTIONS **************************************************************/ +static char *get_blobmsg_option_value(struct blob_attr *entry, const char *option_name) +{ + struct blob_attr *tb[9] = {0}; + char *option_value = NULL; + + if (!entry) + return ""; + + blobmsg_parse(sysmngr_bank_policy, 9, tb, blobmsg_data(entry), blobmsg_len(entry)); + + if (DM_STRCMP(sysmngr_bank_policy[0].name, option_name) == 0 && tb[0]) // Name + option_value = dmstrdup(blobmsg_get_string(tb[0])); + else if (DM_STRCMP(sysmngr_bank_policy[1].name, option_name) == 0 && tb[1]) // ID + dmasprintf(&option_value, "%d", blobmsg_get_u32(tb[1])); + else if (DM_STRCMP(sysmngr_bank_policy[2].name, option_name) == 0 && tb[2]) // Active + option_value = dmstrdup(blobmsg_get_bool(tb[2]) ? "true" : "false"); + else if (DM_STRCMP(sysmngr_bank_policy[3].name, option_name) == 0 && tb[3]) // Boot + option_value = dmstrdup(blobmsg_get_bool(tb[3]) ? "true" : "false"); + else if (DM_STRCMP(sysmngr_bank_policy[4].name, option_name) == 0 && tb[4]) // Upgrade + option_value = dmstrdup(blobmsg_get_bool(tb[4]) ? "true" : "false"); + else if (DM_STRCMP(sysmngr_bank_policy[5].name, option_name) == 0 && tb[5]) // Firmware Version + option_value = dmstrdup(blobmsg_get_string(tb[5])); + else if (DM_STRCMP(sysmngr_bank_policy[6].name, option_name) == 0 && tb[6]) // Software Version + option_value = dmstrdup(blobmsg_get_string(tb[6])); + else if (DM_STRCMP(sysmngr_bank_policy[7].name, option_name) == 0 && tb[7]) // OMCI Software Version + option_value = dmstrdup(blobmsg_get_string(tb[7])); + else if (DM_STRCMP(sysmngr_bank_policy[8].name, option_name) == 0 && tb[8]) // Status + option_value = dmstrdup(blobmsg_get_string(tb[8])); + else // Otherwise + option_value = ""; + + return option_value ? option_value : ""; +} + +static char *get_fwbank_option_value(void *data, const char *option_name) +{ + char *option_value = NULL; + + option_value = get_blobmsg_option_value((struct blob_attr *)((struct dm_data *)data)->additional_data, option_name); + + return option_value ? option_value : ""; +} + +static char *get_fwbank_bank_id(const char *option_name) +{ + char *bank_id = NULL; + + struct blob_buf *dump_bb = sysmngr_fwbank_dump(); + if (!dump_bb) //dump output is empty + return ""; + + struct blob_attr *tb[1] = {0}; + + blobmsg_parse(sysmngr_dump_policy, 1, tb, blobmsg_data(dump_bb->head), blobmsg_len(dump_bb->head)); + + if (!tb[0]) // bank array is not found + return ""; + + struct blob_attr *entry = NULL; + int rem = 0; + + blobmsg_for_each_attr(entry, tb[0], rem) { // parse bank array + char *is_true = get_blobmsg_option_value(entry, option_name); + if (DM_LSTRCMP(is_true, "true") == 0) { + bank_id = get_blobmsg_option_value(entry, "id"); + break; + } + } + + return bank_id ? bank_id : ""; +} + +static bool fwbank_set_bootbank(char *bank_id) +{ + int res = sysmngr_fwbank_set_bootbank((uint32_t)DM_STRTOUL(bank_id), NULL); + + return !res ? true : false; +} + +static bool fwbank_upgrade(const char *path, const char *auto_activate, const char *bank_id, const char *keep_settings) +{ + json_object *json_obj = NULL; + int res = 0; + + dmubus_call_blocking("fwbank", "upgrade", UBUS_ARGS{{"path", path, String}, {"auto_activate", auto_activate, Boolean}, {"bank", bank_id, Integer}, {"keep_settings", keep_settings, Boolean}}, 4, &json_obj); + + if (json_obj) { + char *result = dmjson_get_value(json_obj, 1, "result"); + res = (DM_LSTRCMP(result, "ok") == 0) ? true : false; + } else { + res = false; + } + + if (json_obj != NULL) + json_object_put(json_obj); + + return res; +} + static void _exec_reboot(const void *arg1, void *arg2) { char config_name[16] = {0}; @@ -63,6 +163,7 @@ static void dmubus_receive_sysupgrade(struct ubus_context *ctx, struct ubus_even size_t msg_len = (size_t)blobmsg_data_len(msg); __blob_for_each_attr(msg_attr, blobmsg_data(msg), msg_len) { + if (DM_STRCMP("bank_id", blobmsg_name(msg_attr)) == 0) { char *attr_val = (char *)blobmsg_data(msg_attr); if (DM_STRCMP(attr_val, ev_data->bank_id) != 0) @@ -77,7 +178,6 @@ static void dmubus_receive_sysupgrade(struct ubus_context *ctx, struct ubus_even ev_data->status = true; else ev_data->status = false; - } } @@ -87,7 +187,7 @@ static void dmubus_receive_sysupgrade(struct ubus_context *ctx, struct ubus_even static int bbf_fw_image_download(const char *url, const char *auto_activate, const char *username, const char *password, const char *file_size, const char *checksum_algorithm, const char *checksum, - const char *bank_id, const char *command, const char *obj_path, const char *commandKey, char *keep) + const char *bank_id, const char *command, const char *obj_path, const char *commandKey, const char *keep) { char fw_image_path[256] = {0}; json_object *json_obj = NULL; @@ -133,9 +233,6 @@ static int bbf_fw_image_download(const char *url, const char *auto_activate, con goto end; } - string_to_bool(auto_activate, &activate); - char *act = (activate) ? "1" : "0"; - dmubus_call_blocking("system", "validate_firmware_image", UBUS_ARGS{{"path", fw_image_path, String}}, 1, &json_obj); if (json_obj == NULL) { res = -1; @@ -145,20 +242,21 @@ static int bbf_fw_image_download(const char *url, const char *auto_activate, con char *val = dmjson_get_value(json_obj, 1, "valid"); string_to_bool(val, &valid); + + // Free json_obj json_object_put(json_obj); json_obj = NULL; + if (valid == false) { snprintf(fault_msg, sizeof(fault_msg), "File is not a valid firmware image"); res = -1; goto end; } - // default state is to preserve the config over firmware upgrades - char *keep_config = DM_STRLEN((char *)keep) ? keep : "1"; + string_to_bool(auto_activate, &activate); // Apply Firmware Image - dmubus_call_blocking("fwbank", "upgrade", UBUS_ARGS{{"path", fw_image_path, String}, {"auto_activate", act, Boolean}, {"bank", bank_id, Integer}, {"keep_settings", keep_config, Boolean}}, 4, &json_obj); - if (json_obj == NULL) { + if (!fwbank_upgrade(fw_image_path, (activate) ? "1" : "0", bank_id, DM_STRLEN(keep) ? keep : "1")) { res = 1; snprintf(fault_msg, sizeof(fault_msg), "Internal error occurred when applying the firmware"); goto end; @@ -187,13 +285,8 @@ end: send_transfer_complete_event(command, obj_path, url, fault_msg, start_time, complete_time, commandKey, "Download"); // Remove temporary file if ubus upgrade failed and file exists - if (!json_obj && file_exists(fw_image_path) && strncmp(url, FILE_URI, strlen(FILE_URI))) { + if (file_exists(fw_image_path) && strncmp(url, FILE_URI, strlen(FILE_URI))) remove(fw_image_path); - res = -1; - } - - if (json_obj != NULL) - json_object_put(json_obj); return res; } @@ -203,22 +296,32 @@ end: **************************************************************/ int browseDeviceInfoFirmwareImageInst(struct dmctx *dmctx, DMNODE *parent_node, void *prev_data, char *prev_instance) { - json_object *res = NULL, *bank_obj = NULL, *arrobj = NULL; struct dm_data curr_data = {0}; + struct blob_attr *tb[1] = {0}; char *inst = NULL; - int id = 0, i = 0; + int id = 0; - dmubus_call("fwbank", "dump", UBUS_ARGS{0}, 0, &res); + struct blob_buf *dump_bb = sysmngr_fwbank_dump(); + if (!dump_bb) //dump output is empty + return 0; - dmjson_foreach_obj_in_array(res, arrobj, bank_obj, i, 1, "bank") { + blobmsg_parse(sysmngr_dump_policy, 1, tb, blobmsg_data(dump_bb->head), blobmsg_len(dump_bb->head)); - curr_data.json_object = bank_obj; + if (tb[0]) { // bank array defined + struct blob_attr *entry = NULL; + int rem = 0; - inst = handle_instance_without_section(dmctx, parent_node, ++id); + blobmsg_for_each_attr(entry, tb[0], rem) { // parse bank array - if (DM_LINK_INST_OBJ(dmctx, parent_node, (void *)&curr_data, inst) == DM_STOP) - break; + curr_data.additional_data = (void *)entry; + + inst = handle_instance_without_section(dmctx, parent_node, ++id); + + if (DM_LINK_INST_OBJ(dmctx, parent_node, (void *)&curr_data, inst) == DM_STOP) + break; + } } + return 0; } @@ -227,50 +330,30 @@ int browseDeviceInfoFirmwareImageInst(struct dmctx *dmctx, DMNODE *parent_node, **************************************************************/ int get_device_active_fwimage(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) { - json_object *res = NULL, *bank_obj = NULL, *arrobj = NULL; - char linker[16] = {0}, *id = NULL; - int i = 0; - - dmubus_call("fwbank", "dump", UBUS_ARGS{0}, 0, &res); - dmjson_foreach_obj_in_array(res, arrobj, bank_obj, i, 1, "bank") { - char *active = dmjson_get_value(bank_obj, 1, "active"); - if (active && DM_LSTRCMP(active, "true") == 0) { - id = dmjson_get_value(bank_obj, 1, "id"); - break; - } - } - - if (DM_STRLEN(id) == 0) { + char *bank_id = get_fwbank_bank_id("active"); + if (DM_STRLEN(bank_id) == 0) { *value = dmstrdup(""); return 0; } - snprintf(linker, sizeof(linker), "cpe-%s", id); + char linker[16] = {0}; + + snprintf(linker, sizeof(linker), "cpe-%s", bank_id); _bbfdm_get_references(ctx, "Device.DeviceInfo.FirmwareImage.", "Alias", linker, value); return 0; } int get_device_boot_fwimage(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) { - json_object *res = NULL, *bank_obj = NULL, *arrobj = NULL; - char linker[16] = {0}, *id = NULL; - int i = 0; - - dmubus_call("fwbank", "dump", UBUS_ARGS{0}, 0, &res); - dmjson_foreach_obj_in_array(res, arrobj, bank_obj, i, 1, "bank") { - char *boot = dmjson_get_value(bank_obj, 1, "boot"); - if (boot && DM_LSTRCMP(boot, "true") == 0) { - id = dmjson_get_value(bank_obj, 1, "id"); - break; - } - } - - if (DM_STRLEN(id) == 0) { + char *bank_id = get_fwbank_bank_id("boot"); + if (DM_STRLEN(bank_id) == 0) { *value = dmstrdup(""); return 0; } - snprintf(linker, sizeof(linker), "cpe-%s", id); + char linker[16] = {0}; + + snprintf(linker, sizeof(linker), "cpe-%s", bank_id); _bbfdm_get_references(ctx, "Device.DeviceInfo.FirmwareImage.", "Alias", linker, value); return 0; } @@ -294,7 +377,6 @@ int set_device_boot_fwimage(char *refparam, struct dmctx *ctx, void *data, char case VALUESET: if (DM_STRLEN(reference.value)) { struct uci_section *dmmap_s = NULL; - json_object *res = NULL; char *available = NULL; char *bank_id = DM_STRCHR(reference.value, '-'); // Get bank id 'X' which is linker from Alias prefix 'cpe-X' @@ -306,11 +388,8 @@ int set_device_boot_fwimage(char *refparam, struct dmctx *ctx, void *data, char if (DM_LSTRCMP(available, "false") == 0) return FAULT_9001; - dmubus_call("fwbank", "set_bootbank", UBUS_ARGS{{"bank", bank_id + 1, Integer}}, 1, &res); - char *success = dmjson_get_value(res, 1, "success"); - if (DM_LSTRCMP(success, "true") != 0) + if (!fwbank_set_bootbank(bank_id + 1)) return FAULT_9001; - } break; } @@ -332,7 +411,7 @@ int get_DeviceInfo_FirmwareImageNumberOfEntries(char *refparam, struct dmctx *ct static int get_DeviceInfoFirmwareImage_Alias(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) { - char *id = dmjson_get_value(((struct dm_data *)data)->json_object, 1, "id"); + char *id = get_fwbank_option_value(data, "id"); dmasprintf(value, "cpe-%s", id ? id : instance); return 0; } @@ -353,9 +432,7 @@ static int set_DeviceInfoFirmwareImage_Alias(char *refparam, struct dmctx *ctx, static int get_DeviceInfoFirmwareImage_Name(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) { - char *name; - - name = dmstrdup(dmjson_get_value(((struct dm_data *)data)->json_object, 1, "fwver")); + char *name = get_fwbank_option_value(data, "fwver"); if (DM_STRLEN(name) > 64 ) { name[64] = '\0'; } @@ -366,7 +443,7 @@ static int get_DeviceInfoFirmwareImage_Name(char *refparam, struct dmctx *ctx, v static int get_DeviceInfoFirmwareImage_Version(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) { - *value = dmjson_get_value(((struct dm_data *)data)->json_object, 1, "swver"); + *value = get_fwbank_option_value(data, "swver"); return 0; } @@ -374,7 +451,7 @@ static int get_DeviceInfoFirmwareImage_Available(char *refparam, struct dmctx *c { struct uci_section *s = NULL; - char *id = dmjson_get_value(((struct dm_data *)data)->json_object, 1, "id"); + char *id = get_fwbank_option_value(data, "id"); uci_path_foreach_option_eq(bbfdm, "dmmap_fw_image", "fw_image", "id", id, s) { dmuci_get_value_by_section_string(s, "available", value); @@ -401,13 +478,13 @@ static int set_DeviceInfoFirmwareImage_Available(char *refparam, struct dmctx *c string_to_bool(value, &b); if (!b) { - char *boot = dmjson_get_value(((struct dm_data *)data)->json_object, 1, "boot"); - char *active = dmjson_get_value(((struct dm_data *)data)->json_object, 1, "active"); + char *boot = get_fwbank_option_value(data, "boot"); + char *active = get_fwbank_option_value(data, "active"); if (DM_LSTRCMP(boot, "true") == 0 || DM_LSTRCMP(active, "true") == 0) return FAULT_9001; } - id = dmjson_get_value(((struct dm_data *)data)->json_object, 1, "id"); + id = get_fwbank_option_value(data, "id"); uci_path_foreach_option_eq(bbfdm, "dmmap_fw_image", "fw_image", "id", id, s) { dmuci_set_value_by_section_bbfdm(s, "available", b ? "true" : "false"); @@ -424,7 +501,7 @@ static int set_DeviceInfoFirmwareImage_Available(char *refparam, struct dmctx *c static int get_DeviceInfoFirmwareImage_Status(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) { - *value = dmjson_get_value(((struct dm_data *)data)->json_object, 1, "status"); + *value = get_fwbank_option_value(data, "status"); return 0; } @@ -465,12 +542,12 @@ static int operate_DeviceInfoFirmwareImage_Download(char *refparam, struct dmctx snprintf(obj_path, ret - refparam + 2, "%s", refparam); char *url = dmjson_get_value((json_object *)value, 1, "URL"); - char *auto_activate = dmjson_get_value((json_object *)value, 1, "AutoActivate"); if (url[0] == '\0') return USP_FAULT_INVALID_ARGUMENT; // Assuming auto activate as false, if not provided by controller, in case of strict validation, // this should result into a fault + char *auto_activate = dmjson_get_value((json_object *)value, 1, "AutoActivate"); if (DM_STRLEN(auto_activate) == 0) auto_activate = dmstrdup("0"); @@ -482,7 +559,7 @@ static int operate_DeviceInfoFirmwareImage_Download(char *refparam, struct dmctx char *commandKey = dmjson_get_value((json_object *)value, 1, "CommandKey"); char *keep_config = dmjson_get_value((json_object *)value, 1, BBF_VENDOR_PREFIX"KeepConfig"); - char *bank_id = dmjson_get_value(((struct dm_data *)data)->json_object, 1, "id"); + char *bank_id = get_fwbank_option_value(data, "id"); int res = bbf_fw_image_download(url, auto_activate, username, password, file_size, checksum_algorithm, checksum, bank_id, command, obj_path, commandKey, keep_config); @@ -569,7 +646,8 @@ static int operate_DeviceInfoFirmwareImage_Activate(char *refparam, struct dmctx last_idx++; } - char *bank_id = dmjson_get_value(((struct dm_data *)data)->json_object, 1, "id"); + char *bank_id = get_fwbank_option_value(data, "id"); + if (!DM_STRLEN(bank_id)) return USP_FAULT_COMMAND_FAILURE; @@ -605,11 +683,7 @@ static int operate_DeviceInfoFirmwareImage_Activate(char *refparam, struct dmctx res = dmcmd_no_wait("/etc/init.d/cron", 1, "restart"); } else { - json_object *json_obj = NULL; - - dmubus_call("fwbank", "set_bootbank", UBUS_ARGS{{"bank", bank_id, Integer}}, 1, &json_obj); - char *status = dmjson_get_value(json_obj, 1, "success"); - if (strcasecmp(status, "true") != 0) + if (!fwbank_set_bootbank(bank_id)) return USP_FAULT_COMMAND_FAILURE; bbfdm_task_fork(_exec_reboot, NULL, NULL, NULL); diff --git a/src/fw_images.h b/src/fw_images.h index 23047d9f375bf591c7e3a4cf1e3d5475853ba8af..b79255f62680c82a5183fea01f5d8f5b192d3819 100644 --- a/src/fw_images.h +++ b/src/fw_images.h @@ -13,6 +13,7 @@ #define __FW_IMAGES_H extern DMLEAF tDeviceInfoFirmwareImageParams[]; +extern char fw_image_dependency[]; int browseDeviceInfoFirmwareImageInst(struct dmctx *dmctx, DMNODE *parent_node, void *prev_data, char *prev_instance); diff --git a/src/fwbank.c b/src/fwbank.c new file mode 100644 index 0000000000000000000000000000000000000000..469a615697642d4c7567e9e3e210917c84561f24 --- /dev/null +++ b/src/fwbank.c @@ -0,0 +1,779 @@ +/* + * Copyright (C) 2024 iopsys Software Solutions AB + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 2.1 + * as published by the Free Software Foundation + * + * Author: Amin Ben Romdhane <amin.benromdhane@iopsys.eu> + * + */ + +#include "utils.h" +#include "fwbank.h" + +#ifdef SYSMNGR_FWBANK_UBUS_SUPPORT +char fw_image_dependency[] = "file:/etc/sysmngr/fwbank"; +#define FWBANK_FILE_PATH "/etc/sysmngr/fwbank" +#else +char fw_image_dependency[] = "file:/usr/libexec/rpcd/fwbank"; +#define FWBANK_FILE_PATH "/usr/libexec/rpcd/fwbank" +#endif + +#define FWBANK_DUMP_CMD FWBANK_FILE_PATH " call dump" +#define FWBANK_SET_BOOTBANK_CMD FWBANK_FILE_PATH " call set_bootbank" +#define FWBANK_UPGRADE_CMD FWBANK_FILE_PATH " call upgrade" + +#define FWBANK_DUMP_MAX_RETRIES 10 +#define FWBANK_DUMP_RETRY_DELAY 3 + +struct fwbank_event_data { + struct ubus_context *ctx; + struct uloop_timeout tm; + struct ubus_event_handler ev; + uint32_t band_id; + int timeout; +}; + +struct fwbank_dump_data { + struct ubus_context *ctx; + struct uloop_timeout tm; + struct blob_buf output; +}; + +static struct fwbank_dump_data g_fwbank_dump = {0}; +static int g_retry_count = 0; + +typedef void (*sysmngr_task_callback_t)(struct ubus_context *ctx, struct ubus_request_data *req, int *pipe_fds, uint32_t bank_id); + +typedef struct sysmngr_task_data { + struct ubus_context *ctx; + struct ubus_request_data *req; + struct ubus_request_data new_req; + struct uloop_process process; // Used for forked task + struct uloop_timeout timeoutcb; // Timeout for the task + sysmngr_task_callback_t finishcb; // Finish callback for parent process + const char *command; // Command to execute + int pipe_fds[2]; + uint32_t bank_id; +} sysmngr_task_data_t; + +struct blobmsg_policy sysmngr_dump_policy[] = { + { "bank", BLOBMSG_TYPE_ARRAY } +}; + +struct blobmsg_policy sysmngr_bank_policy[] = { + { "name", BLOBMSG_TYPE_STRING }, + { "id", BLOBMSG_TYPE_INT32 }, + { "active", BLOBMSG_TYPE_BOOL }, + { "boot", BLOBMSG_TYPE_BOOL }, + { "upgrade", BLOBMSG_TYPE_BOOL }, + { "fwver", BLOBMSG_TYPE_STRING }, + { "swver", BLOBMSG_TYPE_STRING }, + { "omci_swver", BLOBMSG_TYPE_STRING }, + { "status", BLOBMSG_TYPE_STRING } +}; + +static void _sysmngr_task_finish_callback(struct uloop_process *p, int ret) +{ + struct sysmngr_task_data *task = NULL; + + task = container_of(p, struct sysmngr_task_data, process); + + if (task == NULL) { + BBF_ERR("Failed to decode forked task"); + return; + } + + if (task->timeoutcb.pending) { + // Cancel timeout if the task finishes on its own + uloop_timeout_cancel(&task->timeoutcb); + } + + if (task->finishcb) { + task->finishcb(task->ctx, &task->new_req, task->pipe_fds, task->bank_id); + } + + if (task->ctx && task->req) { + ubus_complete_deferred_request(task->ctx, &task->new_req, 0); + } + + FREE(task); +} + +static void task_callback(const char *command, int *pipe_fds) +{ + // Redirect stdout to the pipe's write end + dup2(pipe_fds[1], STDOUT_FILENO); + close(pipe_fds[0]); // Close unused read end + close(pipe_fds[1]); // Close write end after dup2 + + if (!command) + exit(EXIT_FAILURE); + + char *line = NULL; + ssize_t read; + size_t len; + + FILE *pipe = popen(command, "r"); // flawfinder: ignore + if (pipe == NULL) + exit(EXIT_FAILURE); + + while ((read = getline(&line, &len, pipe)) != -1) { + // Output the command's result to stdout + line[read - 1] = '\0'; // Remove trailing newline + printf("%s", line); + } + + free(line); + + if (pclose(pipe) == -1) + exit(EXIT_FAILURE); + + exit(EXIT_SUCCESS); +} + +static void timeout_callback(struct uloop_timeout *t) +{ + sysmngr_task_data_t *task = container_of(t, sysmngr_task_data_t, timeoutcb); + + if (task && task->process.pid > 0) { + BBF_ERR("Task timed out. Killing process with PID %d\n", task->process.pid); + kill(task->process.pid, SIGKILL); + } +} + +static int sysmngr_task_fork(sysmngr_task_callback_t finishcb, const char *command, int timeout, struct ubus_request_data *req, uint32_t bank_id) +{ + sysmngr_task_data_t *task; + pid_t child; + + task = (sysmngr_task_data_t *)calloc(sizeof(sysmngr_task_data_t), 1); + if (task == NULL) { + return -1; + } + + if (pipe(task->pipe_fds) == -1) { + BBF_ERR("pipe failed"); + FREE(task); + return -1; + } + + task->command = command; + task->ctx = g_fwbank_dump.ctx; + task->req = req; + task->bank_id = bank_id; + + child = fork(); + if (child == -1) { + BBF_ERR("Failed to fork a child for task"); + FREE(task); + return -1; + } else if (child == 0) { + /* free fd's and memory inherited from parent */ + uloop_done(); + fclose(stdin); + fclose(stderr); + + task_callback(task->command, task->pipe_fds); + + /* write result and exit */ + exit(EXIT_SUCCESS); + } + + if (finishcb) { + task->finishcb = finishcb; + task->process.pid = child; + task->process.cb = _sysmngr_task_finish_callback; + uloop_process_add(&task->process); + } + + if (task->ctx && task->req) { + ubus_defer_request(task->ctx, task->req, &task->new_req); + } + + if (timeout > 0) { + task->timeoutcb.cb = timeout_callback; + uloop_timeout_set(&task->timeoutcb, 1000 * timeout); + } + + return 0; +} + +static void fwbank_dump_timer(struct uloop_timeout *timeout) +{ + struct fwbank_dump_data *data = NULL; + + BBF_DEBUG("fwbank_dump_timer triggered"); + + data = container_of(timeout, struct fwbank_dump_data, tm); + if (data == NULL) + return; + + sysmngr_init_fwbank_dump(data->ctx); +} + +static int validate_global_fwbank_dump(struct blob_buf *fwbank_dump_bb) +{ + if (!fwbank_dump_bb->head || !blob_len(fwbank_dump_bb->head)) { + BBF_ERR("fwbank dump output is empty"); + return -1; + } + + BBF_DEBUG("Validating global fwbank dump"); + struct blob_attr *tb[1] = {0}; + + if (blobmsg_parse(sysmngr_dump_policy, 1, tb, blobmsg_data(fwbank_dump_bb->head), blobmsg_len(fwbank_dump_bb->head))) { + BBF_ERR("Failed to parse fwbank dump blob"); + return -1; + } + + if (!tb[0]) { // bank array is not found + BBF_ERR("Bank array not found in fwbank dump"); + return -1; + } + + struct blob_attr *entry = NULL; + int rem = 0; + + blobmsg_for_each_attr(entry, tb[0], rem) { // parse bank array + struct blob_attr *t[9] = {0}; + + if (blobmsg_parse(sysmngr_bank_policy, 9, t, blobmsg_data(entry), blobmsg_len(entry))) { + BBF_ERR("Failed to parse bank entry"); + return -1; + } + + if (!t[0] || !t[1] || !t[2] || !t[3] || !t[4] || !t[5] || !t[6] || !t[7] || !t[8]) + return -1; + } + + BBF_DEBUG("Global fwbank dump validation passed"); + return 0; +} + +static void fwbank_dump_finish_callback(struct ubus_context *ctx, struct ubus_request_data *req, int *pipe_fds, uint32_t bank_id) +{ + BBF_DEBUG("Task finished Line=%d && func=%s", __LINE__, __func__); + + close(pipe_fds[1]); // Close unused write end + + char buffer[1024] = {0}; + ssize_t bytes_read; + + BBF_DEBUG("Reading script output..."); + + // Read the output from the script + while ((bytes_read = read(pipe_fds[0], buffer, sizeof(buffer) - 1)) > 0) { + buffer[bytes_read] = '\0'; // Null-terminate the buffer + BBF_DEBUG("Script output: %s", buffer); + } + + close(pipe_fds[0]); // Close read end + + if (bytes_read < 0) { + BBF_ERR("Failed to read from pipe"); + goto retry; + } + + memset(&g_fwbank_dump.output, 0, sizeof(struct blob_buf)); + blob_buf_init(&g_fwbank_dump.output, 0); + + if (!blobmsg_add_json_from_string(&g_fwbank_dump.output, buffer)) { + BBF_ERR("Failed to create blob buf"); + goto retry; + } + + int res = validate_global_fwbank_dump(&g_fwbank_dump.output); + if (res) { + BBF_ERR("Failed to validate 'fwbank' output"); + goto retry; + } + + return; + +retry: + if (g_retry_count < FWBANK_DUMP_MAX_RETRIES) { + g_retry_count++; + uloop_timeout_set(&g_fwbank_dump.tm, FWBANK_DUMP_RETRY_DELAY * 1000); + + BBF_ERR("Attempt %d/%d: fwbank dump blob buf is empty. Retrying in %d second(s)...", + g_retry_count, FWBANK_DUMP_MAX_RETRIES, FWBANK_DUMP_RETRY_DELAY); + } else { + BBF_ERR("Max retries (%d) reached: The fwbank dump buffer is empty. Unable to register 'fwbank' ubus object", + FWBANK_DUMP_MAX_RETRIES); + } +} + +static int init_global_fwbank_dump(void) +{ + BBF_DEBUG("Initializing global fwbank dump"); + + int res = sysmngr_task_fork(fwbank_dump_finish_callback, FWBANK_DUMP_CMD, 10, NULL, 0); + if (res) { + BBF_ERR("Failed to start task for fwbank dump command"); + return -1; + } + + BBF_DEBUG("fwbank dump blob initialized successfully"); + return 0; +} + +static int free_global_fwbank_dump(struct blob_buf *fwbank_dump_bb) +{ + if (fwbank_dump_bb->head && blob_len(fwbank_dump_bb->head)) { + BBF_DEBUG("Freeing fwbank dump blob buffer"); + blob_buf_free(fwbank_dump_bb); + } else { + BBF_DEBUG("fwbank dump blob buffer is already empty"); + } + + return 0; +} + +static void fwbank_listen_timeout(struct uloop_timeout *timeout) +{ + struct fwbank_event_data *data = NULL; + + BBF_DEBUG("fwbank listen timeout triggered"); + + data = container_of(timeout, struct fwbank_event_data, tm); + if (data == NULL) + return; + + ubus_unregister_event_handler(data->ctx, &data->ev); +} + +static void fwbank_receive_sysupgrade(struct ubus_context *ctx, struct ubus_event_handler *ev, + const char *type, struct blob_attr *msg) +{ + struct fwbank_event_data *data = NULL; + struct blob_attr *cur = NULL; + char bank_id_str[16] = {0}; + int rem; + + if (!msg || !ev) { + BBF_ERR("Invalid event data in sysupgrade handler"); + return; + } + + data = container_of(ev, struct fwbank_event_data, ev); + if (data == NULL) + return; + + if (data->band_id < 0) { // bank_id should be a valid id + BBF_ERR("Invalid bank_id: %d", data->band_id); + return; + } + + snprintf(bank_id_str, sizeof(bank_id_str), "%u", data->band_id); + + blobmsg_for_each_attr(cur, msg, rem) { + if (DM_STRCMP("bank_id", blobmsg_name(cur)) == 0) { + char *attr_val = (char *)blobmsg_data(cur); + if (DM_STRCMP(attr_val, bank_id_str) != 0) { + BBF_ERR("Mismatched bank_id (%s != %s)", attr_val, bank_id_str); + return; + } + } + + if (DM_STRCMP("status", blobmsg_name(cur)) == 0) { + char *attr_val = (char *)blobmsg_data(cur); + + if (DM_STRCMP(attr_val, "Downloading") == 0) { + BBF_DEBUG("Sysupgrade status: Downloading"); + return; + } + + if (DM_STRCMP(attr_val, "Available") == 0) { + BBF_DEBUG("Sysupgrade status: Available. Refreshing fwbank dump."); + sysmngr_fwbank_refresh_global_dump(); + break; + } + } + } + + if (data->tm.pending) { + // Cancel timeout if the sysupgrade status available is found + uloop_timeout_cancel(&data->tm); + } + + ubus_unregister_event_handler(data->ctx, &data->ev); + return; +} + +static struct fwbank_event_data g_fwbank_event_data = { + .tm.cb = fwbank_listen_timeout, + .ev.cb = fwbank_receive_sysupgrade, + .timeout = 120 +}; + +static void fwbank_wait_for_sysupgrade_event(struct ubus_context *ctx, uint32_t band_id) +{ + BBF_DEBUG("Waiting for sysupgrade event for bank_id: %u", band_id); + + g_fwbank_event_data.ctx = ctx; + g_fwbank_event_data.band_id = band_id; + + ubus_register_event_handler(ctx, &g_fwbank_event_data.ev, "sysupgrade"); + uloop_timeout_set(&g_fwbank_event_data.tm, g_fwbank_event_data.timeout * 1000); +} + +static bool is_set_bootbank_success(struct blob_buf *output_bb) +{ + struct blob_attr *tb = NULL; + struct blobmsg_policy policy = { + .name = "success", + .type = BLOBMSG_TYPE_BOOL, + }; + + // Parse the blob buffer for the "success" field + if (blobmsg_parse(&policy, 1, &tb, blobmsg_data(output_bb->head), blobmsg_len(output_bb->head)) != 0) { + BBF_ERR("Failed to parse blobmsg data"); + return false; + } + + // Check if the "success" field exists and is of the correct type + if (tb && blobmsg_type(tb) == BLOBMSG_TYPE_BOOL) + return blobmsg_get_bool(tb); + + return false; +} + +static bool is_upgrade_success(struct blob_buf *output_bb) +{ + struct blob_attr *tb = NULL; + struct blobmsg_policy policy = { + .name = "result", + .type = BLOBMSG_TYPE_STRING, + }; + + // Parse the blob buffer for the "result" field + if (blobmsg_parse(&policy, 1, &tb, blobmsg_data(output_bb->head), blobmsg_len(output_bb->head)) != 0) { + BBF_ERR("Failed to parse blobmsg data"); + return false; + } + + // Check if the "result" field exists and is of the correct type + if (tb && blobmsg_type(tb) == BLOBMSG_TYPE_STRING) + return (strcmp(blobmsg_get_string(tb), "ok") == 0) ? true : false; + + return false; +} + +struct blob_buf *sysmngr_fwbank_dump(void) +{ + return &g_fwbank_dump.output; +} + +static void fwbank_set_bootbank_finish_callback(struct ubus_context *ctx, struct ubus_request_data *req, int *pipe_fds, uint32_t bank_id) +{ + BBF_DEBUG("Task finished Line=%d && func=%s", __LINE__, __func__); + + close(pipe_fds[1]); // Close unused write end + + char buffer[1024] = {0}; + ssize_t bytes_read; + + BBF_DEBUG("Reading script output..."); + + // Read the output from the script + while ((bytes_read = read(pipe_fds[0], buffer, sizeof(buffer) - 1)) > 0) { + buffer[bytes_read] = '\0'; // Null-terminate the buffer + BBF_DEBUG("Script output: %s", buffer); + } + + close(pipe_fds[0]); // Close read end + + if (bytes_read < 0) { + BBF_ERR("Failed to read from pipe"); + return; + } + + struct blob_buf setbootbank_bb = {0}; + + memset(&setbootbank_bb, 0, sizeof(struct blob_buf)); + blob_buf_init(&setbootbank_bb, 0); + + if (!blobmsg_add_json_from_string(&setbootbank_bb, buffer)) { + BBF_ERR("Failed to create blob buf"); + blob_buf_free(&setbootbank_bb); + return; + } + + bool is_success = is_set_bootbank_success(&setbootbank_bb); + + if (ctx && req) { + BBF_DEBUG("Send ubus output"); + ubus_send_reply(ctx, req, setbootbank_bb.head); + } + + blob_buf_free(&setbootbank_bb); + + if (is_success) { + // Update fwbank dump output + sysmngr_fwbank_refresh_global_dump(); + } + + return; +} + +int sysmngr_fwbank_set_bootbank(uint32_t bank_id, struct ubus_request_data *req) +{ + char cmd[128] = {0}; + + snprintf(cmd, sizeof(cmd), "echo '{\"bank\":%u}' | %s 2>/dev/null", bank_id, FWBANK_SET_BOOTBANK_CMD); + + int res = sysmngr_task_fork(fwbank_set_bootbank_finish_callback, cmd, 5, req, 0); + if (res) { + BBF_ERR("Failed to start task for fwbank set bootbank command"); + return -1; + } + + return 0; +} + +static void fwbank_upgrade_finish_callback(struct ubus_context *ctx, struct ubus_request_data *req, int *pipe_fds, uint32_t bank_id) +{ + BBF_DEBUG("Task finished Line=%d && func=%s", __LINE__, __func__); + + close(pipe_fds[1]); // Close unused write end + + char buffer[1024] = {0}; + ssize_t bytes_read; + + BBF_DEBUG("Reading script output..."); + + // Read the output from the script + while ((bytes_read = read(pipe_fds[0], buffer, sizeof(buffer) - 1)) > 0) { + buffer[bytes_read] = '\0'; // Null-terminate the buffer + BBF_DEBUG("Script output: %s", buffer); + } + + close(pipe_fds[0]); // Close read end + + if (bytes_read < 0) { + BBF_ERR("Failed to read from pipe"); + return; + } + + struct blob_buf upgrade_bb = {0}; + + memset(&upgrade_bb, 0, sizeof(struct blob_buf)); + blob_buf_init(&upgrade_bb, 0); + + if (!blobmsg_add_json_from_string(&upgrade_bb, buffer)) { + BBF_ERR("Failed to create blob buf"); + blob_buf_free(&upgrade_bb); + return; + } + + bool is_success = is_upgrade_success(&upgrade_bb); + + if (ctx && req) { + BBF_DEBUG("Send ubus output"); + ubus_send_reply(ctx, req, upgrade_bb.head); + } + + blob_buf_free(&upgrade_bb); + + if (ctx && is_success) { + // Update fwbank dump output after getting sysupgrade event with status available + // { "sysupgrade": {"status":"Available","bank_id":"x"} } + fwbank_wait_for_sysupgrade_event(ctx, bank_id); + } + + return; +} + +int sysmngr_fwbank_upgrade(const char *path, bool auto_activate, uint32_t bank_id, bool keep_settings, struct ubus_request_data *req) +{ + char cmd[1024] = {0}; + + snprintf(cmd, sizeof(cmd), "echo '{\"path\":\"%s\", \"auto_activate\":%d, \"bank\":%u, \"keep_settings\":%d}' | %s 2>/dev/null", + path, auto_activate, bank_id, keep_settings, FWBANK_UPGRADE_CMD); + + int res = sysmngr_task_fork(fwbank_upgrade_finish_callback, cmd, 10, req, bank_id); + if (res) { + BBF_ERR("Failed to start task for fwbank upgrade command"); + return -1; + } + + return 0; +} + +void sysmngr_fwbank_refresh_global_dump(void) +{ + BBF_INFO("fwbank refresh global dump blob buf"); + + free_global_fwbank_dump(&g_fwbank_dump.output); + init_global_fwbank_dump(); +} + +static int dump_handler(struct ubus_context *ctx, struct ubus_object *obj, + struct ubus_request_data *req, const char *method, + struct blob_attr *msg) +{ + ubus_send_reply(ctx, req, g_fwbank_dump.output.head); + return 0; +} + +enum { + SET_BOOT_BANK, + __SET_BOOT_MAX +}; + +static const struct blobmsg_policy set_bootbank_policy[] = { + [SET_BOOT_BANK] = { .name = "bank", .type = BLOBMSG_TYPE_INT32 }, +}; + +static int set_bootbank_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[__SET_BOOT_MAX]; + uint32_t band_id = 0; + int res = 0; + + if (blobmsg_parse(set_bootbank_policy, __SET_BOOT_MAX, tb, blob_data(msg), blob_len(msg))) { + BBF_ERR("Failed to parse the 'set_bootbank' message"); + return UBUS_STATUS_UNKNOWN_ERROR; + } + + if (tb[SET_BOOT_BANK]) + band_id = blobmsg_get_u32(tb[SET_BOOT_BANK]); + + res = sysmngr_fwbank_set_bootbank(band_id, req); + + if (res) { + struct blob_buf bb = {0}; + + memset(&bb, 0, sizeof(struct blob_buf)); + blob_buf_init(&bb, 0); + blobmsg_add_u8(&bb, "status", false); + ubus_send_reply(ctx, req, bb.head); + blob_buf_free(&bb); + } + + return 0; +} + +enum { + UPGRADE_PATH, + UPGRADE_AUTO_ACTIVATE, + UPGRADE_BANK, + UPGRADE_KEEP_SETTINGS, + __UPGRADE_MAX +}; + +static const struct blobmsg_policy upgrade_policy[] = { + [UPGRADE_PATH] = { .name = "path", .type = BLOBMSG_TYPE_STRING }, + [UPGRADE_AUTO_ACTIVATE] = { .name = "auto_activate", .type = BLOBMSG_TYPE_BOOL }, + [UPGRADE_BANK] = { .name = "bank", .type = BLOBMSG_TYPE_INT32 }, + [UPGRADE_KEEP_SETTINGS] = { .name = "keep_settings", .type = BLOBMSG_TYPE_BOOL}, +}; + +static int upgrade_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[__UPGRADE_MAX]; + char *fw_path = NULL; + uint32_t bank_id = 0; + bool auto_activate = false; + bool keep_settings = false; + int res = 0; + + if (blobmsg_parse(upgrade_policy, __UPGRADE_MAX, tb, blob_data(msg), blob_len(msg))) { + BBF_ERR("Failed to parse the 'upgrade' message"); + return UBUS_STATUS_UNKNOWN_ERROR; + } + + if (tb[UPGRADE_PATH]) + fw_path = blobmsg_get_string(tb[UPGRADE_PATH]); + + if (tb[UPGRADE_AUTO_ACTIVATE]) + auto_activate = blobmsg_get_bool(tb[UPGRADE_AUTO_ACTIVATE]); + + if (tb[UPGRADE_BANK]) + bank_id = blobmsg_get_u32(tb[UPGRADE_BANK]); + + if (tb[UPGRADE_KEEP_SETTINGS]) + keep_settings = blobmsg_get_bool(tb[UPGRADE_KEEP_SETTINGS]); + + res = sysmngr_fwbank_upgrade(fw_path, auto_activate, bank_id, keep_settings, req); + + if (res) { + struct blob_buf bb = {0}; + + memset(&bb, 0, sizeof(struct blob_buf)); + blob_buf_init(&bb, 0); + blobmsg_add_string(&bb, "result", "failure"); + ubus_send_reply(ctx, req, bb.head); + blob_buf_free(&bb); + } + + return 0; +} + +static struct ubus_method fwbank_methods[] = { + UBUS_METHOD_NOARG("dump", dump_handler), + UBUS_METHOD("set_bootbank", set_bootbank_handler, set_bootbank_policy), + UBUS_METHOD("upgrade", upgrade_handler, upgrade_policy), +}; + +static struct ubus_object_type fwbank_type = UBUS_OBJECT_TYPE("fwbank", fwbank_methods); + +static struct ubus_object fwbank_object = { + .name = "fwbank", + .type = &fwbank_type, + .methods = fwbank_methods, + .n_methods = ARRAY_SIZE(fwbank_methods) +}; + +int sysmngr_register_fwbank(struct ubus_context *ubus_ctx) +{ + int res = ubus_add_object(ubus_ctx, &fwbank_object); + if (res) { + BBF_ERR("Failed to register 'fwbank' ubus object!!!!!!"); + return -1; + } + + BBF_INFO("'fwbank' ubus object was registered"); + return res; +} + +int sysmngr_unregister_fwbank(struct ubus_context *ubus_ctx) +{ + ubus_remove_object(ubus_ctx, &fwbank_object); + + BBF_INFO("'fwbank' ubus object was unregistered, and resources were freed"); + return 0; +} + +int sysmngr_init_fwbank_dump(struct ubus_context *ubus_ctx) +{ + int res = 0; + + g_fwbank_dump.ctx = ubus_ctx; + g_fwbank_dump.tm.cb = fwbank_dump_timer; + + if (!file_exists(FWBANK_FILE_PATH)) { + BBF_ERR("The fwbank file (%s) is missing", FWBANK_FILE_PATH); + return -1; + } + + res = init_global_fwbank_dump(); + if (res) { + BBF_ERR("Failed to fetch 'fwbank' output or no data available"); + return -1; + } + + return 0; +} + +int sysmngr_clean_fwbank_dump(struct ubus_context *ubus_ctx) +{ + free_global_fwbank_dump(&g_fwbank_dump.output); + return 0; +} diff --git a/src/fwbank.h b/src/fwbank.h new file mode 100644 index 0000000000000000000000000000000000000000..c73ce84979a5bc9ead5989d1a2a752bcaab4b8ed --- /dev/null +++ b/src/fwbank.h @@ -0,0 +1,30 @@ +/* + * Copyright (C) 2024 iopsys Software Solutions AB + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 2.1 + * as published by the Free Software Foundation + * + * Author: Amin Ben Romdhane <amin.benromdhane@iopsys.eu> + * + */ + +#ifndef __FWBANK_H +#define __FWBANK_H + +extern struct blobmsg_policy sysmngr_dump_policy[]; +extern struct blobmsg_policy sysmngr_bank_policy[]; + +struct blob_buf *sysmngr_fwbank_dump(void); +int sysmngr_fwbank_set_bootbank(uint32_t bank_id, struct ubus_request_data *req); +int sysmngr_fwbank_upgrade(const char *path, bool auto_activate, uint32_t bank_id, bool keep_settings, struct ubus_request_data *req); + +void sysmngr_fwbank_refresh_global_dump(void); + +int sysmngr_register_fwbank(struct ubus_context *ubus_ctx); +int sysmngr_unregister_fwbank(struct ubus_context *ubus_ctx); + +int sysmngr_init_fwbank_dump(struct ubus_context *ubus_ctx); +int sysmngr_clean_fwbank_dump(struct ubus_context *ubus_ctx); + +#endif //__FWBANK_H diff --git a/src/sysmngr.c b/src/sysmngr.c index 249e86c4529d352df3336bc067f75efbc595561c..5541cb03ab5357b82715c42db752dff13aafb054 100644 --- a/src/sysmngr.c +++ b/src/sysmngr.c @@ -28,6 +28,10 @@ #include "memory.h" #endif +#if defined(SYSMNGR_FWBANK_UBUS_SUPPORT) || defined(SYSMNGR_FIRMWARE_IMAGE) +#include "fwbank.h" +#endif + #define DEFAULT_LOG_LEVEL LOG_INFO extern DM_MAP_OBJ tDynamicObj[]; @@ -97,6 +101,10 @@ int main(int argc, char **argv) sysmngr_reboots_init(); #endif +#if defined(SYSMNGR_FWBANK_UBUS_SUPPORT) || defined(SYSMNGR_FIRMWARE_IMAGE) + sysmngr_init_fwbank_dump(&bbfdm_ctx.ubus_ctx); +#endif + #ifdef SYSMNGR_PROCESS_STATUS sysmngr_process_init(&bbfdm_ctx.ubus_ctx); sysmngr_cpu_init(); @@ -109,6 +117,11 @@ int main(int argc, char **argv) if (bbfdm_ubus_regiter_init(&bbfdm_ctx)) goto out; +#ifdef SYSMNGR_FWBANK_UBUS_SUPPORT + if (sysmngr_register_fwbank(&bbfdm_ctx.ubus_ctx)) + goto out; +#endif + if (ubus_register_event_handler(&bbfdm_ctx.ubus_ctx, &ev, "sysmngr.reload")) goto out; @@ -126,6 +139,14 @@ out: sysmngr_memory_clean(); #endif +#ifdef SYSMNGR_FWBANK_UBUS_SUPPORT + sysmngr_unregister_fwbank(&bbfdm_ctx.ubus_ctx); +#endif + +#if defined(SYSMNGR_FWBANK_UBUS_SUPPORT) || defined(SYSMNGR_MEMORY_STATUS) + sysmngr_clean_fwbank_dump(&bbfdm_ctx.ubus_ctx); +#endif + closelog(); return 0;