diff --git a/libbbfdm-api/legacy/dmapi.h b/libbbfdm-api/legacy/dmapi.h index de0cac01..860ae5f5 100644 --- a/libbbfdm-api/legacy/dmapi.h +++ b/libbbfdm-api/legacy/dmapi.h @@ -207,6 +207,7 @@ struct dmctx { struct ubus_context *ubus_ctx; struct list_head *memhead; + char *obj_buf[16]; char *inst_buf[16]; char fault_msg[256]; }; @@ -215,6 +216,7 @@ typedef struct dmnode { DMOBJ *obj; struct dmnode *parent; char *current_object; + char *current_object_file; void *prev_data; char *prev_instance; unsigned char instance_level; diff --git a/libbbfdm-api/legacy/dmbbf.c b/libbbfdm-api/legacy/dmbbf.c index 35875250..9e8be483 100644 --- a/libbbfdm-api/legacy/dmbbf.c +++ b/libbbfdm-api/legacy/dmbbf.c @@ -431,6 +431,7 @@ static void dm_browse_entry(struct dmctx *dmctx, DMNODE *parent_node, DMOBJ *ent node.matched = parent_node->matched; node.prev_data = data; node.prev_instance = instance; + node.current_object_file = parent_node->current_object_file; if (!bbfdatamodel_matches(dmctx->dm_type, entryobj->bbfdm_type)) { *err = FAULT_9005; @@ -447,6 +448,16 @@ static void dm_browse_entry(struct dmctx *dmctx, DMNODE *parent_node, DMOBJ *ent else 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) { *err = dmctx->checkobj(dmctx, &node, entryobj->permission, entryobj->addobj, entryobj->delobj, entryobj->get_linker, data, instance); 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.is_instanceobj = 1; node.matched = parent_node->matched; + node.current_object_file = parent_node->current_object_file; parent_obj = parent_node->current_object; if (instance == NULL) @@ -637,6 +649,87 @@ char *handle_instance(struct dmctx *dmctx, DMNODE *parent_node, struct uci_secti 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 *instance = NULL; @@ -655,6 +748,30 @@ char *handle_instance_without_section(struct dmctx *dmctx, DMNODE *parent_node, 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) { *value = dmstrdup(""); @@ -916,6 +1033,10 @@ static int get_value_param(DMPARAM_ARGS) 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); return 0; } @@ -1350,7 +1471,6 @@ static int mobj_add_object(DMOBJECT_ARGS) { char *refparam = node->current_object; char *perm = permission->val; - char *new_instance = NULL; int fault = 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) 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; + char *new_instance = find_instance(dmctx, node, NULL); + fault = (addobj)(refparam, dmctx, data, &new_instance); if (fault) return fault; diff --git a/libbbfdm-api/legacy/dmbbf.h b/libbbfdm-api/legacy/dmbbf.h index 1f1e3824..d30a8f79 100644 --- a/libbbfdm-api/legacy/dmbbf.h +++ b/libbbfdm-api/legacy/dmbbf.h @@ -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)); 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); +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); void fill_blob_param(struct blob_buf *bb, const char *path, const char *data, const char *type, uint32_t dm_flags); diff --git a/libbbfdm/schedules.c b/libbbfdm/schedules.c index 933f2f3c..008262ad 100644 --- a/libbbfdm/schedules.c +++ b/libbbfdm/schedules.c @@ -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) { - struct uci_section *s = NULL, *dmmap_s = NULL; - char s_name[16] = {0}; - int i; + struct dm_data curr_data = {0}; + char sec_name[16] = {0}; - snprintf(s_name, sizeof(s_name), "schedule_%s", *instance); + snprintf(sec_name, sizeof(sec_name), "schedule_%s", *instance); - dmuci_add_section("schedules", "schedule", &s); - dmuci_rename_section_by_section(s, s_name); + uci_handle_add(ctx, refparam, *instance, &curr_data, "schedules", "schedule", sec_name); - dmuci_set_value_by_section(s, "enable", "0"); - - for (i = 0; allowed_days[i] != NULL; i++) { - dmuci_add_list_value_by_section(s, "day", allowed_days[i]); - } + // 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"); - 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; } @@ -170,24 +166,65 @@ static int delSchedule(char *refparam, struct dmctx *ctx, void *data, char *inst 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 *************************************************************/ 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; - LIST_HEAD(dup_list); - synchronize_specific_config_sections_with_dmmap("schedules", "schedule", "dmmap_schedules", &dup_list); - list_for_each_entry(p, &dup_list, list) { - - 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) + uci_foreach_sections("schedules", "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; } - 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; } @@ -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) { - 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) @@ -281,8 +318,8 @@ static int set_schedule_alias(char *refparam, struct dmctx *ctx, void *data, cha 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, "schedule_alias", 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; } @@ -426,13 +463,97 @@ static int get_schedule_status(char *refparam, struct dmctx *ctx, void *data, ch 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 ***********************************************************************************************************************************/ +/* *** 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. *** */ DMOBJ tSchedulesObj[] = { /* 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} }; @@ -452,5 +573,6 @@ DMLEAF tScheduleParams[] = { {"Day", &DMWRITE, DMT_STRING, get_schedule_day, set_schedule_day, 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}, +{"TestNumberOfEntries", &DMREAD, DMT_UNINT, get_schedule_test_number, NULL, BBFDM_BOTH}, {0} }; diff --git a/libbbfdm/schedules.h b/libbbfdm/schedules.h index fb429137..4781d977 100644 --- a/libbbfdm/schedules.h +++ b/libbbfdm/schedules.h @@ -16,5 +16,7 @@ extern DMOBJ tSchedulesObj[]; extern DMLEAF tSchedulesParams[]; extern DMLEAF tScheduleParams[]; + +extern DMLEAF tScheduleTestParams[]; #endif