Redesign dmmap to be portable and structured

This commit is contained in:
Amin Ben Romdhane 2025-07-25 23:34:41 +02:00
parent a4f6108138
commit d3ef967693
5 changed files with 282 additions and 34 deletions

View file

@ -207,6 +207,7 @@ struct dmctx {
struct ubus_context *ubus_ctx; struct ubus_context *ubus_ctx;
struct list_head *memhead; struct list_head *memhead;
char *obj_buf[16];
char *inst_buf[16]; char *inst_buf[16];
char fault_msg[256]; char fault_msg[256];
}; };
@ -215,6 +216,7 @@ typedef struct dmnode {
DMOBJ *obj; DMOBJ *obj;
struct dmnode *parent; struct dmnode *parent;
char *current_object; char *current_object;
char *current_object_file;
void *prev_data; void *prev_data;
char *prev_instance; char *prev_instance;
unsigned char instance_level; unsigned char instance_level;

View file

@ -431,6 +431,7 @@ static void dm_browse_entry(struct dmctx *dmctx, DMNODE *parent_node, DMOBJ *ent
node.matched = parent_node->matched; node.matched = parent_node->matched;
node.prev_data = data; node.prev_data = data;
node.prev_instance = instance; node.prev_instance = instance;
node.current_object_file = parent_node->current_object_file;
if (!bbfdatamodel_matches(dmctx->dm_type, entryobj->bbfdm_type)) { if (!bbfdatamodel_matches(dmctx->dm_type, entryobj->bbfdm_type)) {
*err = FAULT_9005; *err = FAULT_9005;
@ -447,6 +448,16 @@ static void dm_browse_entry(struct dmctx *dmctx, DMNODE *parent_node, DMOBJ *ent
else else
dmasprintf(&(node.current_object), "%s%s.", parent_obj, entryobj->obj); dmasprintf(&(node.current_object), "%s%s.", parent_obj, entryobj->obj);
if (DM_STRCMP(parent_obj, ROOT_NODE) == 0) {
char fname[128];
snprintf(fname, sizeof(fname), "/etc/bbfdm/dmmap/%s", entryobj->obj);
create_empty_file(fname);
node.current_object_file = entryobj->obj;
}
if (dmctx->checkobj) { if (dmctx->checkobj) {
*err = dmctx->checkobj(dmctx, &node, entryobj->permission, entryobj->addobj, entryobj->delobj, entryobj->get_linker, data, instance); *err = dmctx->checkobj(dmctx, &node, entryobj->permission, entryobj->addobj, entryobj->delobj, entryobj->get_linker, data, instance);
if (*err) if (*err)
@ -546,6 +557,7 @@ int dm_link_inst_obj(struct dmctx *dmctx, DMNODE *parent_node, void *data, char
node.instance_level = parent_node->instance_level + 1; node.instance_level = parent_node->instance_level + 1;
node.is_instanceobj = 1; node.is_instanceobj = 1;
node.matched = parent_node->matched; node.matched = parent_node->matched;
node.current_object_file = parent_node->current_object_file;
parent_obj = parent_node->current_object; parent_obj = parent_node->current_object;
if (instance == NULL) if (instance == NULL)
@ -637,6 +649,87 @@ char *handle_instance(struct dmctx *dmctx, DMNODE *parent_node, struct uci_secti
return instance ? instance : ""; return instance ? instance : "";
} }
static char *find_instance(struct dmctx *dmctx, DMNODE *parent_node, struct dm_data *data)
{
const char *config_name = parent_node->current_object_file;
const char *sec_name = parent_node->obj->obj;
const char *sec_name_value = data ? section_name(data->config_section) : "";
struct uci_section *s = NULL;
char *instance = NULL;
int max_instance = 0;
if (data) data->dmmap_section = NULL;
uci_path_foreach_sections(bbfdm, config_name, sec_name, s) {
bool is_same_parent = true;
for (int i = 0; i < parent_node->instance_level; i++) {
char *curr_obj_inst = NULL;
dmuci_get_value_by_section_string(s, dmctx->obj_buf[i], &curr_obj_inst);
if (DM_STRCMP(curr_obj_inst, dmctx->inst_buf[i]) != 0) {
is_same_parent = false;
break;
}
}
if (is_same_parent == false)
continue;
char *curr_instance = NULL;
dmuci_get_value_by_section_string(s, "__instance__", &curr_instance);
int curr_instance_int = (curr_instance && *curr_instance != '\0') ? DM_STRTOL(curr_instance) : 0;
if (curr_instance_int > max_instance)
max_instance = curr_instance_int;
if (data != NULL) {
char *curr_sec_name = NULL;
dmuci_get_value_by_section_string(s, "__section_name__", &curr_sec_name);
if (DM_STRCMP(curr_sec_name, sec_name_value) == 0) {
data->dmmap_section = s;
if (curr_instance && *curr_instance != '\0')
return curr_instance;
}
}
}
dmasprintf(&instance, "%d", max_instance + 1);
if (data != NULL) {
if (data->dmmap_section == NULL) {
// Section not found -> create it
dmuci_add_section_bbfdm(config_name, sec_name, &data->dmmap_section);
for (int i = 0; i < parent_node->instance_level; i++) {
dmuci_set_value_by_section(data->dmmap_section, dmctx->obj_buf[i], dmctx->inst_buf[i]);
}
dmuci_set_value_by_section(data->dmmap_section, "__section_name__", sec_name_value);
}
dmuci_set_value_by_section(data->dmmap_section, "__instance__", instance);
}
return instance ? instance : "";
}
char *uci_handle_instance(struct dmctx *dmctx, DMNODE *parent_node, struct dm_data *data)
{
char *instance = NULL;
switch(parent_node->browse_type) {
case BROWSE_NORMAL:
instance = find_instance(dmctx, parent_node, data);
dmctx->obj_buf[parent_node->instance_level] = parent_node->obj->obj;
dmctx->inst_buf[parent_node->instance_level] = instance ? instance : "";
break;
case BROWSE_FIND_MAX_INST:
case BROWSE_NUM_OF_ENTRIES:
break;
}
return instance ? instance : "";
}
char *handle_instance_without_section(struct dmctx *dmctx, DMNODE *parent_node, int inst_nbr) char *handle_instance_without_section(struct dmctx *dmctx, DMNODE *parent_node, int inst_nbr)
{ {
char *instance = NULL; char *instance = NULL;
@ -655,6 +748,30 @@ char *handle_instance_without_section(struct dmctx *dmctx, DMNODE *parent_node,
return instance ? instance : ""; return instance ? instance : "";
} }
int uci_handle_add(struct dmctx *dmctx, const char *refparam, const char *instance, struct dm_data *data,
const char *config_name, const char *sec_name, const char *sec_name_value)
{
size_t count = 0;
char **parts = strsplit(refparam, ".", &count);
if (count < 2 || parts == NULL)
return -1;
if (config_name != NULL && sec_name != NULL && sec_name_value != NULL) {
dmuci_add_section(config_name, sec_name, &data->config_section);
dmuci_rename_section_by_section(data->config_section, sec_name_value);
}
dmuci_add_section_bbfdm(parts[1], parts[count - 1], &data->dmmap_section);
dmuci_rename_section_by_section(data->dmmap_section, sec_name_value);
dmuci_set_value_by_section(data->dmmap_section, "__section_name__", sec_name_value ? sec_name_value : section_name(data->dmmap_section));
dmuci_set_value_by_section(data->dmmap_section, "__instance__", instance ? instance : "");
return 0;
}
int get_empty(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) int get_empty(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
{ {
*value = dmstrdup(""); *value = dmstrdup("");
@ -916,6 +1033,10 @@ static int get_value_param(DMPARAM_ARGS)
value = get_default_value_by_type(full_param, leaf->type); value = get_default_value_by_type(full_param, leaf->type);
} }
if ((leaf->dm_flags & DM_FLAG_LINKER) || (leaf->dm_flags & DM_FLAG_REFERENCE)) {
if (data) dmuci_set_value_by_section(((struct dm_data *)data)->dmmap_section, leaf->parameter, value);
}
fill_blob_param(&dmctx->bb, full_param, value, DMT_TYPE[leaf->type], leaf->dm_flags); fill_blob_param(&dmctx->bb, full_param, value, DMT_TYPE[leaf->type], leaf->dm_flags);
return 0; return 0;
} }
@ -1350,7 +1471,6 @@ static int mobj_add_object(DMOBJECT_ARGS)
{ {
char *refparam = node->current_object; char *refparam = node->current_object;
char *perm = permission->val; char *perm = permission->val;
char *new_instance = NULL;
int fault = 0; int fault = 0;
if (DM_STRCMP(refparam, dmctx->in_param) != 0) if (DM_STRCMP(refparam, dmctx->in_param) != 0)
@ -1365,13 +1485,11 @@ static int mobj_add_object(DMOBJECT_ARGS)
if (perm[0] == '0' || addobj == NULL) if (perm[0] == '0' || addobj == NULL)
return FAULT_9005; return FAULT_9005;
int max_inst = find_max_instance(dmctx, node);
fault = dmasprintf(&new_instance, "%d", max_inst);
if (fault)
return fault;
dmctx->stop = 1; dmctx->stop = 1;
char *new_instance = find_instance(dmctx, node, NULL);
fault = (addobj)(refparam, dmctx, data, &new_instance); fault = (addobj)(refparam, dmctx, data, &new_instance);
if (fault) if (fault)
return fault; return fault;

View file

@ -29,7 +29,11 @@
int get_number_of_entries(struct dmctx *ctx, void *data, char *instance, int (*browseinstobj)(struct dmctx *ctx, struct dmnode *node, void *data, char *instance)); 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, const char *inst_opt, const char *alias_opt); char *handle_instance(struct dmctx *dmctx, DMNODE *parent_node, struct uci_section *s, const char *inst_opt, const char *alias_opt);
char *uci_handle_instance(struct dmctx *dmctx, DMNODE *parent_node, struct dm_data *data);
char *handle_instance_without_section(struct dmctx *dmctx, DMNODE *parent_node, int inst_nbr); char *handle_instance_without_section(struct dmctx *dmctx, DMNODE *parent_node, int inst_nbr);
int uci_handle_add(struct dmctx *dmctx, const char *refparam, const char *instance, struct dm_data *data,
const char *config_name, const char *sec_name, const char *sec_name_value);
int get_empty(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value); int get_empty(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value);
void fill_blob_param(struct blob_buf *bb, const char *path, const char *data, const char *type, uint32_t dm_flags); void fill_blob_param(struct blob_buf *bb, const char *path, const char *data, const char *type, uint32_t dm_flags);

View file

@ -138,27 +138,23 @@ static char *get_status(char *start, char *period, char *day)
**************************************************************/ **************************************************************/
static int addSchedule(char *refparam, struct dmctx *ctx, void *data, char **instance) static int addSchedule(char *refparam, struct dmctx *ctx, void *data, char **instance)
{ {
struct uci_section *s = NULL, *dmmap_s = NULL; struct dm_data curr_data = {0};
char s_name[16] = {0}; char sec_name[16] = {0};
int i;
snprintf(s_name, sizeof(s_name), "schedule_%s", *instance); snprintf(sec_name, sizeof(sec_name), "schedule_%s", *instance);
dmuci_add_section("schedules", "schedule", &s); uci_handle_add(ctx, refparam, *instance, &curr_data, "schedules", "schedule", sec_name);
dmuci_rename_section_by_section(s, s_name);
dmuci_set_value_by_section(s, "enable", "0"); // Default config option
dmuci_set_value_by_section(curr_data.config_section, "enable", "0");
for (i = 0; allowed_days[i] != NULL; i++) { dmuci_set_value_by_section(curr_data.config_section, "duration", "1");
dmuci_add_list_value_by_section(s, "day", allowed_days[i]);
}
dmuci_set_value_by_section(s, "duration", "1"); for (int i = 0; allowed_days[i] != NULL; i++)
dmuci_add_list_value_by_section(curr_data.config_section, "day", allowed_days[i]);
// Default dmmap option
dmuci_set_value_by_section(curr_data.dmmap_section, "Alias", sec_name);
dmuci_add_section_bbfdm("dmmap_schedules", "schedule", &dmmap_s);
dmuci_set_value_by_section(dmmap_s, "section_name", s_name);
dmuci_set_value_by_section(dmmap_s, "schedule_instance", *instance);
dmuci_set_value_by_section(dmmap_s, "schedule_alias", s_name);
return 0; return 0;
} }
@ -170,24 +166,65 @@ static int delSchedule(char *refparam, struct dmctx *ctx, void *data, char *inst
return 0; return 0;
} }
static int addScheduleTest(char *refparam, struct dmctx *ctx, void *data, char **instance)
{
struct dm_data curr_data = {0};
char sec_name[16] = {0};
snprintf(sec_name, sizeof(sec_name), "Schedule_%s", *instance);
uci_handle_add(ctx, refparam, *instance, &curr_data, "schedules", "schedule", sec_name);
// Default config option
dmuci_set_value_by_section(curr_data.config_section, "enable", "0");
dmuci_set_value_by_section(curr_data.config_section, "duration", "1");
for (int i = 0; allowed_days[i] != NULL; i++)
dmuci_add_list_value_by_section(curr_data.config_section, "day", allowed_days[i]);
// Default dmmap option
dmuci_set_value_by_section(curr_data.dmmap_section, "Alias", sec_name);
return 0;
}
static int delScheduleTest(char *refparam, struct dmctx *ctx, void *data, char *instance, unsigned char del_action)
{
dmuci_delete_by_section(((struct dm_data *)data)->config_section, NULL, NULL);
dmuci_delete_by_section(((struct dm_data *)data)->dmmap_section, NULL, NULL);
return 0;
}
/************************************************************* /*************************************************************
* ENTRY METHODS * ENTRY METHODS
*************************************************************/ *************************************************************/
static int browseScheduleInstance(struct dmctx *dmctx, DMNODE *parent_node, void *prev_data, char *prev_instance) static int browseScheduleInstance(struct dmctx *dmctx, DMNODE *parent_node, void *prev_data, char *prev_instance)
{ {
struct dm_data *p = NULL; struct dm_data curr_data = {0};
char *inst = NULL; char *inst = NULL;
LIST_HEAD(dup_list);
synchronize_specific_config_sections_with_dmmap("schedules", "schedule", "dmmap_schedules", &dup_list); uci_foreach_sections("schedules", "schedule", curr_data.config_section) {
list_for_each_entry(p, &dup_list, list) { inst = uci_handle_instance(dmctx, parent_node, &curr_data);
if (DM_LINK_INST_OBJ(dmctx, parent_node, (void *)&curr_data, inst) == DM_STOP)
inst = handle_instance(dmctx, parent_node, p->dmmap_section, "schedule_instance", "schedule_alias");
if (DM_LINK_INST_OBJ(dmctx, parent_node, (void *)p, inst) == DM_STOP)
break; break;
} }
free_dmmap_config_dup_list(&dup_list);
return 0;
}
static int browseScheduleTestInstance(struct dmctx *dmctx, DMNODE *parent_node, void *prev_data, char *prev_instance)
{
struct dm_data curr_data = {0};
char *prev_schedule = section_name(((struct dm_data *)prev_data)->config_section);
char *inst = NULL;
uci_foreach_option_eq("schedules", "test", "schedule", prev_schedule, curr_data.config_section) {
inst = uci_handle_instance(dmctx, parent_node, &curr_data);
if (DM_LINK_INST_OBJ(dmctx, parent_node, (void *)&curr_data, inst) == DM_STOP)
break;
}
return 0; return 0;
} }
@ -253,7 +290,7 @@ static int set_schedule_enable(char *refparam, struct dmctx *ctx, void *data, ch
static int get_schedule_alias(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) static int get_schedule_alias(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
{ {
return bbf_get_alias(ctx, ((struct dm_data *)data)->dmmap_section, "schedule_alias", instance, value); return bbf_get_alias(ctx, ((struct dm_data *)data)->dmmap_section, "Alias", instance, value);
} }
static int set_schedule_alias(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action) static int set_schedule_alias(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action)
@ -281,8 +318,8 @@ static int set_schedule_alias(char *refparam, struct dmctx *ctx, void *data, cha
break; break;
case VALUESET: case VALUESET:
dmuci_rename_section_by_section(((struct dm_data *)data)->config_section, value); dmuci_rename_section_by_section(((struct dm_data *)data)->config_section, value);
dmuci_set_value_by_section(((struct dm_data *)data)->dmmap_section, "section_name", value); dmuci_set_value_by_section(((struct dm_data *)data)->dmmap_section, "__section_name__", value);
dmuci_set_value_by_section(((struct dm_data *)data)->dmmap_section, "schedule_alias", value); dmuci_set_value_by_section(((struct dm_data *)data)->dmmap_section, "Alias", value);
break; break;
} }
@ -426,13 +463,97 @@ static int get_schedule_status(char *refparam, struct dmctx *ctx, void *data, ch
return 0; return 0;
} }
static int get_schedule_test_number(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
{
unsigned int cnt = get_number_of_entries(ctx, data, instance, browseScheduleTestInstance);
dmasprintf(value, "%u", cnt);
return 0;
}
static int get_schedule_test_enable(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
{
*value = dmuci_get_value_by_section_fallback_def(((struct dm_data *)data)->config_section, "enable", "0");
return 0;
}
static int set_schedule_test_enable(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action)
{
bool b;
int ret = 0;
switch (action) {
case VALUECHECK:
if (bbfdm_validate_boolean(ctx, value))
ret = FAULT_9007;
break;
case VALUESET:
string_to_bool(value, &b);
dmuci_set_value_by_section(((struct dm_data *)data)->config_section, "enable", b ? "1" : "0");
break;
}
return ret;
}
static int get_schedule_test_alias(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
{
return bbf_get_alias(ctx, ((struct dm_data *)data)->dmmap_section, "Alias", instance, value);
}
static int set_schedule_test_alias(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action)
{
int ret = 0;
switch (action) {
case VALUECHECK:
if (bbfdm_validate_string(ctx, value, -1, 64, NULL, NULL)) {
ret = FAULT_9007;
break;
}
/* alias is mapped with the section name because this value is used by external packages
* to refer to schedule configuration. As alias is mapped with section name so we can't
* accept empty value and as well as special characters in the alias.
* Encoded section name is also not used because that will keep the section name encoded
* but the linker value will return decoded string value thus external package will fail
* to refer to correct section */
if ((DM_STRLEN(value) == 0) || special_char_exits(value)) {
bbfdm_set_fault_message(ctx, "Empty value and character other than A-Z,a-z,0-9 and _ are not allowed");
ret = FAULT_9007;
}
break;
case VALUESET:
dmuci_rename_section_by_section(((struct dm_data *)data)->config_section, value);
dmuci_set_value_by_section(((struct dm_data *)data)->dmmap_section, "__section_name__", value);
dmuci_set_value_by_section(((struct dm_data *)data)->dmmap_section, "Alias", value);
break;
}
return ret;
}
/********************************************************************************************************************************** /**********************************************************************************************************************************
* OBJ & PARAM DEFINITION * OBJ & PARAM DEFINITION
***********************************************************************************************************************************/ ***********************************************************************************************************************************/
/* *** Device.Schedules.{i}.Test. *** */
DMOBJ tScheduleObj[] = {
/* OBJ, permission, addobj, delobj, checkdep, browseinstobj, nextdynamicobj, dynamicleaf, nextobj, leaf, linker, bbfdm_type, uniqueKeys, version*/
{"Test", &DMWRITE, addScheduleTest, delScheduleTest, NULL, browseScheduleTestInstance, NULL, NULL, NULL, tScheduleTestParams, NULL, BBFDM_BOTH, NULL},
{0}
};
DMLEAF tScheduleTestParams[] = {
/* PARAM, permission, type, getvalue, setvalue, bbfdm_type, version*/
{"Alias", &DMWRITE, DMT_STRING, get_schedule_test_alias, set_schedule_test_alias, BBFDM_BOTH, DM_FLAG_UNIQUE|DM_FLAG_LINKER},
{"Enable", &DMWRITE, DMT_BOOL, get_schedule_test_enable, set_schedule_test_enable, BBFDM_BOTH},
{0}
};
/* *** Device.Schedules. *** */ /* *** Device.Schedules. *** */
DMOBJ tSchedulesObj[] = { DMOBJ tSchedulesObj[] = {
/* OBJ, permission, addobj, delobj, checkdep, browseinstobj, nextdynamicobj, dynamicleaf, nextobj, leaf, linker, bbfdm_type, uniqueKeys, version*/ /* OBJ, permission, addobj, delobj, checkdep, browseinstobj, nextdynamicobj, dynamicleaf, nextobj, leaf, linker, bbfdm_type, uniqueKeys, version*/
{"Schedule", &DMWRITE, addSchedule, delSchedule, NULL, browseScheduleInstance, NULL, NULL, NULL, tScheduleParams, NULL, BBFDM_BOTH, NULL}, {"Schedule", &DMWRITE, addSchedule, delSchedule, NULL, browseScheduleInstance, NULL, NULL, tScheduleObj, tScheduleParams, NULL, BBFDM_BOTH, NULL},
{0} {0}
}; };
@ -452,5 +573,6 @@ DMLEAF tScheduleParams[] = {
{"Day", &DMWRITE, DMT_STRING, get_schedule_day, set_schedule_day, BBFDM_BOTH}, {"Day", &DMWRITE, DMT_STRING, get_schedule_day, set_schedule_day, BBFDM_BOTH},
{"StartTime", &DMWRITE, DMT_STRING, get_schedule_start, set_schedule_start, BBFDM_BOTH}, {"StartTime", &DMWRITE, DMT_STRING, get_schedule_start, set_schedule_start, BBFDM_BOTH},
{"Duration", &DMWRITE, DMT_UNINT, get_schedule_duration, set_schedule_duration, BBFDM_BOTH}, {"Duration", &DMWRITE, DMT_UNINT, get_schedule_duration, set_schedule_duration, BBFDM_BOTH},
{"TestNumberOfEntries", &DMREAD, DMT_UNINT, get_schedule_test_number, NULL, BBFDM_BOTH},
{0} {0}
}; };

View file

@ -16,5 +16,7 @@
extern DMOBJ tSchedulesObj[]; extern DMOBJ tSchedulesObj[];
extern DMLEAF tSchedulesParams[]; extern DMLEAF tSchedulesParams[];
extern DMLEAF tScheduleParams[]; extern DMLEAF tScheduleParams[];
extern DMLEAF tScheduleTestParams[];
#endif #endif