From 154c6051820a94e191880de5856d91ee76f0059d Mon Sep 17 00:00:00 2001 From: suvendhu <suvendhu.hansa@iopsys.eu> Date: Thu, 7 Sep 2023 11:10:56 +0530 Subject: [PATCH] swmodules datamodel vers 2.16 support --- src/Makefile | 6 +- src/datamodel.c | 1014 +++++++++++++++---------------- src/datamodel.h | 4 +- src/opkg_utils.c | 78 --- src/opkg_utils.h | 20 - src/swmod.c | 1078 +++------------------------------ src/swmod.h | 94 +-- src/swmod_api.c | 530 ++++------------- src/swmod_api.h | 22 +- src/swmod_common.h | 19 +- src/swmod_crun.c | 741 +---------------------- src/swmod_crun.h | 8 +- src/swmod_host.c | 67 --- src/swmod_host.h | 19 - src/swmod_lxc.c | 794 +------------------------ src/swmod_lxc.h | 15 +- src/swmod_opkg.c | 145 ----- src/swmod_opkg.h | 18 - src/swmod_uci.c | 10 +- src/swmod_uci.h | 2 +- src/tools.c | 1421 +++++++++++++++++++++++++------------------- src/tools.h | 89 +-- 22 files changed, 1558 insertions(+), 4636 deletions(-) delete mode 100644 src/opkg_utils.c delete mode 100644 src/opkg_utils.h delete mode 100644 src/swmod_host.c delete mode 100644 src/swmod_host.h delete mode 100644 src/swmod_opkg.c delete mode 100644 src/swmod_opkg.h diff --git a/src/Makefile b/src/Makefile index ad5e925..2d8ae15 100644 --- a/src/Makefile +++ b/src/Makefile @@ -5,7 +5,7 @@ endif PROG = swmodd LIB = libswmodd.so -OBJS = swmod.o swmod_host.o swmod_opkg.o swmod_uci.o tools.o opkg_utils.o swmod_api.o +OBJS = swmod.o swmod_uci.o tools.o swmod_api.o LIB_OBJS = datamodel.o PROG_CFLAGS = $(CFLAGS) -fstrict-aliasing -Wall -Werror -fPIC @@ -22,6 +22,10 @@ OBJS += swmod_crun.o PROG_CFLAGS += -DSWMOD_CRUN endif +ifdef SWMOD_VERS +PROG_CFLAGS += -DSWMOD_VERSION=\"$(SWMOD_VERS)\" +endif + %.o: %.c $(CC) $(PROG_CFLAGS) $(FPIC) -c -o $@ $< diff --git a/src/datamodel.c b/src/datamodel.c index be99ac0..67d14ed 100644 --- a/src/datamodel.c +++ b/src/datamodel.c @@ -17,477 +17,490 @@ DM_MAP_OBJ tDynamicObj[] = { {0} }; +struct ee_class { + char name[256]; + char vendor[128]; + char version[32]; + struct uci_section *dmmap_sec; + struct list_head *cap_head; +}; + +struct capability { + struct list_head list; + char spec[256]; + char spec_ver[32]; + char uri[256]; +}; + +static void free_capability_list(struct list_head *cap_list) +{ + struct capability *cap = NULL, *tmp = NULL; + list_for_each_entry_safe(cap, tmp, cap_list, list) { + list_del(&cap->list); + dmfree(cap); + } +} + +static bool valid_execenv_name(const char *name) +{ + /* check if already exist or is a child exec env */ + struct uci_section *s = NULL, *stmp = NULL; + + uci_foreach_sections_safe("swmodd", "execenv", stmp, s) { + char *env_name = NULL; + int len; + + dmuci_get_value_by_section_string(s, "name", &env_name); + len = DM_STRLEN(env_name); + + if (DM_STRNCMP(env_name, name, len) == 0) + return false; + + len = DM_STRLEN(name); + if (DM_STRNCMP(name, env_name, len) == 0) + return false; + } + + return true; +} + /************************************************************* * ENTRY METHOD *************************************************************/ -static int browseSoftwareModulesExecEnvInst(struct dmctx *dmctx, DMNODE *parent_node, void *prev_data, char *prev_instance) +static int browseSoftwareModulesExecEnvClass(struct dmctx *dmctx, DMNODE *parent_node, void *prev_data, char *prev_instance) { - json_object *res = NULL, *du_obj = NULL, *arrobj = NULL; - char *inst = NULL; - int env = 0; - - dmubus_call("swmodules", "ee_list", UBUS_ARGS{0}, 0, &res); - dmjson_foreach_obj_in_array(res, arrobj, du_obj, env, 1, "environment") { - inst = dmjson_get_value(du_obj, 1, "eeid"); - if (inst) { - if (DM_LINK_INST_OBJ(dmctx, parent_node, (void *)du_obj, inst) == DM_STOP) - break; - } + json_object *res = NULL, *cap_obj = NULL, *arrobj = NULL; + struct ee_class *class = NULL; + int inst = 0; + LIST_HEAD(cap_list); + + class = dmcalloc(1, sizeof(struct ee_class)); + if (!class) + return 0; + + memset(class, 0, sizeof(struct ee_class)); + + dmubus_call("swmodules", "ee_class", UBUS_ARGS{0}, 0, &res); + if (!res) + return 0; + + snprintf(class->name, sizeof(class->name), "%s", dmjson_get_value(res, 1, "name")); + snprintf(class->vendor, sizeof(class->vendor), "%s", dmjson_get_value(res, 1, "vendor")); + snprintf(class->version, sizeof(class->version), "%s", dmjson_get_value(res, 1, "version")); + + dmjson_foreach_obj_in_array(res, arrobj, cap_obj, inst, 1, "capabilities") { + struct capability *cap = dmcalloc(1, sizeof(struct capability)); + if (!cap) + break; + + snprintf(cap->spec, sizeof(cap->spec), "%s", dmjson_get_value(cap_obj, 1, "specification")); + snprintf(cap->spec_ver, sizeof(cap->spec_ver), "%s", dmjson_get_value(cap_obj, 1, "version")); + snprintf(cap->uri, sizeof(cap->uri), "%s", dmjson_get_value(cap_obj, 1, "uri")); + + list_add_tail(&cap->list, &cap_list); + } + + class->cap_head = &cap_list; + + struct uci_section *sec = is_dmmap_section_exist("dmmap_swmodd", "execenvclass"); + if (!sec) { + dmuci_add_section_bbfdm("dmmap_swmodd", "execenvclass", &sec); + dmuci_set_value_by_section(sec, "class_instance", "1"); } + + class->dmmap_sec = sec; + handle_instance(dmctx, parent_node, sec, "class_instance", "class_alias"); + DM_LINK_INST_OBJ(dmctx, parent_node, (void *)class, "1"); + + free_capability_list(&cap_list); + dmfree(class); + return 0; } -static int browseSoftwareModulesDeploymentUnitInst(struct dmctx *dmctx, DMNODE *parent_node, void *prev_data, char *prev_instance) +static int browseSoftwareModulesCapability(struct dmctx *dmctx, DMNODE *parent_node, void *prev_data, char *prev_instance) { - json_object *res = NULL, *du_obj = NULL, *arrobj = NULL; + struct ee_class *class = (struct ee_class *)prev_data; + struct capability *cap = NULL, *tmp = NULL; + int id = 0; char *inst = NULL; - int id = 0, du = 0; - dmubus_call("swmodules", "du_list", UBUS_ARGS{0}, 0, &res); - dmjson_foreach_obj_in_array(res, arrobj, du_obj, du, 1, "deployment_unit") { + if (!class) + return 0; + + list_for_each_entry_safe(cap, tmp, class->cap_head, list) { inst = handle_instance_without_section(dmctx, parent_node, ++id); - if (DM_LINK_INST_OBJ(dmctx, parent_node, (void *)du_obj, inst) == DM_STOP) + if (DM_LINK_INST_OBJ(dmctx, parent_node, (void *)cap, inst) == DM_STOP) break; } + return 0; } -static int browseSoftwareModulesExecutionUnitInst(struct dmctx *dmctx, DMNODE *parent_node, void *prev_data, char *prev_instance) +static int browseSoftwareModulesExecEnvInst(struct dmctx *dmctx, DMNODE *parent_node, void *prev_data, char *prev_instance) { - json_object *res = NULL, *eu_obj = NULL, *arrobj = NULL; + struct uci_section *s; char *inst = NULL; - int id = 0, eu = 0; - dmubus_call("swmodules", "eu_list", UBUS_ARGS{0}, 0, &res); - dmjson_foreach_obj_in_array(res, arrobj, eu_obj, eu, 1, "execution_unit") { - inst = handle_instance_without_section(dmctx, parent_node, ++id); - if (DM_LINK_INST_OBJ(dmctx, parent_node, (void *)eu_obj, inst) == DM_STOP) + uci_foreach_sections("swmodd", "execenv", s) { + inst = handle_instance(dmctx, parent_node, s, "ee_instance", "ee_alias"); + + if (DM_LINK_INST_OBJ(dmctx, parent_node, (void *)s, inst) == DM_STOP) break; } + return 0; } -/************************************************************* -* LINKER FUNCTIONS -*************************************************************/ -static int get_linker_eu(char *refparam, struct dmctx *dmctx, void *data, char *instance, char **linker) +static int browseSoftwareModulesDeploymentUnitInst(struct dmctx *dmctx, DMNODE *parent_node, void *prev_data, char *prev_instance) { - char *ee_name = NULL, *eu_name = NULL; - - ee_name = dmjson_get_value((json_object *)data, 1, "ee_name"); - eu_name = dmjson_get_value((json_object *)data, 1, "eu_name"); - if (ee_name == NULL) - ee_name = ""; + struct uci_section *s; + char *inst = NULL; - if (eu_name == NULL) - eu_name = ""; + uci_foreach_sections("swmodd", "du_eu_assoc", s) { + inst = handle_instance(dmctx, parent_node, s, "du_instance", "du_alias"); - dmasprintf(linker, "%.32s%.32s", ee_name, eu_name); + if (DM_LINK_INST_OBJ(dmctx, parent_node, (void *)s, inst) == DM_STOP) + break; + } return 0; } /************************************************************* -* COMMON FUNCTIONS -**************************************************************/ -#if 0 -static int get_SoftwareModules_VendorConfigList(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) +* LINKER FUNCTIONS +*************************************************************/ +static int get_linker_execenv(char *refparam, struct dmctx *ctx, void *data, char *instance, char **linker) { - struct uci_section *s = NULL; - dmasprintf(value, ""); - - char *config = dmjson_get_value((json_object *)data, 1, "config"); - if (config == NULL || *config == '\0') - return 0; + char *value = NULL; - uci_path_foreach_sections(bbfdm, DMMAP, "vcf", s) { - char *name = NULL; + dmuci_get_value_by_section_string((struct uci_section *)data, "name", &value); + *linker = dmstrdup(value); - dmuci_get_value_by_section_string(s, "name", &name); - if (name && strcmp(name, config) == 0) { - char *vcf_instance; - dmuci_get_value_by_section_string(s, "vcf_instance", &vcf_instance); - dmasprintf(value, "Device.DeviceInfo.VendorConfigFile.%s", vcf_instance); - break; - } - } return 0; } -#endif + +/************************************************************* +* COMMON FUNCTIONS +**************************************************************/ /************************************************************* * GET & SET PARAM *************************************************************/ +static int get_SoftwareModules_ExecEnvClassNumberOfEntries(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) +{ + unsigned int cnt = get_number_of_entries(ctx, data, instance, browseSoftwareModulesExecEnvClass); + dmasprintf(value, "%u", cnt); + + return 0; +} + static int get_SoftwareModules_ExecEnvNumberOfEntries(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) { - json_object *res = NULL, *environment = NULL; - size_t nbre_env = 0; + unsigned int cnt = get_number_of_entries(ctx, data, instance, browseSoftwareModulesExecEnvInst); + dmasprintf(value, "%u", cnt); - dmubus_call("swmodules", "ee_list", UBUS_ARGS{0}, 0, &res); - DM_ASSERT(res, dmasprintf(value, "0")); - json_object_object_get_ex(res, "environment", &environment); - nbre_env = (environment) ? json_object_array_length(environment) : 0; - dmasprintf(value, "%d", nbre_env); return 0; } static int get_SoftwareModules_DeploymentUnitNumberOfEntries(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) { - json_object *res = NULL, *deployment_unit = NULL; - size_t nbre_du = 0; + unsigned int cnt = get_number_of_entries(ctx, data, instance, browseSoftwareModulesDeploymentUnitInst); + dmasprintf(value, "%u", cnt); - dmubus_call("swmodules", "du_list", UBUS_ARGS{0}, 0, &res); - DM_ASSERT(res, dmasprintf(value, "0")); - json_object_object_get_ex(res, "deployment_unit", &deployment_unit); - nbre_du = (deployment_unit) ? json_object_array_length(deployment_unit) : 0; - dmasprintf(value, "%d", nbre_du); return 0; } -static int get_SoftwareModules_ExecutionUnitNumberOfEntries(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) +static int get_SoftwareModules_CapabilityNumberOfEntries(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) { - json_object *res = NULL, *execution_unit = NULL; - size_t nbre_env = 0; + unsigned int cnt = get_number_of_entries(ctx, data, instance, browseSoftwareModulesCapability); + dmasprintf(value, "%u", cnt); - dmubus_call("swmodules", "eu_list", UBUS_ARGS{0}, 0, &res); - DM_ASSERT(res, dmasprintf(value, "0")); - json_object_object_get_ex(res, "execution_unit", &execution_unit); - nbre_env = (execution_unit) ? json_object_array_length(execution_unit) : 0; - dmasprintf(value, "%d", nbre_env); return 0; } -/*#Device.SoftwareModules.ExecEnv.{i}.Enable!UBUS:swmodules/environment//environment[i-1].autoboot*/ -static int get_SoftwareModulesExecEnv_Enable(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) +static int get_SoftwareModulesExecEnvClass_Alias(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) +{ + return bbf_get_alias(ctx, ((struct ee_class *)data)->dmmap_sec, "class_alias", instance, value); +} + +static int set_SoftwareModulesExecEnvClass_Alias(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action) +{ + return bbf_set_alias(ctx, ((struct ee_class *)data)->dmmap_sec, "class_alias", instance, value); +} + +static int get_SoftwareModulesExecEnvClass_Name(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) { - *value = dmjson_get_value((json_object *)data, 1, "autoboot"); + struct ee_class *class = (struct ee_class *)data; + if (!class) + return 0; + + *value = dmstrdup(class->name); return 0; } -static int set_SoftwareModulesExecEnv_Enable(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action) +static int get_SoftwareModulesExecEnvClass_Vendor(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) { - char *env_name = NULL; + struct ee_class *class = (struct ee_class *)data; + if (!class) + return 0; - switch (action) { - case VALUECHECK: - if (bbfdm_validate_boolean(ctx, value)) - return FAULT_9007; - break; - case VALUESET: - env_name = dmjson_get_value((json_object *)data, 1, "ee_name"); + *value = dmstrdup(class->vendor); + return 0; +} - dmubus_call_set("swmodules", "set_config", UBUS_ARGS{ - {"ee_name", env_name, String}, - {"parameter", "ee_enable", String}, - {"value", value, String}}, - 3); - break; - } +static int get_SoftwareModulesExecEnvClass_Version(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) +{ + struct ee_class *class = (struct ee_class *)data; + if (!class) + return 0; + + *value = dmstrdup(class->version); return 0; } -/*#Device.SoftwareModules.ExecEnv.{i}.Status!UBUS:swmodules/environment//environment[i-1].status*/ -static int get_SoftwareModulesExecEnv_Status(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) +static int get_SoftwareModulesExecEnvClass_DURef(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) { - *value = dmjson_get_value((json_object *)data, 1, "status"); return 0; } -static int get_SoftwareModulesExecEnv_Reset(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) +static int get_CapabilitySpecification(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) { - dmasprintf(value, "0"); + struct capability *cap = (struct capability *)data; + if (!cap) + return 0; + + *value = dmstrdup(cap->spec); return 0; } -static int set_SoftwareModulesExecEnv_Reset(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action) +static int get_CapabilitySpecificationVersion(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) { + struct capability *cap = (struct capability *)data; + if (!cap) + return 0; + + *value = dmstrdup(cap->spec_ver); return 0; } -static int get_SoftwareModulesExecEnv_Alias(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) +static int get_CapabilitySpecificationURI(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) { - char *alias = dmjson_get_value((json_object *)data, 1, "ee_alias"); + struct capability *cap = (struct capability *)data; + if (!cap) + return 0; - if (DM_STRLEN(alias) == 0) - dmasprintf(value, "cpe-%s", instance); - else - dmasprintf(value, "%s", alias); + *value = dmstrdup(cap->uri); + return 0; +} +static int get_SoftwareModulesExecEnv_Enable(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) +{ + dmuci_get_value_by_section_string((struct uci_section *)data, "enable", value); return 0; } -static int set_SoftwareModulesExecEnv_Alias(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action) +static int set_SoftwareModulesExecEnv_Enable(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action) { - char *ee_name = NULL; + bool val; + char *ee_action = NULL; switch (action) { case VALUECHECK: - if (bbfdm_validate_string(ctx, value, -1, 64, NULL, NULL)) + if (bbfdm_validate_boolean(ctx, value)) return FAULT_9007; break; case VALUESET: - ee_name = dmjson_get_value((json_object *)data, 1, "ee_name"); - - if (DM_STRLEN(ee_name) == 0) - return 0; + dmuci_get_value_by_section_string((struct uci_section *)data, "action", &ee_action); + if (DM_STRLEN(ee_action) != 0) { + bbfdm_set_fault_message(ctx, "Execution Environment is busy. Try after sometime."); + return FAULT_9001; + } - dmubus_call_set("swmodules", "set_config", UBUS_ARGS{ - {"ee_name", ee_name, String}, - {"parameter", "ee_alias", String}, - {"value", value, String}}, - 3); + string_to_bool(value, &val); + dmuci_set_value_by_section((struct uci_section *)data, "enable", val ? "1" : "0"); + dmuci_set_value_by_section((struct uci_section *)data, "action", val ? "enable" : "disable"); break; } return 0; } -/*#Device.SoftwareModules.ExecEnv.{i}.Name!UBUS:swmodules/environment//environment[i-1].name*/ -static int get_SoftwareModulesExecEnv_Name(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) +static int get_SoftwareModulesExecEnv_Status(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) { - *value = dmjson_get_value((json_object *)data, 1, "ee_name"); + char *val = NULL; + dmuci_get_value_by_section_string((struct uci_section *)data, "status", &val); + if (DM_STRLEN(val) != 0) { + *value = dmstrdup(val); + return 0; + } + + dmuci_get_value_by_section_string((struct uci_section *)data, "action", &val); + if (DM_STRCMP(val, "restart") == 0) { + *value = dmstrdup("Restarting"); + return 0; + } + + dmuci_get_value_by_section_string((struct uci_section *)data, "enable", &val); + if (val[0] == '1') + *value = dmstrdup("Up"); + else + *value = dmstrdup("Disabled"); + return 0; } -/*#Device.SoftwareModules.ExecEnv.{i}.Type!UBUS:swmodules/environment//environment[i-1].type*/ -static int get_SoftwareModulesExecEnv_Type(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) +static int get_SoftwareModulesExecEnv_Alias(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) { - *value = dmjson_get_value((json_object *)data, 1, "type"); - return 0; + return bbf_get_alias(ctx, (struct uci_section *)data, "ee_alias", instance, value); } -static int get_SoftwareModulesExecEnv_InitialRunLevel(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) +static int set_SoftwareModulesExecEnv_Alias(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action) { - dmasprintf(value, "0"); + return bbf_set_alias(ctx, (struct uci_section *)data, "ee_alias", instance, value); +} + +static int get_SoftwareModulesExecEnv_Name(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) +{ + dmuci_get_value_by_section_string((struct uci_section *)data, "name", value); return 0; } -static int set_SoftwareModulesExecEnv_InitialRunLevel(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action) +static int get_SoftwareModulesExecEnv_Type(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) { return 0; } -static int get_SoftwareModulesExecEnv_RequestedRunLevel(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) +static int get_SoftwareModulesExecEnv_InitialRunLevel(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) { - dmasprintf(value, "-1"); + dmuci_get_value_by_section_string((struct uci_section *)data, "initial_runlevel", value); return 0; } -static int set_SoftwareModulesExecEnv_RequestedRunLevel(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action) +static int set_SoftwareModulesExecEnv_InitialRunLevel(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action) { + switch (action) { + case VALUECHECK: + if (bbfdm_validate_unsignedInt(ctx, value, RANGE_ARGS{{"0","65535"}}, 1)) + return FAULT_9007; + break; + case VALUESET: + dmuci_set_value_by_section((struct uci_section *)data, "initial_runlevel", value); + break; + } return 0; } static int get_SoftwareModulesExecEnv_CurrentRunLevel(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) { - dmasprintf(value, "-1"); + dmuci_get_value_by_section_string((struct uci_section *)data, "current_runlevel", value); return 0; } static int get_SoftwareModulesExecEnv_InitialExecutionUnitRunLevel(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) { - dmasprintf(value, "-1"); + dmuci_get_value_by_section_string((struct uci_section *)data, "initial_eu_runlevel", value); return 0; } static int set_SoftwareModulesExecEnv_InitialExecutionUnitRunLevel(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action) { + switch (action) { + case VALUECHECK: + if (bbfdm_validate_unsignedInt(ctx, value, RANGE_ARGS{{"0","65535"}}, 1)) + return FAULT_9007; + break; + case VALUESET: + dmuci_set_value_by_section((struct uci_section *)data, "initial_eu_runlevel", value); + break; + } return 0; } -/*#Device.SoftwareModules.ExecEnv.{i}.Vendor!UBUS:swmodules/environment//environment[i-1].vendor*/ static int get_SoftwareModulesExecEnv_Vendor(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) { - *value = dmjson_get_value((json_object *)data, 1, "vendor"); return 0; } -/*#Device.SoftwareModules.ExecEnv.{i}.Version!UBUS:swmodules/environment//environment[i-1].version*/ static int get_SoftwareModulesExecEnv_Version(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) { - *value = dmjson_get_value((json_object *)data, 1, "version"); return 0; } static int get_SoftwareModulesExecEnv_ParentExecEnv(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) { - char *eid = dmjson_get_value((json_object *)data, 1, "parent_ee_ref"); - if (eid == NULL || strcmp(eid, "0") == 0) { - dmasprintf(value, ""); - } else { - dmasprintf(value, "Device.SoftwareModules.ExecEnv.%s", eid); - } - return 0; } -/*#Device.SoftwareModules.ExecEnv.{i}.AllocatedDiskSpace!UBUS:swmodules/environment//environment[i-1].allocateddiskspace*/ -static int get_SoftwareModulesExecEnv_AllocatedDiskSpace(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) +static int get_SoftwareModulesExecEnv_RestartReason(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) { - *value = dmjson_get_value((json_object *)data, 1, "allocated_disk_space"); + dmuci_get_value_by_section_string((struct uci_section *)data, "restart_reason", value); return 0; } -/*#Device.SoftwareModules.ExecEnv.{i}.AvailableDiskSpace!UBUS:swmodules/environment//environment[i-1].availablediskspace*/ -static int get_SoftwareModulesExecEnv_AvailableDiskSpace(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) +static int get_SoftwareModulesExecEnv_RestartCount(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) { - *value = dmjson_get_value((json_object *)data, 1, "available_disk_space"); + dmuci_get_value_by_section_string((struct uci_section *)data, "restart_count", value); return 0; } -/*#Device.SoftwareModules.ExecEnv.{i}.AllocatedMemory!UBUS:swmodules/environment//environment[i-1].allocatedmemory*/ -static int get_SoftwareModulesExecEnv_AllocatedMemory(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) +static int get_SoftwareModulesExecEnv_LastRestarted(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) { - *value = dmjson_get_value((json_object *)data, 1, "allocated_memory"); + dmuci_get_value_by_section_string((struct uci_section *)data, "last_restarted", value); return 0; } -/*#Device.SoftwareModules.ExecEnv.{i}.AvailableMemory!UBUS:swmodules/environment//environment[i-1].availablememory*/ -static int get_SoftwareModulesExecEnv_AvailableMemory(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) +static int get_SoftwareModulesExecEnv_CreatedAt(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) { - *value = dmjson_get_value((json_object *)data, 1, "available_memory"); + dmuci_get_value_by_section_string((struct uci_section *)data, "created_at", value); return 0; } -int get_SoftwareModulesExecEnv_ActiveExecutionUnits(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) +static int get_SoftwareModulesExecEnv_ExecEnvClassRef(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) { - json_object *res = NULL, *du_obj = NULL, *arrobj = NULL; - char eu_list[2048]; - unsigned pos = 0; - int eu = 0; - - eu_list[0] = 0; - char *curr_env = dmjson_get_value((json_object *)data, 1, "ee_name"); - dmubus_call("swmodules", "eu_list", UBUS_ARGS{0}, 0, &res); - DM_ASSERT(res, dmasprintf(value, "")); - dmjson_foreach_obj_in_array(res, arrobj, du_obj, eu, 1, "execution_unit") { - char *environment = dmjson_get_value(du_obj, 1, "ee_name"); - - if (strcmp(environment, curr_env) == 0) - pos += snprintf(&eu_list[pos], sizeof(eu_list) - pos, "Device.SoftwareModules.ExecutionUnit.%d,", eu+1); - } - - if (pos) - eu_list[pos - 1] = 0; - - *value = dmstrdup(eu_list); + *value = "Device.SoftwareModules.ExecEnvClass.1"; return 0; } -/*#Device.SoftwareModules.DeploymentUnit.{i}.UUID!UBUS:swmodules/du_list//deployment_unit[i-1].uuid*/ static int get_SoftwareModulesDeploymentUnit_UUID(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) { - *value = dmjson_get_value((json_object *)data, 1, "uuid"); + dmuci_get_value_by_section_string((struct uci_section *)data, "uuid", value); return 0; } -/*#Device.SoftwareModules.DeploymentUnit.{i}.DUID!UBUS:swmodules/du_list//deployment_unit[i-1].duid*/ static int get_SoftwareModulesDeploymentUnit_DUID(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) { - *value = dmjson_get_value((json_object *)data, 1, "duid"); + dmuci_get_value_by_section_string((struct uci_section *)data, "duid", value); return 0; } static int get_SoftwareModulesDeploymentUnit_Alias(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) { - char *alias = dmjson_get_value((json_object *)data, 1, "du_alias"); - - if (DM_STRLEN(alias) == 0) - dmasprintf(value, "cpe-%s", instance); - else - dmasprintf(value, "%s", alias); - - return 0; + return bbf_get_alias(ctx, (struct uci_section *)data, "du_alias", instance, value); } static int set_SoftwareModulesDeploymentUnit_Alias(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action) { - char *ee_name = NULL, *uuid = NULL; - - switch (action) { - case VALUECHECK: - if (bbfdm_validate_string(ctx, value, -1, 64, NULL, NULL)) - return FAULT_9007; - break; - case VALUESET: - ee_name = dmjson_get_value((json_object *)data, 1, "ee_name"); - uuid = dmjson_get_value((json_object *)data, 1, "uuid"); - - if (DM_STRLEN(ee_name) == 0 || DM_STRLEN(uuid) == 0) - return 0; - - dmubus_call_set("swmodules", "set_config", UBUS_ARGS{ - {"ee_name", ee_name, String}, - {"uuid", uuid, String}, - {"parameter", "du_alias", String}, - {"value", value, String}}, - 4); - - break; - } - return 0; -} - -static int set_SoftwareModulesExecutionUnit_RequestedState(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action) -{ - char *eid = NULL, *name = NULL; - - switch (action) { - case VALUECHECK: - if (strcmp(value, "Idle") != 0 && strcmp(value, "Active") != 0) - return FAULT_9007; - break; - case VALUESET: - eid = dmjson_get_value((json_object *)data, 1, "eeid"); - name = dmjson_get_value((json_object *)data, 1, "eu_name"); - - if (eid == NULL || name == NULL) { - return 0; - } - - if (eid[0] == '\0' || name[0] == '\0') { - return 0; - } - - dmubus_call_set("swmodules", "set_config", UBUS_ARGS{ - {"eeid", eid, Integer}, - {"eu_name", name, String}, - {"parameter", "eu_requested_state", String}, - {"value", value, String}}, - 4); - - break; - } - - return 0; + return bbf_set_alias(ctx, (struct uci_section *)data, "du_alias", instance, value); } -/*#Device.SoftwareModules.DeploymentUnit.{i}.Name!UBUS:swmodules/du_list//deployment_unit[i-1].name*/ static int get_SoftwareModulesDeploymentUnit_Name(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) { - *value = dmjson_get_value((json_object *)data, 1, "du_name"); + *value = dmstrdup(section_name((struct uci_section *)data)); return 0; } static int get_SoftwareModulesDeploymentUnit_Status(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) { - char *val = dmjson_get_value((json_object *)data, 1, "du_status"); - if (val) { - char *tmp = strchr(val, '_'); - if (tmp) - *tmp = '\0'; - - dmasprintf(value, val); - } else { - dmasprintf(value, ""); - } - + dmuci_get_value_by_section_string((struct uci_section *)data, "status", value); return 0; } static int get_SoftwareModulesDeploymentUnit_Resolved(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) { - char *val = dmjson_get_value((json_object *)data, 1, "du_status"); + char *val = NULL; + + dmuci_get_value_by_section_string((struct uci_section *)data, "status", &val); if (DM_STRCMP(val, "Installed") == 0) dmasprintf(value, "1"); else @@ -496,325 +509,214 @@ static int get_SoftwareModulesDeploymentUnit_Resolved(char *refparam, struct dmc return 0; } -/*#Device.SoftwareModules.DeploymentUnit.{i}.URL!UBUS:swmodules/du_list//deployment_unit[i-1].url*/ static int get_SoftwareModulesDeploymentUnit_URL(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) { - *value = dmjson_get_value((json_object *)data, 1, "url"); + dmuci_get_value_by_section_string((struct uci_section *)data, "url", value); return 0; } -/*#Device.SoftwareModules.DeploymentUnit.{i}.Description!UBUS:swmodules/du_list//deployment_unit[i-1].description*/ static int get_SoftwareModulesDeploymentUnit_Description(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) { - *value = dmjson_get_value((json_object *)data, 1, "description"); + dmuci_get_value_by_section_string((struct uci_section *)data, "description", value); return 0; } -/*#Device.SoftwareModules.DeploymentUnit.{i}.Vendor!UBUS:swmodules/du_list//deployment_unit[i-1].vendor*/ static int get_SoftwareModulesDeploymentUnit_Vendor(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) { - *value = dmjson_get_value((json_object *)data, 1, "vendor"); + dmuci_get_value_by_section_string((struct uci_section *)data, "vendor", value); return 0; } -/*#Device.SoftwareModules.DeploymentUnit.{i}.Version!UBUS:swmodules/du_list//deployment_unit[i-1].version*/ static int get_SoftwareModulesDeploymentUnit_Version(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) { - *value = dmjson_get_value((json_object *)data, 1, "version"); + dmuci_get_value_by_section_string((struct uci_section *)data, "version", value); return 0; } static int get_SoftwareModulesDeploymentUnit_VendorLogList(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) { - dmasprintf(value, ""); return 0; } -/*#Device.SoftwareModules.DeploymentUnit.{i}.VendorConfigList!UBUS:swmodules/du_list//deployment_unit[i-1].config*/ static int get_SoftwareModulesDeploymentUnit_VendorConfigList(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) { - dmasprintf(value, ""); return 0; } static int get_SoftwareModulesDeploymentUnit_ExecutionUnitList(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) { - char eu_label[65] = {0}; - - char *ee = dmjson_get_value((json_object *)data, 1, "ee_name"); - char *eu = dmjson_get_value((json_object *)data, 1, "eu_name"); - - snprintf(eu_label, sizeof(eu_label), "%.32s%.32s", ee ? ee : "", eu ? eu : ""); - - char *linker = NULL; - adm_entry_get_linker_param(ctx, "Device.SoftwareModules.ExecutionUnit.", eu_label, &linker); - if (DM_STRLEN(linker) != 0) - dmasprintf(value, "%s", linker); - return 0; } -/*#Device.SoftwareModules.DeploymentUnit.{i}.ExecutionEnvRef!UBUS:swmodules/du_list//deployment_unit[i-1].environment*/ static int get_SoftwareModulesDeploymentUnit_ExecutionEnvRef(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) { - char *eid = dmjson_get_value((json_object *)data, 1, "eeid"); + char *execenv = NULL; - dmasprintf(value, "Device.SoftwareModules.ExecEnv.%s", eid); - return 0; -} + dmuci_get_value_by_section_string((struct uci_section *)data, "execenv", &execenv); + adm_entry_get_linker_param(ctx, "Device.SoftwareModules.ExecEnv.", execenv, value); -/*#Device.SoftwareModules.ExecutionUnit.{i}.EUID!UBUS:swmodules/eu_list//execution_unit[i-1].euid*/ -static int get_SoftwareModulesExecutionUnit_EUID(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) -{ - *value = dmjson_get_value((json_object *)data, 1, "euid"); return 0; } -static int get_SoftwareModulesExecutionUnit_Alias(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) +static int get_SoftwareModulesDeploymentUnit_Installed(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) { - char *alias = dmjson_get_value((json_object *)data, 1, "eu_alias"); - - if (DM_STRLEN(alias) == 0) - dmasprintf(value, "cpe-%s", instance); - else - dmasprintf(value, "%s", alias); - + dmuci_get_value_by_section_string((struct uci_section *)data, "installed_at", value); return 0; } -static int set_SoftwareModulesExecutionUnit_Alias(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action) -{ - char *eu_name = NULL, *eu_env = NULL; - - switch (action) { - case VALUECHECK: - if (bbfdm_validate_string(ctx, value, -1, 64, NULL, NULL)) - return FAULT_9007; - break; - case VALUESET: - eu_name = dmjson_get_value((json_object *)data, 1, "eu_name"); - eu_env = dmjson_get_value((json_object *)data, 1, "ee_name"); - - if (DM_STRLEN(eu_name) == 0 || DM_STRLEN(eu_env) == 0) - return 0; - - dmubus_call_set("swmodules", "set_config", UBUS_ARGS{ - {"ee_name", eu_env, String}, - {"eu_name", eu_name, String}, - {"parameter", "eu_alias", String}, - {"value", value, String}}, - 4); - - break; +/************************************************************* + * OPERATE COMMANDS + *************************************************************/ +static operation_args softwaremodules_add_execenv_args = { + .in = (const char *[]) { + "Alias", + "Name", + "ParentExecEnv", + "Enable", + "AllocatedDiskSpace", + NULL } +}; + +static int get_operate_args_SoftwareModules_AddExecEnv(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) +{ + *value = (char *)&softwaremodules_add_execenv_args; return 0; } -static int set_SoftwareModulesExecutionUnit_AutoStart(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action) +static int operate_SoftwareModules_AddExecEnv(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action) { - char *eeid = NULL, *eu_name = NULL; - - switch (action) { - case VALUECHECK: - if (bbfdm_validate_boolean(ctx, value)) - return FAULT_9007; - break; - case VALUESET: - eeid = dmjson_get_value((json_object *)data, 1, "eeid"); - eu_name = dmjson_get_value((json_object *)data, 1, "eu_name"); + struct uci_section *s = NULL; + char *name, *alias, *enable, *disk_space; + int len; + time_t now; + char ctime[32] = {0}; + bool ee_enable; + + name = dmjson_get_value((json_object *)value, 1, "Name"); + if (name[0] == '\0') + return USP_FAULT_INVALID_ARGUMENT; - if (eu_name == NULL || eeid == NULL) { - return 0; - } + alias = dmjson_get_value((json_object *)value, 1, "Alias"); + enable = dmjson_get_value((json_object *)value, 1, "Enable"); + disk_space = dmjson_get_value((json_object *)value, 1, "AllocatedDiskSpace"); - if (eu_name[0] == '\0' || eeid[0] == '\0') { - return 0; - } + len = DM_STRLEN(name); + if (name[len-1] == '/') + name[len-1] = '0'; - dmubus_call_set("swmodules", "set_config", UBUS_ARGS{ - {"eeid", eeid, Integer}, - {"eu_name", eu_name, String}, - {"parameter", "eu_autostart", String}, - {"value", value, String}}, - 4); + /* check if duplicate env or a nested env */ + if (!valid_execenv_name(name)) + return USP_FAULT_INVALID_ARGUMENT; - break; - } + dmuci_add_section("swmodd", "execenv", &s); + if (!s) + return USP_FAULT_INTERNAL_ERROR; - return 0; -} + dmuci_rename_section_by_section(s, section_name(s)); -/*#Device.SoftwareModules.ExecutionUnit.{i}.Name!UBUS:swmodules/eu_list//execution_unit[i-1].name*/ -static int get_SoftwareModulesExecutionUnit_Name(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) -{ - *value = dmjson_get_value((json_object *)data, 1, "eu_name"); - return 0; -} + string_to_bool(enable, &ee_enable); + now = time(NULL); + strftime(ctime, sizeof(ctime), "%Y-%m-%dT%H:%M:%SZ", gmtime(&now)); -/*#Device.SoftwareModules.ExecutionUnit.{i}.ExecEnvLabel!UBUS:swmodules/eu_list//execution_unit[i-1].euid*/ -static int get_SoftwareModulesExecutionUnit_ExecEnvLabel(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) -{ - char *ee_name = NULL, *eu_name = NULL; + dmuci_set_value_by_section(s, "name", name); + dmuci_set_value_by_section(s, "ee_alias", alias); + dmuci_set_value_by_section(s, "enable", ee_enable ? "1" : "0"); + dmuci_set_value_by_section(s, "action", "add"); + dmuci_set_value_by_section(s, "disk_space", disk_space); + dmuci_set_value_by_section(s, "initial_runlevel", "65535"); + dmuci_set_value_by_section(s, "current_runlevel", "-1"); + dmuci_set_value_by_section(s, "initial_eu_runlevel", "0"); + dmuci_set_value_by_section(s, "restart_count", "0"); + dmuci_set_value_by_section(s, "created_at", ctime); + dmuci_set_value_by_section(s, "last_restarted", "0001-01-01T00:00:00Z"); - ee_name = dmjson_get_value((json_object *)data, 1, "ee_name"); - eu_name = dmjson_get_value((json_object *)data, 1, "eu_name"); - if (ee_name == NULL) - ee_name = ""; - - if (eu_name == NULL) - eu_name = ""; + dmubus_call_set("uci", "commit", UBUS_ARGS{{"config", "swmodd", String}}, 1); - dmasprintf(value, "%.32s%.32s", ee_name, eu_name); return 0; } -static int get_SoftwareModulesExecutionUnit_Status(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) -{ - *value = dmjson_get_value((json_object *)data, 1, "state"); - return 0; -} +static operation_args softwaremodules_set_runlevel_args = { + .in = (const char *[]) { + "RequestedRunLevel", + NULL + } +}; -static int get_SoftwareModulesExecutionUnit_ExecutionFaultCode(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) +static int get_operate_args_SoftwareModules_SetRunLevel(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) { - *value = dmjson_get_value((json_object *)data, 1, "fault_code"); + *value = (char *)&softwaremodules_set_runlevel_args; return 0; } -static int get_SoftwareModulesExecutionUnit_ExecutionFaultMessage(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) +static int operate_SoftwareModulesExecEnv_SetRunLevel(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action) { - char *fault = dmjson_get_value((json_object *)data, 1, "fault_code"); - if (DM_STRCMP(fault, "FailureOnStart") == 0) - dmasprintf(value, "Failed to start the OCI based Execution Unit"); - else - dmasprintf(value, ""); + char *run_level = dmjson_get_value((json_object *)value, 1, "RequestedRunLevel"); - return 0; -} + if (bbfdm_validate_int(ctx, run_level, RANGE_ARGS{{"-1","65535"}}, 1)) + return USP_FAULT_INVALID_ARGUMENT; -static int get_SoftwareModulesExecutionUnit_AutoStart(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) -{ - *value = dmjson_get_value((json_object *)data, 1, "autostart"); - return 0; -} + dmuci_set_value_by_section((struct uci_section *)data, "current_runlevel", run_level); -static int get_SoftwareModulesExecutionUnit_RunLevel(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) -{ - dmasprintf(value, "-1"); - return 0; -} + dmuci_commit_package("swmodd"); -static int set_SoftwareModulesExecutionUnit_RunLevel(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action) -{ return 0; } -/*#Device.SoftwareModules.ExecutionUnit.{i}.Vendor!UBUS:swmodules/eu_list//execution_unit[i-1].vendor*/ -static int get_SoftwareModulesExecutionUnit_Vendor(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) -{ - *value = dmjson_get_value((json_object *)data, 1, "vendor"); - return 0; -} +static operation_args softwaremodules_restart_args = { + .in = (const char *[]) { + "Reason", + "Force", + NULL + } +}; -/*#Device.SoftwareModules.ExecutionUnit.{i}.Version!UBUS:swmodules/eu_list//execution_unit[i-1].version*/ -static int get_SoftwareModulesExecutionUnit_Version(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) +static int get_operate_args_SoftwareModules_Restart(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) { - *value = dmjson_get_value((json_object *)data, 1, "version"); + *value = (char *)&softwaremodules_restart_args; return 0; } -/*#Device.SoftwareModules.ExecutionUnit.{i}.Description!UBUS:swmodules/eu_list//execution_unit[i-1].description*/ -static int get_SoftwareModulesExecutionUnit_Description(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) +static int operate_SoftwareModulesExecEnv_Restart(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action) { - *value = dmjson_get_value((json_object *)data, 1, "description"); return 0; } -/*#Device.SoftwareModules.ExecutionUnit.{i}.DiskSpaceInUse!UBUS:swmodules/eu_list//execution_unit[i-1].disk_space*/ -static int get_SoftwareModulesExecutionUnit_DiskSpaceInUse(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) -{ - *value = dmjson_get_value((json_object *)data, 1, "disk_space"); - return 0; -} +static operation_args softwaremodules_remove_args = { + .in = (const char *[]) { + "Force", + NULL + } +}; -/*#Device.SoftwareModules.ExecutionUnit.{i}.MemoryInUse!UBUS:swmodules/eu_list//execution_unit[i-1].memory_space*/ -static int get_SoftwareModulesExecutionUnit_MemoryInUse(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) +static int get_operate_args_SoftwareModules_Remove(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) { - *value = dmjson_get_value((json_object *)data, 1, "memory_space"); + *value = (char *)&softwaremodules_remove_args; return 0; } -int get_SoftwareModulesExecutionUnit_References(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) +static int operate_SoftwareModulesExecEnv_Remove(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action) { - json_object *res = NULL, *du_obj = NULL, *arrobj = NULL; - char *environment = NULL, *name = NULL; - int du = 0; - - char *curr_name = dmjson_get_value((json_object *)data, 1, "eu_name"); - char *curr_environment = dmjson_get_value((json_object *)data, 1, "ee_name"); + char *ee_action = NULL; + char *val = NULL; + bool force; - dmubus_call("swmodules", "du_list", UBUS_ARGS{0}, 0, &res); - DM_ASSERT(res, dmasprintf(value, "")); - dmjson_foreach_obj_in_array(res, arrobj, du_obj, du, 1, "deployment_unit") { - name = dmjson_get_value(du_obj, 1, "du_name"); - environment = dmjson_get_value(du_obj, 1, "ee_name"); - if ((name && curr_name && strcmp(name, curr_name) == 0) && (environment && curr_environment && strcmp(environment, curr_environment) == 0)) { - dmasprintf(value, "Device.SoftwareModules.DeploymentUnit.%d", du+1); - break; - } + dmuci_get_value_by_section_string((struct uci_section *)data, "action", &ee_action); + if (DM_STRLEN(ee_action) != 0) { + bbfdm_set_fault_message(ctx, "Execution Environment is busy. Try after sometime."); + return USP_FAULT_REQUEST_DENIED; } - return 0; -} -static int get_SoftwareModulesExecutionUnit_AssociatedProcessList(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) -{ - char *euid = dmjson_get_value((json_object *)data, 1, "euid"); + val = dmjson_get_value((json_object *)value, 1, "Force"); + string_to_bool(val, &force); - if (DM_STRLEN(euid) == 0 || DM_STRCMP(euid, "Unknown") == 0) - return 0; + dmuci_set_value_by_section((struct uci_section *)data, "action", force ? "force_remove" : "remove"); - char *linker = NULL; - adm_entry_get_linker_param(ctx, "Device.DeviceInfo.ProcessStatus.", euid, &linker); - if (DM_STRLEN(linker) != 0) - dmasprintf(value, "%s", linker); - - return 0; -} - -static int get_SoftwareModulesExecutionUnit_VendorLogList(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) -{ - dmasprintf(value, ""); - return 0; -} - -/*#Device.SoftwareModules.ExecutionUnit.{i}.VendorConfigList!UBUS:swmodules/eu_list//execution_unit[i-1].config*/ -static int get_SoftwareModulesExecutionUnit_VendorConfigList(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) -{ - dmasprintf(value, ""); - return 0; -} - -/*#Device.SoftwareModules.ExecutionUnit.{i}.ExecutionEnvRef!UBUS:swmodules/eu_list//execution_unit[i-1].environment*/ -static int get_SoftwareModulesExecutionUnit_ExecutionEnvRef(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) -{ - char *eid = dmjson_get_value((json_object *)data, 1, "eeid"); + dmubus_call_set("uci", "commit", UBUS_ARGS{{"config", "swmodd", String}}, 1); - dmasprintf(value, "Device.SoftwareModules.ExecEnv.%s", eid); return 0; } -/************************************************************* - * OPERATE COMMANDS - *************************************************************/ -static int operate_SoftwareModulesExecEnv_Reset(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action) -{ - return USP_FAULT_COMMAND_FAILURE; -} - -static int operate_SoftwareModulesExecEnv_SetRunLevel(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action) -{ - return USP_FAULT_COMMAND_FAILURE; -} - static operation_args softwaremodules_installdu_args = { .in = (const char *[]) { "URL", @@ -822,6 +724,7 @@ static operation_args softwaremodules_installdu_args = { "Username", "Password", "ExecutionEnvRef", + "AutoRestart.Enable", NULL } }; @@ -834,8 +737,8 @@ static int get_operate_args_SoftwareModules_InstallDU(char *refparam, struct dmc static int operate_SoftwareModules_InstallDU(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action) { - unsigned int eeid = 0; - json_object *res = NULL; + char *env = ""; + char *autostart = "false"; char *url = dmjson_get_value((json_object *)value, 1, "URL"); if (url[0] == '\0') @@ -845,29 +748,33 @@ static int operate_SoftwareModules_InstallDU(char *refparam, struct dmctx *ctx, char *username = dmjson_get_value((json_object *)value, 1, "Username"); char *password = dmjson_get_value((json_object *)value, 1, "Password"); char *environment = dmjson_get_value((json_object *)value, 1, "ExecutionEnvRef"); - if (DM_STRLEN(environment) == 0) { - eeid = 1; - } else { - sscanf(environment, "Device.SoftwareModules.ExecEnv.%u", &eeid); - } - if (eeid == 0) - return USP_FAULT_COMMAND_FAILURE; + if (DM_STRLEN(environment) != 0) + adm_entry_get_linker_value(ctx, environment, &env); - char eeid_str[16] = {0}; - snprintf(eeid_str, sizeof(eeid_str), "%u", eeid); + autostart = dmjson_get_value((json_object *)value, 1, "AutoRestart.Enable"); - dmubus_call("swmodules", "du_install", UBUS_ARGS{ + dmubus_call_set("swmodules", "du_install", UBUS_ARGS{ {"url", url, String}, {"uuid", uuid, String}, {"username", username, String}, {"password", password, String}, - {"eeid", eeid_str, Integer}}, - 5, - &res); + {"execenv", env, String}, + {"autorestart", autostart, Boolean}}, + 6); - char *status = dmjson_get_value(res, 1, "status"); - return (strcmp(status, "true") == 0) ? 0 : USP_FAULT_COMMAND_FAILURE; + return 0; +} + +#if 0 +static int operate_SoftwareModulesExecEnv_Reset(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action) +{ + return USP_FAULT_COMMAND_FAILURE; +} + +static int operate_SoftwareModulesExecEnv_SetRunLevel(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action) +{ + return USP_FAULT_COMMAND_FAILURE; } static operation_args softwaremodulesdeploymentunit_update_args = { @@ -1002,6 +909,21 @@ static int get_event_DUStateChagne(char *refparam, struct dmctx *ctx, void *data *value = (char *)&du_state_change_args; return 0; } +#endif + +static event_args ee_restarted_args = { + .param = (const char *[]) { + "RestartTime", + "RestartReason", + NULL + } +}; + +static int get_event_ExecEnvRestarted(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) +{ + *value = (char *)&ee_restarted_args; + return 0; +} /********************************************************************************************************************************** * OBJ & PARAM DEFINITION @@ -1016,50 +938,78 @@ DMOBJ tSWmodObj[] = { /* *** Device.SoftwareModules. *** */ DMOBJ tSoftwareModulesObj[] = { /* OBJ, permission, addobj, delobj, checkdep, browseinstobj, nextdynamicobj, dynamicleaf, nextobj, leaf, linker, bbfdm_type, uniqueKeys*/ -{"ExecEnv", &DMREAD, NULL, NULL, NULL, browseSoftwareModulesExecEnvInst, NULL, NULL, NULL, tSoftwareModulesExecEnvParams, NULL, BBFDM_BOTH, LIST_KEY{"Alias", "Name", NULL}}, +{"ExecEnvClass", &DMREAD, NULL, NULL, NULL, browseSoftwareModulesExecEnvClass, NULL, NULL, tCapabilityObj, tSoftwareModulesExecEnvClassParams, NULL, BBFDM_BOTH, LIST_KEY{"Alias", NULL}}, +{"ExecEnv", &DMREAD, NULL, NULL, NULL, browseSoftwareModulesExecEnvInst, NULL, NULL, NULL, tSoftwareModulesExecEnvParams, get_linker_execenv, BBFDM_BOTH, LIST_KEY{"Alias", "Name", NULL}}, {"DeploymentUnit", &DMREAD, NULL, NULL, NULL, browseSoftwareModulesDeploymentUnitInst, NULL, NULL, NULL, tSoftwareModulesDeploymentUnitParams, NULL, BBFDM_BOTH, LIST_KEY{"UUID", "Version", "ExecutionEnvRef", "Alias", NULL}}, -{"ExecutionUnit", &DMREAD, NULL, NULL, NULL, browseSoftwareModulesExecutionUnitInst, NULL, NULL, NULL, tSoftwareModulesExecutionUnitParams, get_linker_eu, BBFDM_BOTH, LIST_KEY{"EUID", "Alias", NULL}}, +{0} +}; + +DMOBJ tCapabilityObj[] = { +/* OBJ, permission, addobj, delobj, checkdep, browseinstobj, nextdynamicobj, dynamicleaf, nextobj, leaf, linker, bbfdm_type, uniqueKeys*/ +{"Capability", &DMREAD, NULL, NULL, NULL, browseSoftwareModulesCapability, NULL, NULL, NULL, tSoftwareModulesCapabilityParams, NULL, BBFDM_BOTH, LIST_KEY{"Alias", NULL}}, +{0} +}; + +DMLEAF tSoftwareModulesExecEnvClassParams[] = { +/* PARAM, permission, type, getvalue, setvalue, bbfdm_type*/ +{"Alias", &DMWRITE, DMT_STRING, get_SoftwareModulesExecEnvClass_Alias, set_SoftwareModulesExecEnvClass_Alias, BBFDM_BOTH}, +{"Name", &DMREAD, DMT_STRING, get_SoftwareModulesExecEnvClass_Name, NULL, BBFDM_BOTH}, +{"Vendor", &DMREAD, DMT_STRING, get_SoftwareModulesExecEnvClass_Vendor, NULL, BBFDM_BOTH}, +{"Version", &DMREAD, DMT_STRING, get_SoftwareModulesExecEnvClass_Version, NULL, BBFDM_BOTH}, +{"DeploymentUnitRef", &DMREAD, DMT_STRING, get_SoftwareModulesExecEnvClass_DURef, NULL, BBFDM_BOTH}, +{"CapabilityNumberOfEntries", &DMREAD, DMT_UNINT, get_SoftwareModules_CapabilityNumberOfEntries, NULL, BBFDM_BOTH}, +{"AddExecEnv()", &DMSYNC, DMT_COMMAND, get_operate_args_SoftwareModules_AddExecEnv, operate_SoftwareModules_AddExecEnv, BBFDM_USP}, {0} }; DMLEAF tSoftwareModulesParams[] = { /* PARAM, permission, type, getvalue, setvalue, bbfdm_type*/ +{"ExecEnvClassNumberOfEntries", &DMREAD, DMT_UNINT, get_SoftwareModules_ExecEnvClassNumberOfEntries, NULL, BBFDM_BOTH}, {"ExecEnvNumberOfEntries", &DMREAD, DMT_UNINT, get_SoftwareModules_ExecEnvNumberOfEntries, NULL, BBFDM_BOTH}, {"DeploymentUnitNumberOfEntries", &DMREAD, DMT_UNINT, get_SoftwareModules_DeploymentUnitNumberOfEntries, NULL, BBFDM_BOTH}, -{"ExecutionUnitNumberOfEntries", &DMREAD, DMT_UNINT, get_SoftwareModules_ExecutionUnitNumberOfEntries, NULL, BBFDM_BOTH}, {"InstallDU()", &DMASYNC, DMT_COMMAND, get_operate_args_SoftwareModules_InstallDU, operate_SoftwareModules_InstallDU, BBFDM_USP}, -{"DUStateChange!", &DMREAD, DMT_EVENT, get_event_DUStateChagne, NULL, BBFDM_USP}, {0} }; -/* *** Device.SoftwareModules.ExecEnv.{i}. *** */ +DMLEAF tSoftwareModulesCapabilityParams[] = { +/* PARAM, permission, type, getvalue, setvalue, bbfdm_type*/ +{"Specification", &DMREAD, DMT_STRING, get_CapabilitySpecification, NULL, BBFDM_BOTH}, +{"SpecificationVersion", &DMREAD, DMT_STRING, get_CapabilitySpecificationVersion, NULL, BBFDM_BOTH}, +{"SpecificationURI", &DMREAD, DMT_STRING, get_CapabilitySpecificationURI, NULL, BBFDM_BOTH}, +{0} +}; + DMLEAF tSoftwareModulesExecEnvParams[] = { /* PARAM, permission, type, getvalue, setvalue, bbfdm_type*/ {"Enable", &DMWRITE, DMT_BOOL, get_SoftwareModulesExecEnv_Enable, set_SoftwareModulesExecEnv_Enable, BBFDM_BOTH}, {"Status", &DMREAD, DMT_STRING, get_SoftwareModulesExecEnv_Status, NULL, BBFDM_BOTH}, -{"Reset", &DMWRITE, DMT_BOOL, get_SoftwareModulesExecEnv_Reset, set_SoftwareModulesExecEnv_Reset, BBFDM_CWMP}, {"Alias", &DMWRITE, DMT_STRING, get_SoftwareModulesExecEnv_Alias, set_SoftwareModulesExecEnv_Alias, BBFDM_BOTH}, {"Name", &DMREAD, DMT_STRING, get_SoftwareModulesExecEnv_Name, NULL, BBFDM_BOTH}, {"Type", &DMREAD, DMT_STRING, get_SoftwareModulesExecEnv_Type, NULL, BBFDM_BOTH}, {"InitialRunLevel", &DMWRITE, DMT_UNINT, get_SoftwareModulesExecEnv_InitialRunLevel, set_SoftwareModulesExecEnv_InitialRunLevel, BBFDM_BOTH}, -{"RequestedRunLevel", &DMWRITE, DMT_INT, get_SoftwareModulesExecEnv_RequestedRunLevel, set_SoftwareModulesExecEnv_RequestedRunLevel, BBFDM_CWMP}, {"CurrentRunLevel", &DMREAD, DMT_INT, get_SoftwareModulesExecEnv_CurrentRunLevel, NULL, BBFDM_BOTH}, {"InitialExecutionUnitRunLevel", &DMWRITE, DMT_INT, get_SoftwareModulesExecEnv_InitialExecutionUnitRunLevel, set_SoftwareModulesExecEnv_InitialExecutionUnitRunLevel, BBFDM_BOTH}, {"Vendor", &DMREAD, DMT_STRING, get_SoftwareModulesExecEnv_Vendor, NULL, BBFDM_BOTH}, {"Version", &DMREAD, DMT_STRING, get_SoftwareModulesExecEnv_Version, NULL, BBFDM_BOTH}, {"ParentExecEnv", &DMREAD, DMT_STRING, get_SoftwareModulesExecEnv_ParentExecEnv, NULL, BBFDM_BOTH}, -{"AllocatedDiskSpace", &DMREAD, DMT_INT, get_SoftwareModulesExecEnv_AllocatedDiskSpace, NULL, BBFDM_BOTH}, -{"AvailableDiskSpace", &DMREAD, DMT_INT, get_SoftwareModulesExecEnv_AvailableDiskSpace, NULL, BBFDM_BOTH}, -{"AllocatedMemory", &DMREAD, DMT_INT, get_SoftwareModulesExecEnv_AllocatedMemory, NULL, BBFDM_BOTH}, -{"AvailableMemory", &DMREAD, DMT_INT, get_SoftwareModulesExecEnv_AvailableMemory, NULL, BBFDM_BOTH}, +{"RestartReason", &DMREAD, DMT_STRING, get_SoftwareModulesExecEnv_RestartReason, NULL, BBFDM_BOTH}, +{"RestartCount", &DMREAD, DMT_STRING, get_SoftwareModulesExecEnv_RestartCount, NULL, BBFDM_BOTH}, +{"LastRestarted", &DMREAD, DMT_STRING, get_SoftwareModulesExecEnv_LastRestarted, NULL, BBFDM_BOTH}, +//{"AllocatedDiskSpace", &DMREAD, DMT_INT, get_SoftwareModulesExecEnv_AllocatedDiskSpace, NULL, BBFDM_BOTH}, +//{"AvailableDiskSpace", &DMREAD, DMT_INT, get_SoftwareModulesExecEnv_AvailableDiskSpace, NULL, BBFDM_BOTH}, +//{"AllocatedMemory", &DMREAD, DMT_INT, get_SoftwareModulesExecEnv_AllocatedMemory, NULL, BBFDM_BOTH}, +//{"AvailableMemory", &DMREAD, DMT_INT, get_SoftwareModulesExecEnv_AvailableMemory, NULL, BBFDM_BOTH}, //{"ActiveExecutionUnits", &DMREAD, DMT_STRING, get_SoftwareModulesExecEnv_ActiveExecutionUnits, NULL, BBFDM_BOTH}, //{"ProcessorRefList", &DMREAD, DMT_STRING, get_SoftwareModulesExecEnv_ProcessorRefList, NULL, BBFDM_BOTH}, -{"Reset()", &DMSYNC, DMT_COMMAND, NULL, operate_SoftwareModulesExecEnv_Reset, BBFDM_USP}, -{"SetRunLevel()", &DMSYNC, DMT_COMMAND, NULL, operate_SoftwareModulesExecEnv_SetRunLevel, BBFDM_USP}, +{"CreatedAt", &DMREAD, DMT_STRING, get_SoftwareModulesExecEnv_CreatedAt, NULL, BBFDM_BOTH}, +{"ExecEnvClassRef", &DMREAD, DMT_STRING, get_SoftwareModulesExecEnv_ExecEnvClassRef, NULL, BBFDM_BOTH}, +{"SetRunLevel()", &DMSYNC, DMT_COMMAND, get_operate_args_SoftwareModules_SetRunLevel, operate_SoftwareModulesExecEnv_SetRunLevel, BBFDM_USP}, +{"Restart()", &DMASYNC, DMT_COMMAND, get_operate_args_SoftwareModules_Restart, operate_SoftwareModulesExecEnv_Restart, BBFDM_USP}, +{"Remove()", &DMSYNC, DMT_COMMAND, get_operate_args_SoftwareModules_Remove, operate_SoftwareModulesExecEnv_Remove, BBFDM_USP}, +{"Restarted!", &DMREAD, DMT_EVENT, get_event_ExecEnvRestarted, NULL, BBFDM_USP}, {0} }; -/* *** Device.SoftwareModules.DeploymentUnit.{i}. *** */ DMLEAF tSoftwareModulesDeploymentUnitParams[] = { /* PARAM, permission, type, getvalue, setvalue, bbfdm_type*/ {"UUID", &DMREAD, DMT_STRING, get_SoftwareModulesDeploymentUnit_UUID, NULL, BBFDM_BOTH}, @@ -1076,34 +1026,8 @@ DMLEAF tSoftwareModulesDeploymentUnitParams[] = { {"VendorConfigList", &DMREAD, DMT_STRING, get_SoftwareModulesDeploymentUnit_VendorConfigList, NULL, BBFDM_BOTH}, {"ExecutionUnitList", &DMREAD, DMT_STRING, get_SoftwareModulesDeploymentUnit_ExecutionUnitList, NULL, BBFDM_BOTH}, {"ExecutionEnvRef", &DMREAD, DMT_STRING, get_SoftwareModulesDeploymentUnit_ExecutionEnvRef, NULL, BBFDM_BOTH}, +{"Installed", &DMREAD, DMT_STRING, get_SoftwareModulesDeploymentUnit_Installed, NULL, BBFDM_BOTH}, //{"Update()", &DMASYNC, DMT_COMMAND, get_operate_args_SoftwareModulesDeploymentUnit_Update, operate_SoftwareModulesDeploymentUnit_Update, BBFDM_USP}, -{"Uninstall()", &DMASYNC, DMT_COMMAND, NULL, operate_SoftwareModulesDeploymentUnit_Uninstall, BBFDM_USP}, -{0} -}; - -DMLEAF tSoftwareModulesExecutionUnitParams[] = { -/* PARAM, permission, type, getvalue, setvalue, bbfdm_type*/ -{"EUID", &DMREAD, DMT_STRING, get_SoftwareModulesExecutionUnit_EUID, NULL, BBFDM_BOTH}, -{"Alias", &DMWRITE, DMT_STRING, get_SoftwareModulesExecutionUnit_Alias, set_SoftwareModulesExecutionUnit_Alias, BBFDM_BOTH}, -{"Name", &DMREAD, DMT_STRING, get_SoftwareModulesExecutionUnit_Name, NULL, BBFDM_BOTH}, -{"ExecEnvLabel", &DMREAD, DMT_STRING, get_SoftwareModulesExecutionUnit_ExecEnvLabel, NULL, BBFDM_BOTH}, -{"Status", &DMREAD, DMT_STRING, get_SoftwareModulesExecutionUnit_Status, NULL, BBFDM_BOTH}, -{"RequestedState", &DMWRITE, DMT_STRING, get_empty, set_SoftwareModulesExecutionUnit_RequestedState, BBFDM_CWMP}, -{"ExecutionFaultCode", &DMREAD, DMT_STRING, get_SoftwareModulesExecutionUnit_ExecutionFaultCode, NULL, BBFDM_BOTH}, -{"ExecutionFaultMessage", &DMREAD, DMT_STRING, get_SoftwareModulesExecutionUnit_ExecutionFaultMessage, NULL, BBFDM_BOTH}, -{"AutoStart", &DMWRITE, DMT_BOOL, get_SoftwareModulesExecutionUnit_AutoStart, set_SoftwareModulesExecutionUnit_AutoStart, BBFDM_BOTH}, -{"RunLevel", &DMWRITE, DMT_UNINT, get_SoftwareModulesExecutionUnit_RunLevel, set_SoftwareModulesExecutionUnit_RunLevel, BBFDM_BOTH}, -{"Vendor", &DMREAD, DMT_STRING, get_SoftwareModulesExecutionUnit_Vendor, NULL, BBFDM_BOTH}, -{"Version", &DMREAD, DMT_STRING, get_SoftwareModulesExecutionUnit_Version, NULL, BBFDM_BOTH}, -{"Description", &DMREAD, DMT_STRING, get_SoftwareModulesExecutionUnit_Description, NULL, BBFDM_BOTH}, -{"DiskSpaceInUse", &DMREAD, DMT_INT, get_SoftwareModulesExecutionUnit_DiskSpaceInUse, NULL, BBFDM_BOTH}, -{"MemoryInUse", &DMREAD, DMT_INT, get_SoftwareModulesExecutionUnit_MemoryInUse, NULL, BBFDM_BOTH}, -//{"References", &DMREAD, DMT_STRING, get_SoftwareModulesExecutionUnit_References, NULL, BBFDM_BOTH}, -{"AssociatedProcessList", &DMREAD, DMT_STRING, get_SoftwareModulesExecutionUnit_AssociatedProcessList, NULL, BBFDM_BOTH}, -{"VendorLogList", &DMREAD, DMT_STRING, get_SoftwareModulesExecutionUnit_VendorLogList, NULL, BBFDM_BOTH}, -{"VendorConfigList", &DMREAD, DMT_STRING, get_SoftwareModulesExecutionUnit_VendorConfigList, NULL, BBFDM_BOTH}, -//{"SupportedDataModelList", &DMREAD, DMT_STRING, get_SoftwareModulesExecutionUnit_SupportedDataModelList, NULL, BBFDM_CWMP}, -{"ExecutionEnvRef", &DMREAD, DMT_STRING, get_SoftwareModulesExecutionUnit_ExecutionEnvRef, NULL, BBFDM_BOTH}, -{"SetRequestedState()", &DMSYNC, DMT_COMMAND, get_operate_args_SoftwareModulesExecutionUnit_SetRequestedState, operate_SoftwareModulesExecutionUnit_SetRequestedState, BBFDM_USP}, +//{"Uninstall()", &DMASYNC, DMT_COMMAND, NULL, operate_SoftwareModulesDeploymentUnit_Uninstall, BBFDM_USP}, {0} }; diff --git a/src/datamodel.h b/src/datamodel.h index fba0d44..cb91e60 100644 --- a/src/datamodel.h +++ b/src/datamodel.h @@ -15,10 +15,12 @@ DMOBJ tSWmodObj[]; DMOBJ tSoftwareModulesObj[]; +DMOBJ tCapabilityObj[]; DMLEAF tSoftwareModulesParams[]; +DMLEAF tSoftwareModulesExecEnvClassParams[]; +DMLEAF tSoftwareModulesCapabilityParams[]; DMLEAF tSoftwareModulesExecEnvParams[]; DMLEAF tSoftwareModulesDeploymentUnitParams[]; -DMLEAF tSoftwareModulesExecutionUnitParams[]; #endif //__DATAMODEL_H diff --git a/src/opkg_utils.c b/src/opkg_utils.c deleted file mode 100644 index dd2a3c2..0000000 --- a/src/opkg_utils.c +++ /dev/null @@ -1,78 +0,0 @@ -/* - * opkg_utils.c: OPKG utility functions - * - * Copyright (C) 2021-2023 IOPSYS Software Solutions AB. All rights reserved. - * - * Author: Vivek Dutta <vivek.dutta@iopsys.eu> - * - * See LICENSE file for license related information. - */ - -/* -* Description: Opkg does not provide a library to interact with opkg packages, -* utilities written in this file is to provide a wrapper functions. -*/ - -#include "opkg_utils.h" -#include "tools.h" // run_cmd - -int opkg_install_pkg(const char *pkg_name, char *output, int out_len) -{ - char command[1024] = {0}; - - if (pkg_name == NULL) - return 0; - - snprintf(command, sizeof(command), "opkg --force-depends --force-maintainer install %s 2>&1", pkg_name); - - return run_cmd(command, output, out_len); -} - -int opkg_update_pkg(const char *pkg_name, char *output, int out_len) -{ - char command[1024] = {0}; - - if (pkg_name == NULL) - return 0; - - snprintf(command, sizeof(command), "opkg --force-depends --force-maintainer install %s 2>&1", pkg_name); - - return run_cmd(command, output, out_len); -} - -int opkg_remove_pkg(const char *pkg_name, char *output, int out_len) -{ - char command[1024] = {0}; - - if (pkg_name == NULL) - return 0; - - snprintf(command, sizeof(command), "opkg --force-depends remove %s 2>&1", pkg_name); - - return run_cmd(command, output, out_len); -} - -int opkg_get_version(const char *pkg_name, char *buffer, int buf_len) -{ - /* Get Description from package_name.control */ - char pkg_path[128] = {0}; - snprintf(pkg_path, sizeof(pkg_path), "%s/%s.control", OPKG_INFO_PATH, pkg_name); - - FILE *fp = fopen(pkg_path, "r"); - if (fp != NULL) { - char line[256] = {0}; - char *spch = NULL; - - while (fgets(line, sizeof(line), fp) != NULL) { - if ((spch = strstr(line, "Version:"))) { - remove_new_line(spch); - snprintf(buffer, buf_len, "%s", spch+9); - break; - } - } - - fclose(fp); - } - - return 0; -} diff --git a/src/opkg_utils.h b/src/opkg_utils.h deleted file mode 100644 index 6d35f8a..0000000 --- a/src/opkg_utils.h +++ /dev/null @@ -1,20 +0,0 @@ -/* - * opkg_utils.h: OPKG utility functions - * - * Copyright (C) 2021-2023 IOPSYS Software Solutions AB. All rights reserved. - * - * Author: Vivek Dutta <vivek.dutta@iopsys.eu> - * - * See LICENSE file for license related information. - */ - -#ifndef __OPKG_UTILS_H -#define __OPKG_UTILS_H -#include <stdbool.h> - -int opkg_install_pkg(const char *pkg_name, char *output, int out_len); -int opkg_update_pkg(const char *pkg_name, char *output, int out_len); -int opkg_remove_pkg(const char *pkg_name, char *output, int out_len); -int opkg_get_version(const char *pkg_name, char *output, int out_len); - -#endif //__OPKG_UTILS_H diff --git a/src/swmod.c b/src/swmod.c index b3e38d1..7617bd6 100644 --- a/src/swmod.c +++ b/src/swmod.c @@ -15,12 +15,11 @@ #include <libubox/uloop.h> #include <sys/prctl.h> +#include "swmod.h" #include "swmod_uci.h" -#include "swmod_opkg.h" #include "swmod_api.h" #include "tools.h" -#include "swmod_host.h" -#include "swmod.h" + #ifdef SWMOD_LXC #include "swmod_lxc.h" #endif @@ -29,192 +28,36 @@ #include "swmod_crun.h" #endif +#ifdef SWMOD_VERSION +#define version SWMOD_VERSION +#else +#define version "Unknown" +#endif + struct ubus_context *ubus_ctx; -ExecEnv_t g_environments[MAX_ENV] = {0}; ConfigParams swmod_config; enum { - DU_INSTALL_ENV_ID, DU_INSTALL_ENV, DU_INSTALL_UUID, DU_INSTALL_URL, DU_INSTALL_USERNAME, DU_INSTALL_PASSWORD, + DU_AUTO_RESTART, __DU_INSTALL_MAX }; -enum { - DU_UPDATE_ENV_ID, - DU_UPDATE_ENV, - DU_UPDATE_UUID, - DU_UPDATE_URL, - DU_UPDATE_USERNAME, - DU_UPDATE_PASSWORD, - __DU_UPDATE_MAX -}; - -enum { - DU_UNINSTALL_ENV_ID, - DU_UNINSTALL_ENV, - DU_UNINSTALL_NAME, - __DU_UNINSTALL_MAX -}; - -enum { - EU_DU_LIST_ENV_ID, - EU_DU_LIST_ENV, - __EU_DU_LIST_MAX -}; - -enum { - SET_CONFIG_ENV_ID, - SET_CONFIG_ENV, - SET_CONFIG_UUID, - SET_CONFIG_EU_NAME, - SET_CONFIG_PARAM, - SET_CONFIG_VALUE, - __SET_CONFIG_MAX -}; - -enum config_param { - EE_ALIAS, - EE_ENABLE, - DU_ALIAS, - EU_ALIAS, - EU_REQUESTED_STATE, - EU_AUTOSTART, - __CONFIG_PARAM_MAX -}; - -struct param_name { - enum config_param type; - char param_name[MAX_LEN_32]; -}; - -static const struct param_name param[__CONFIG_PARAM_MAX] = { - { EE_ALIAS, "ee_alias" }, - { EE_ENABLE, "ee_enable" }, - { DU_ALIAS, "du_alias" }, - { EU_ALIAS, "eu_alias" }, - { EU_REQUESTED_STATE, "eu_requested_state" }, - { EU_AUTOSTART, "eu_autostart" }, -}; - -static int get_param_type(const char *param_name) -{ - int i; - if (param_name == NULL) - return __CONFIG_PARAM_MAX; - - for (i = 0; i < __CONFIG_PARAM_MAX; i++) { - if (strcmp(param_name, param[i].param_name) == 0) - return param[i].type; - } - - return __CONFIG_PARAM_MAX; -} - -static const struct blobmsg_policy set_config_policy[__SET_CONFIG_MAX] = { - [SET_CONFIG_ENV_ID] = { .name = "eeid", .type = BLOBMSG_TYPE_INT32 }, - [SET_CONFIG_ENV] = { .name = "ee_name", .type = BLOBMSG_TYPE_STRING }, - [SET_CONFIG_UUID] = { .name = "uuid", .type = BLOBMSG_TYPE_STRING }, - [SET_CONFIG_EU_NAME] = { .name = "eu_name", .type = BLOBMSG_TYPE_STRING }, - [SET_CONFIG_PARAM] = { .name = "parameter", .type = BLOBMSG_TYPE_STRING }, - [SET_CONFIG_VALUE] = { .name = "value", .type = BLOBMSG_TYPE_STRING }, -}; - static const struct blobmsg_policy du_install_policy[__DU_INSTALL_MAX] = { - [DU_INSTALL_ENV_ID] = { .name = "eeid", .type = BLOBMSG_TYPE_INT32 }, - [DU_INSTALL_ENV] = { .name = "ee_name", .type = BLOBMSG_TYPE_STRING }, + [DU_INSTALL_ENV] = { .name = "execenv", .type = BLOBMSG_TYPE_STRING }, [DU_INSTALL_UUID] = { .name = "uuid", .type = BLOBMSG_TYPE_STRING }, [DU_INSTALL_URL] = { .name = "url", .type = BLOBMSG_TYPE_STRING }, [DU_INSTALL_USERNAME] = { .name = "username", .type = BLOBMSG_TYPE_STRING }, [DU_INSTALL_PASSWORD] = { .name = "password", .type = BLOBMSG_TYPE_STRING }, + [DU_AUTO_RESTART] = { .name = "autorestart", .type = BLOBMSG_TYPE_BOOL }, }; -static const struct blobmsg_policy du_update_policy[__DU_UPDATE_MAX] = { - [DU_UPDATE_ENV_ID] = { .name = "eeid", .type = BLOBMSG_TYPE_INT32 }, - [DU_UPDATE_ENV] = { .name = "ee_name", .type = BLOBMSG_TYPE_STRING }, - [DU_UPDATE_UUID] = { .name = "uuid", .type = BLOBMSG_TYPE_STRING }, - [DU_UPDATE_URL] = { .name = "url", .type = BLOBMSG_TYPE_STRING }, - [DU_UPDATE_USERNAME] = { .name = "username", .type = BLOBMSG_TYPE_STRING }, - [DU_UPDATE_PASSWORD] = { .name = "password", .type = BLOBMSG_TYPE_STRING }, -}; - -static const struct blobmsg_policy du_uninstall_policy[__DU_UNINSTALL_MAX] = { - [DU_UNINSTALL_ENV_ID] = { .name = "eeid", .type = BLOBMSG_TYPE_INT32 }, - [DU_UNINSTALL_ENV] = { .name = "ee_name", .type = BLOBMSG_TYPE_STRING }, - [DU_UNINSTALL_NAME] = { .name = "du_name", .type = BLOBMSG_TYPE_STRING }, -}; - -static const struct blobmsg_policy eu_du_list_policy[__EU_DU_LIST_MAX] = { - [EU_DU_LIST_ENV_ID] = { .name = "eeid", .type = BLOBMSG_TYPE_INT32 }, - [EU_DU_LIST_ENV] = { .name = "ee_name", .type = BLOBMSG_TYPE_STRING }, -}; - -static void -populate_environments(void) -{ - struct list_head ee_head; - memset(&ee_head, 0, sizeof(struct list_head)); - memset(g_environments, '\0', sizeof(g_environments)); - - INIT_LIST_HEAD(&ee_head); - /* Host system */ - populate_host_system_environment(&ee_head); - - /* Linux containers */ -#ifdef SWMOD_LXC - populate_lxc_environment(&ee_head, swmod_config.lxc_bundle_root); -#endif - - sync_eeid_with_uci(&ee_head, g_environments, swmod_config.lxc_bundle_root); - swmod_delete_ee_list(&ee_head); - - int i; - for (i = 0; i < MAX_ENV; i++) { - if (!g_environments[i].exists) - continue; - - swmod_get_env_info(&g_environments[i]); - } -} - -ExecEnv_t* get_ee_from_eeid(unsigned int eid) -{ - int i; - for (i = 0; i < MAX_ENV; i++) { - if (!g_environments[i].exists) - continue; - - if (eid == g_environments[i].eeid) { - return &g_environments[i]; - } - } - - return NULL; -} - -ExecEnv_t* get_ee_from_name(char *ename) -{ - if (ename == NULL) - return NULL; - - int i; - for (i = 0; i < MAX_ENV; i++) { - if (!g_environments[i].exists) - continue; - - if (strcmp(g_environments[i].name, ename) == 0) { - return &g_environments[i]; - } - } - - return NULL; -} - static int -swmod_environment(struct ubus_context *ctx, struct ubus_object *obj, +swmod_ee_class(struct ubus_context *ctx, struct ubus_object *obj, struct ubus_request_data *req, const char *method, struct blob_attr *msg) { @@ -222,34 +65,23 @@ swmod_environment(struct ubus_context *ctx, struct ubus_object *obj, void *a, *t; int i; - populate_environments(); - memset(&bb, 0, sizeof(struct blob_buf)); blob_buf_init(&bb, 0); - a = blobmsg_open_array(&bb, "environment"); + blobmsg_add_string(&bb, "name", swmod_config.ee_class_name); + blobmsg_add_string(&bb, "vendor", swmod_config.ee_class_vendor); + blobmsg_add_string(&bb, "version", swmod_config.ee_class_version); + + a = blobmsg_open_array(&bb, "capabilities"); - for (i = 0; i < MAX_ENV; i++) { - if (!g_environments[i].exists) + for (i = 0; i < DU_TYPE_MAX; i++) { + if (strlen(swmod_config.ee_cap[i].spec) == 0) continue; t = blobmsg_open_table(&bb, ""); - - blobmsg_add_string(&bb, "ee_name", g_environments[i].name); - blobmsg_add_string(&bb, "ee_alias", g_environments[i].alias); - blobmsg_add_u32(&bb, "eeid", g_environments[i].eeid); - blobmsg_add_string(&bb, "status", g_environments[i].status); - blobmsg_add_u32(&bb, "pause", g_environments[i].pause); - blobmsg_add_u32(&bb, "autoboot", g_environments[i].autoboot); - blobmsg_add_string(&bb, "type", g_environments[i].type); - blobmsg_add_string(&bb, "vendor", g_environments[i].vendor); - blobmsg_add_string(&bb, "version", g_environments[i].version); - blobmsg_add_u64(&bb, "allocated_disk_space", g_environments[i].allocated_disk_space); - blobmsg_add_u64(&bb, "available_disk_space", g_environments[i].available_disk_space); - blobmsg_add_u64(&bb, "allocated_memory", g_environments[i].allocated_memory); - blobmsg_add_u64(&bb, "available_memory", g_environments[i].available_memory); - blobmsg_add_u32(&bb, "parent_ee_ref", g_environments[i].parent_eeid); - + blobmsg_add_string(&bb, "specification", swmod_config.ee_cap[i].spec); + blobmsg_add_string(&bb, "version", swmod_config.ee_cap[i].ver); + blobmsg_add_string(&bb, "uri", swmod_config.ee_cap[i].uri); blobmsg_close_table(&bb, t); } @@ -261,362 +93,12 @@ swmod_environment(struct ubus_context *ctx, struct ubus_object *obj, } static int -swmod_reload_config(struct ubus_context *ctx, struct ubus_object *obj, +swmod_reload(struct ubus_context *ctx, struct ubus_object *obj, struct ubus_request_data *req, const char *method, struct blob_attr *msg) { -#ifdef SWMOD_CRUN - swmod_change_crun_du_state(swmod_config.oci_bundle_root); -#endif - return 0; -} - -static void swmod_perform_package_uninstall(PkgInfo *pkg) -{ - char output[MAX_LEN_1024] = {0}; - ExecEnv_t *env = NULL; - time_t finish; - bool reload_crun = false; - - if (pkg == NULL) { - finish = time(NULL); - snprintf(output, sizeof(output), "Invalid DU arguments"); - swmod_send_event_du_state_change(true, 7002, finish, finish, "", "", - SWMOD_REMOVE, output); - return; - } - - env = get_ee_from_name((char*)pkg->env_name); - if (env == NULL) { - finish = time(NULL); - snprintf(output, sizeof(output), "Invalid ExecEnvReference"); - swmod_send_event_du_state_change(true, 7223, pkg->start, finish, "", "", - SWMOD_REMOVE, output); - return; - } - - /* Now write the DU params in UCI */ - char uci_file[MAX_LEN_256] = {0}; - int ret = swmod_ee_uci_init(env, uci_file, sizeof(uci_file)); - if (ret != 0 || strlen(uci_file) == 0) { - finish = time(NULL); - snprintf(output, sizeof(output), "Internal Error"); - swmod_send_event_du_state_change(true, 7002, pkg->start, finish, "", "", - SWMOD_REMOVE, output); - return; - } - - bool found = false; - struct uci_section *s = NULL, *stmp = NULL; - swmod_uci_foreach_section_safe(uci_file, "du_eu_assoc", stmp, s) { - char *ee_name = swmod_uci_get_value_by_section(s, "ee_name"); - char *du_name = swmod_uci_get_value_by_section(s, "name"); - - if (strcmp(ee_name, env->name) == 0 && strcmp(du_name, pkg->url) == 0) { - char *uuid = swmod_uci_get_value_by_section(s, "uuid"); - memset(pkg->uuid, 0, sizeof(pkg->uuid)); - snprintf(pkg->uuid, sizeof(pkg->uuid), "%s", uuid); - found = true; - break; - } - } - - if (found == false) { - finish = time(NULL); - snprintf(output, sizeof(output), "DU (%.64s) not exists in (%s) env", pkg->url, env->name); - swmod_send_event_du_state_change(true, 7002, pkg->start, finish, "", "", - SWMOD_REMOVE, output); - swmod_uci_fini(uci_file); - return; - } - - char start_time[MAX_LEN_32] = {0}; - snprintf(start_time, sizeof(start_time), "%lu", (unsigned long)pkg->start); - - swmod_uci_set_value_by_section(s, "start_time", start_time); - swmod_uci_set_value_by_section(s, "du_status", "Uninstalling"); - - int err = swmod_remove_package(env, pkg, output, sizeof(output)); - - struct du_info info; - memset(&info, 0, sizeof(struct du_info)); - - if (err == 0) { - if (strstr(output, "Removing package") != NULL) { - char *ptr = strstr(output, "Package Name:"); - if (ptr != NULL) { - sscanf(ptr, "Package Name:%63s Version:%63s", info.name, info.version); - } - } else if (strstr(output, "Container") != NULL) { - sscanf(output, "Container %63s uninstalled", info.name); - reload_crun = true; - } else { - err = -1; - } - } - - bool failed = (err) ? true : false; - - if (!failed) { - if (reload_crun) { - // for crun containers - swmod_uci_fini(uci_file); - swmod_uci_commit("crun"); - } else { - // for lxc packages - swmod_uci_delete_by_section(s, NULL, NULL); - swmod_uci_fini(uci_file); - finish = time(NULL); - swmod_send_event_du_state_change(false, 0, pkg->start, finish, pkg->uuid, - info.version, SWMOD_REMOVE, output); - } - } else { - swmod_uci_set_value_by_section(s, "du_status", "Installed"); - swmod_uci_fini(uci_file); - finish = time(NULL); - swmod_send_event_du_state_change(true, 7002, pkg->start, finish, pkg->uuid, - info.version, SWMOD_REMOVE, output); - } - -} - -static void swmod_perform_package_install(PkgInfo *pkg) -{ - char output[MAX_LEN_1024] = {0}; - ExecEnv_t *env = NULL; - time_t finish; - bool docker_image = false; - - if (pkg == NULL) { - finish = time(NULL); - snprintf(output, sizeof(output), "Invalid DU arguments"); - swmod_send_event_du_state_change(true, 7002, finish, finish, "", "", - SWMOD_INSTALL, output); - return; - } - - env = get_ee_from_name((char*)pkg->env_name); - if (env == NULL) { - finish = time(NULL); - snprintf(output, sizeof(output), "Invalid ExecEnvReference"); - swmod_send_event_du_state_change(true, 7223, pkg->start, finish, pkg->uuid, "", - SWMOD_INSTALL, output); - return; - } - - char uci_file[MAX_LEN_256] = {0}; - int ret = swmod_ee_uci_init(env, uci_file, sizeof(uci_file)); - if (ret != 0 || strlen(uci_file) == 0) { - finish = time(NULL); - snprintf(output, sizeof(output), "Internal Error"); - swmod_send_event_du_state_change(true, 7002, pkg->start, finish, pkg->uuid, "", - SWMOD_INSTALL, output); - return; - } - - char start_time[MAX_LEN_32] = {0}; - snprintf(start_time, sizeof(start_time), "%lu", (unsigned long)pkg->start); - - struct uci_section *s = swmod_uci_add_section(uci_file, "du_eu_assoc", false); - swmod_uci_set_value_by_section(s, "start_time", start_time); - swmod_uci_set_value_by_section(s, "url", pkg->url); - swmod_uci_set_value_by_section(s, "username", pkg->uname); - swmod_uci_set_value_by_section(s, "password", pkg->psw); - swmod_uci_set_value_by_section(s, "uuid", pkg->uuid); - swmod_uci_set_value_by_section(s, "ee_name", pkg->env_name); - swmod_uci_set_value_by_section(s, "du_status", "Installing"); - - static int incr = 0; - char *duid = generate_duid(true, incr++); - swmod_uci_set_value_by_section(s, "duid", duid); - FREE(duid); - - // set the corresponding section in pkg for further use if any - pkg->section = s; - - // Now perform installation - int err = swmod_install_package(env, pkg, output, sizeof(output)); - - struct du_info info; - memset(&info, 0, sizeof(struct du_info)); - if (err == 0) { - if (strstr(output, "Installing") != NULL) { - sscanf(output, "Installing %63s (%63[^)] to root...", info.name, info.version); - get_opkg_description(env, info.name, info.desc, sizeof(info.desc)); - get_opkg_service_name(env, info.name, info.eu_name, sizeof(info.eu_name)); - snprintf(info.du_type, sizeof(info.du_type), "lxc"); - } else if (strstr(output, "Container") != NULL) { - sscanf(output, "Container %63s to be installed", info.name); - snprintf(info.du_type, sizeof(info.du_type), "crun"); - snprintf(info.eu_name, sizeof(info.eu_name), "%.32s", info.name); - docker_image = true; // installation performed externally - } else if (strstr(output, "Tar") != NULL) { - sscanf(output, "Tar %63s installed", info.name); - snprintf(info.du_type, sizeof(info.du_type), "crun"); - snprintf(info.eu_name, sizeof(info.eu_name), "%.32s", info.name); - } else { - err = -1; - } - } - - bool failed = (err) ? true : false; - - if (!failed) { - // write the DU informations - swmod_uci_set_value_by_section(s, "name", info.name); - swmod_uci_set_value_by_section(s, "version", info.version); - swmod_uci_set_value_by_section(s, "description", info.desc); - swmod_uci_set_value_by_section(s, "type", info.du_type); - swmod_uci_set_value_by_section(s, "autostart", "1"); - swmod_uci_set_value_by_section(s, "requested_state", "Active"); - swmod_uci_set_value_by_section(s, "eu_name", info.eu_name); - - if (docker_image == false) { - // internally handled so need to set status accordingly - swmod_uci_set_value_by_section(s, "du_status", "Installed"); - swmod_uci_delete_by_section(s, "username", pkg->uname); - swmod_uci_delete_by_section(s, "password", pkg->psw); - finish = time(NULL); - swmod_send_event_du_state_change(false, 0, pkg->start, finish, - pkg->uuid, info.version, SWMOD_INSTALL, output); - } - - swmod_uci_fini(uci_file); - - if (strcmp(info.du_type, "crun") == 0) {// for crun containers - swmod_uci_commit("crun"); - } - } else { - PRINT_ERR("DU Installation failed"); - swmod_uci_delete_by_section(s, NULL, NULL); - swmod_uci_fini(uci_file); - finish = time(NULL); - swmod_send_event_du_state_change(true, 7002, pkg->start, finish, pkg->uuid, - info.version, SWMOD_INSTALL, output); - } -} - -static int swmod_perform_du_operation(PkgInfo *pkg, size_t size) -{ - int ret = -1; - int fd[2]; - - if (pkg == NULL) - return ret; - - if (pipe(fd) < 0) - return ret; - - pid_t child; - child = fork(); - if (child == -1) { - PRINT_ERR("fork error"); - return ret; - } else if (child != 0) { - // parent process - close(fd[0]); - write(fd[1], pkg, size); - close(fd[1]); - ret = 0; - } else { - // child process - prctl(PR_SET_NAME, "swmodd_du_operation"); - ubus_shutdown(ubus_ctx); - ubus_ctx = NULL; - uloop_done(); - fclose(stderr); - fclose(stdout); - fclose(stdin); - - close(fd[1]); - PkgInfo p_info; - memset(&p_info, 0, sizeof(PkgInfo)); - int res = read(fd[0], &p_info, sizeof(PkgInfo)); - close(fd[0]); - - if (res == -1) { - PRINT_DEBUG("DU param value read failed"); - exit(EXIT_FAILURE); - } - - PRINT_DEBUG("Perform DU operation: %d", p_info.operation); - ubus_ctx = ubus_connect(NULL); - if (ubus_ctx == NULL) { - PRINT_ERR("Failed to connect UBUS"); - exit(EXIT_FAILURE); - } - - switch (p_info.operation) { - case SWMOD_INSTALL: - swmod_perform_package_install(&p_info); - break; - case SWMOD_UPDATE: - break; - case SWMOD_REMOVE: - swmod_perform_package_uninstall(&p_info); - break; - } - - ubus_free(ubus_ctx); - exit(EXIT_SUCCESS); - } - - return ret; -} - -static int -swmod_du_uninstall(struct ubus_context *ctx, struct ubus_object *obj, - struct ubus_request_data *req, const char *method, - struct blob_attr *msg) -{ - struct blob_attr *tb[__DU_UNINSTALL_MAX] = {NULL}; - char output[MAX_LEN_1024] = {0}; - ExecEnv_t *env = NULL; - time_t finish; - PkgInfo pkg; - - memset(&pkg, 0, sizeof(PkgInfo)); - pkg.start = time(NULL); - - if (blobmsg_parse(du_uninstall_policy, __DU_UNINSTALL_MAX, tb, blob_data(msg), blob_len(msg))) - return UBUS_STATUS_UNKNOWN_ERROR; - - if (!tb[DU_UNINSTALL_NAME]) { - finish = time(NULL); - snprintf(output, sizeof(output), "No DU Name found"); - swmod_send_event_du_state_change(true, 7002, pkg.start, finish, "", "", - SWMOD_REMOVE, output); - return UBUS_STATUS_INVALID_ARGUMENT; - } - - if (tb[DU_UNINSTALL_ENV]) - env = get_ee_from_name(blobmsg_get_string(tb[DU_UNINSTALL_ENV])); - - /* Priority should be given on EID if both EID and ENV name are provided */ - if (tb[DU_UNINSTALL_ENV_ID]) - env = get_ee_from_eeid(blobmsg_get_u32(tb[DU_UNINSTALL_ENV_ID])); - - if (env == NULL) { - finish = time(NULL); - snprintf(output, sizeof(output), "Could not find Execution Environment"); - swmod_send_event_du_state_change(true, 7223, pkg.start, finish, "", "", - SWMOD_REMOVE, output); - return UBUS_STATUS_INVALID_ARGUMENT; - } - - snprintf(pkg.url, sizeof(pkg.url), "%s", blobmsg_get_string(tb[DU_UNINSTALL_NAME])); - snprintf(pkg.env_name, sizeof(pkg.env_name), "%s", env->name); - pkg.operation = SWMOD_REMOVE; - - int ret = swmod_perform_du_operation(&pkg, sizeof(pkg)); - - struct blob_buf bb; - memset(&bb, 0, sizeof(struct blob_buf)); - blob_buf_init(&bb, 0); - blobmsg_add_u8(&bb, "status", ret ? false : true); - ubus_send_reply(ctx, req, bb.head); - blob_buf_free(&bb); - + /* there could be request for execenv add, restart or remove */ + swmod_execenv_actions(); return 0; } @@ -625,480 +107,55 @@ swmod_du_install(struct ubus_context *ctx, struct ubus_object *obj, struct ubus_request_data *req, const char *method, struct blob_attr *msg) { - time_t finish; struct blob_attr *tb[__DU_INSTALL_MAX] = {NULL}; - ExecEnv_t *env = NULL; PkgInfo pkg; - char output[MAX_LEN_1024] = {0}; - - memset(&pkg, 0, sizeof(PkgInfo)); - pkg.start = time(NULL); if (blobmsg_parse(du_install_policy, __DU_INSTALL_MAX, tb, blob_data(msg), blob_len(msg))) return UBUS_STATUS_UNKNOWN_ERROR; - if (tb[DU_INSTALL_ENV]) - env = get_ee_from_name(blobmsg_get_string(tb[DU_INSTALL_ENV])); + memset(&pkg, 0, sizeof(PkgInfo)); - /* Priority should be given on EID if both EID and ENV name are provided */ - if (tb[DU_INSTALL_ENV_ID]) - env = get_ee_from_eeid(blobmsg_get_u32(tb[DU_INSTALL_ENV_ID])); + if (tb[DU_INSTALL_ENV]) + snprintf(pkg.execenv, sizeof(pkg.execenv), "%s", blobmsg_get_string(tb[DU_INSTALL_ENV])); + + if (strlen(pkg.execenv) == 0) { + char *env = swmod_select_env(); + snprintf(pkg.execenv, sizeof(pkg.execenv), "%s", env ? env : ""); + FREE(env); + } - if (tb[DU_INSTALL_UUID]) { + if (tb[DU_INSTALL_UUID]) snprintf(pkg.uuid, sizeof(pkg.uuid), "%s", blobmsg_get_string(tb[DU_INSTALL_UUID])); - if (!valid_uuid(pkg.uuid, swmod_config.lxc_bundle_root, swmod_config.oci_bundle_root)) { - finish = time(NULL); - snprintf(output, sizeof(output), "UUID is not valid"); - swmod_send_event_du_state_change(true, 7002, pkg.start, finish, pkg.uuid, "", - SWMOD_INSTALL, output); - return UBUS_STATUS_INVALID_ARGUMENT; - } - } - // Generate UUID if not provided if (strlen(pkg.uuid) == 0) { - char *id = generate_uuid(); - if (id == NULL) { - finish = time(NULL); - snprintf(output, sizeof(output), "Failed to generate UUID"); - swmod_send_event_du_state_change(true, 7002, pkg.start, finish, "", "", - SWMOD_INSTALL, output); - return UBUS_STATUS_UNKNOWN_ERROR; - } - - snprintf(pkg.uuid, sizeof(pkg.uuid), "%s", id); - free(id); - } - - if (!tb[DU_INSTALL_URL]) { - finish = time(NULL); - snprintf(output, sizeof(output), "No URL provided"); - swmod_send_event_du_state_change(true, 7002, pkg.start, finish, pkg.uuid, "", - SWMOD_INSTALL, output); - return UBUS_STATUS_INVALID_ARGUMENT; - } - - if (env == NULL) { - finish = time(NULL); - snprintf(output, sizeof(output), "Could not find Execution Environment"); - swmod_send_event_du_state_change(true, 7223, pkg.start, finish, pkg.uuid, "", - SWMOD_INSTALL, output); - return UBUS_STATUS_INVALID_ARGUMENT; - } - - snprintf(pkg.url, sizeof(pkg.url), "%s", blobmsg_get_string(tb[DU_INSTALL_URL])); - if (strncmp(pkg.url, "docker://", 9) != 0 && strchr(pkg.url, '@') != NULL) { /* In docker link there could be '@' for specific sha */ - finish = time(NULL); - snprintf(output, sizeof(output), "URL contains user info"); - swmod_send_event_du_state_change(true, 7004, pkg.start, finish, pkg.uuid, "", - SWMOD_INSTALL, output); - return UBUS_STATUS_INVALID_ARGUMENT; + char *uuid = generate_uuid(); + snprintf(pkg.uuid, sizeof(pkg.uuid), "%s", uuid ? uuid : ""); + FREE(uuid); } + if (tb[DU_INSTALL_URL]) + snprintf(pkg.url, sizeof(pkg.url), "%s", blobmsg_get_string(tb[DU_INSTALL_URL])); + if (tb[DU_INSTALL_USERNAME]) snprintf(pkg.uname, sizeof(pkg.uname), "%s", blobmsg_get_string(tb[DU_INSTALL_USERNAME])); if (tb[DU_INSTALL_PASSWORD]) snprintf(pkg.psw, sizeof(pkg.psw), "%s", blobmsg_get_string(tb[DU_INSTALL_PASSWORD])); + + if (tb[DU_AUTO_RESTART]) + pkg.autostart = blobmsg_get_bool(tb[DU_AUTO_RESTART]); - snprintf(pkg.env_name, sizeof(pkg.env_name), "%s", env->name); pkg.operation = SWMOD_INSTALL; - int ret = swmod_perform_du_operation(&pkg, sizeof(pkg)); - - struct blob_buf bb; - memset(&bb, 0, sizeof(struct blob_buf)); - blob_buf_init(&bb, 0); - blobmsg_add_u8(&bb, "status", ret ? false : true); - ubus_send_reply(ctx, req, bb.head); - blob_buf_free(&bb); - - return 0; -} - -static char *get_performed_operation(int action) -{ - switch(action) { - case SWMOD_INSTALL: - return "Install"; - case SWMOD_UPDATE: - return "Update"; - case SWMOD_REMOVE: - return "Uninstall"; - } - - return "Invalid"; -} - -static char *get_current_du_state(int action, bool failed) -{ - switch(action) { - case SWMOD_INSTALL: - if (failed) - return "Failed"; - - return "Installed"; - case SWMOD_UPDATE: - return "Installed"; - case SWMOD_REMOVE: - if (failed) - return "Installed"; - return "UnInstalled"; - } - - return "Invalid"; -} - -void swmod_send_event_du_state_change(bool failed, int code, time_t start, time_t end, - const char *uuid, const char *ver, int action, const char *err) -{ - uint32_t id; - char start_time[MAX_LEN_32] = {0}; - char end_time[MAX_LEN_32] = {0}; - - if (ubus_ctx == NULL) { - return; - } - - strftime(start_time, sizeof(start_time), "%Y-%m-%dT%H:%M:%SZ", gmtime(&start)); - strftime(end_time, sizeof(end_time), "%Y-%m-%dT%H:%M:%SZ", gmtime(&end)); - char *operation = get_performed_operation(action); - char *state = get_current_du_state(action, failed); - - struct blob_buf b; - memset(&b, 0, sizeof(struct blob_buf)); - - blob_buf_init(&b, 0); - blobmsg_add_string(&b, "name", "Device.SoftwareModules.DUStateChange!"); - - void *tbl = blobmsg_open_table(&b, "input"); - blobmsg_add_string(&b, "UUID", uuid); - blobmsg_add_string(&b, "Version", ver); - blobmsg_add_string(&b, "CurrentState", state); - blobmsg_add_string(&b, "Resolved", failed ? "0" : "1"); - blobmsg_add_string(&b, "StartTime", start_time); - blobmsg_add_string(&b, "CompleteTime", end_time); - blobmsg_add_string(&b, "OperationPerformed", operation); - - if (failed) { - blobmsg_add_u32(&b, "Fault.FaultCode", code); - if (err && err[0] != '\0') - blobmsg_add_string(&b, "Fault.FaultString", err); - else - blobmsg_add_string(&b, "Fault.FaultString", "Internal Error"); - } else { - blobmsg_add_u32(&b, "Fault.FaultCode", 0); - blobmsg_add_string(&b, "Fault.FaultString", ""); - } - - blobmsg_close_table(&b, tbl); - - if (!ubus_lookup_id(ubus_ctx, "usp.raw", &id)) - ubus_invoke(ubus_ctx, id, "notify_event", b.head, NULL, NULL, UBUS_TIMEOUT); - - blob_buf_free(&b); - - return; -} - -static int -swmod_du_update(struct ubus_context *ctx, struct ubus_object *obj, - struct ubus_request_data *req, const char *method, - struct blob_attr *msg) -{ - struct blob_buf bb; - memset(&bb, 0, sizeof(struct blob_buf)); - blob_buf_init(&bb, 0); - blobmsg_add_u8(&bb, "status", false); - blobmsg_add_string(&bb, "info", "DU update not supported"); - ubus_send_reply(ctx, req, bb.head); - blob_buf_free(&bb); - - return 0; -} - -static ExecEnv_t* get_ee_from_blob(struct blob_attr *msg) -{ - ExecEnv_t *env = NULL; - struct blob_attr *tb[__EU_DU_LIST_MAX] = {NULL}; - - if (blobmsg_parse(eu_du_list_policy, __EU_DU_LIST_MAX, tb, blob_data(msg), blob_len(msg)) == 0) { - if (tb[EU_DU_LIST_ENV]) { - env = get_ee_from_name(blobmsg_get_string(tb[EU_DU_LIST_ENV])); - } - - /* Priority given to EID if both EID and ENV name are provided */ - if (tb[EU_DU_LIST_ENV_ID]) { - env = get_ee_from_eeid(blobmsg_get_u32(tb[EU_DU_LIST_ENV_ID])); - } - } - - return env; -} - -static void prepare_du_list_result(ExecEnv_t *env, struct blob_buf *bb) -{ - struct uci_section *ss = NULL; - - if (env == NULL) - return; - - if (env->exists == false) - return; - - char uci_file[MAX_LEN_256] = {0}; - int ret = swmod_ee_uci_init(env, uci_file, sizeof(uci_file)); - if (ret != 0 || strlen(uci_file) == 0) { - return; - } - - swmod_uci_foreach_section(uci_file, "du_eu_assoc", ss) { - - const char *ee_name = swmod_uci_get_value_by_section(ss, "ee_name"); - if (strlen(ee_name) == 0) - continue; - - if (strcmp(ee_name, env->name) != 0) - continue; - - void *t = blobmsg_open_table(bb, ""); - - blobmsg_add_string(bb, "du_name", swmod_uci_get_value_by_section(ss, "name")); - blobmsg_add_string(bb, "du_alias", swmod_uci_get_value_by_section(ss, "du_alias")); - blobmsg_add_string(bb, "ee_name", ee_name); - blobmsg_add_u32(bb, "eeid", env->eeid); - blobmsg_add_string(bb, "uuid", swmod_uci_get_value_by_section(ss, "uuid")); - blobmsg_add_string(bb, "duid", swmod_uci_get_value_by_section(ss, "duid")); - blobmsg_add_string(bb, "url", swmod_uci_get_value_by_section(ss, "url")); - blobmsg_add_string(bb, "version", swmod_uci_get_value_by_section(ss, "version")); - blobmsg_add_string(bb, "config", swmod_uci_get_value_by_section(ss, "config")); - blobmsg_add_string(bb, "description", swmod_uci_get_value_by_section(ss, "description")); - blobmsg_add_string(bb, "du_status", swmod_uci_get_value_by_section(ss, "du_status")); - blobmsg_add_string(bb, "eu_name", swmod_uci_get_value_by_section(ss, "eu_name")); - blobmsg_add_string(bb, "vendor", swmod_uci_get_value_by_section(ss, "vendor")); - - blobmsg_close_table(bb, t); - } - - swmod_uci_fini(uci_file); -} - -static int -swmod_du_list(struct ubus_context *ctx, struct ubus_object *obj, - struct ubus_request_data *req, const char *method, - struct blob_attr *msg) -{ - struct blob_buf bb; - void *a; - ExecEnv_t *env = get_ee_from_blob(msg); - - memset(&bb, 0, sizeof(struct blob_buf)); - blob_buf_init(&bb, 0); - - a = blobmsg_open_array(&bb, "deployment_unit"); - - if (env != NULL) { - prepare_du_list_result(env, &bb); - } else { - for (int i = 0; i < MAX_ENV; i++) { - prepare_du_list_result(&g_environments[i], &bb); - } - } - - blobmsg_close_array(&bb, a); - - ubus_send_reply(ctx, req, bb.head); - blob_buf_free(&bb); - return 0; -} - -static void prepare_eu_list_result(ExecEnv_t *env, struct blob_buf *bb) -{ - void *t; - - if (env == NULL) - return; - - if (env->exists == false) - return; - - if (list_empty(&env->eu_list)) - return; - - EuNode *iter = NULL; - - list_for_each_entry(iter, &env->eu_list, list) { - if (iter->eu.eu_exists == false) { - continue; - } - - t = blobmsg_open_table(bb, ""); - - blobmsg_add_string(bb, "eu_name", iter->eu.name); - blobmsg_add_string(bb, "eu_alias", iter->eu.eu_alias); - blobmsg_add_string(bb, "command", iter->eu.command); - blobmsg_add_string(bb, "state", iter->eu.state); - blobmsg_add_string(bb, "config", iter->eu.config); - blobmsg_add_string(bb, "version", iter->eu.version); - blobmsg_add_string(bb, "description", iter->eu.description); - blobmsg_add_string(bb, "ee_name", iter->eu.environment); - blobmsg_add_u32(bb, "eeid", env->eeid); - blobmsg_add_string(bb, "euid", iter->eu.euid); - blobmsg_add_u32(bb, "disk_space", iter->eu.disk_space); - blobmsg_add_u32(bb, "memory_space", iter->eu.memory_space); - blobmsg_add_string(bb, "vendor", iter->eu.vendor); //TODO - blobmsg_add_string(bb, "req_state", iter->eu.req_state); - blobmsg_add_u8(bb, "autostart", iter->eu.autostart); - blobmsg_add_string(bb, "du_name", iter->eu.du_name); - blobmsg_add_string(bb, "fault_code", iter->eu.fault_code); - - blobmsg_close_table(bb, t); - } - - swmod_delete_eu_list(&env->eu_list); -} - -static int -swmod_eu_list(struct ubus_context *ctx, struct ubus_object *obj, - struct ubus_request_data *req, const char *method, - struct blob_attr *msg) -{ - struct blob_buf bb; - void *a; - - ExecEnv_t *env = get_ee_from_blob(msg); - - memset(&bb, 0, sizeof(struct blob_buf)); - blob_buf_init(&bb, 0); - - a = blobmsg_open_array(&bb, "execution_unit"); - - if (env != NULL) { - populate_execution_unit(env); - prepare_eu_list_result(env, &bb); - } else { - for (int i = 0; i < MAX_ENV; i++) { - populate_execution_unit(&g_environments[i]); - prepare_eu_list_result(&g_environments[i], &bb); - } - } - - blobmsg_close_array(&bb, a); - - ubus_send_reply(ctx, req, bb.head); - blob_buf_free(&bb); - return 0; -} - -static int -swmod_set_config(struct ubus_context *ctx, struct ubus_object *obj, - struct ubus_request_data *req, const char *method, - struct blob_attr *msg) -{ - struct blob_buf bb; - struct blob_attr *tb[__SET_CONFIG_MAX] = {NULL}; - char param_name[MAX_LEN_32] = {0}; - ExecEnv_t *env = NULL; - char alias[65] = {0}; - bool enable = false; - - if (blobmsg_parse(set_config_policy, __SET_CONFIG_MAX, tb, blob_data(msg), blob_len(msg)) != 0) { - return UBUS_STATUS_INVALID_ARGUMENT; - } - - if (!tb[SET_CONFIG_PARAM] || !tb[SET_CONFIG_VALUE]) { - return UBUS_STATUS_INVALID_ARGUMENT; - } - - if (tb[SET_CONFIG_ENV]) { - env = get_ee_from_name(blobmsg_get_string(tb[SET_CONFIG_ENV])); - } - - /* Priority should be given on EID if both EID and ENV name are provided */ - if (tb[SET_CONFIG_ENV_ID]) { - env = get_ee_from_eeid(blobmsg_get_u32(tb[SET_CONFIG_ENV_ID])); - } - - if (env == NULL) - return UBUS_STATUS_INVALID_ARGUMENT; - - memset(&bb, 0, sizeof(struct blob_buf)); - blob_buf_init(&bb, 0); - - snprintf(param_name, sizeof(param_name), "%s", blobmsg_get_string(tb[SET_CONFIG_PARAM])); - int param = get_param_type(param_name); - - switch (param) { - case EE_ALIAS: - snprintf(alias, sizeof(alias), "%s", blobmsg_get_string(tb[SET_CONFIG_VALUE])); - swmod_set_ee_alias(env, alias, &bb); - break; - case EE_ENABLE: - enable = uci_str_to_bool(blobmsg_get_string(tb[SET_CONFIG_VALUE])); - enable ? swmod_change_ee_state(env, "start", &bb) : swmod_change_ee_state(env, "stop", &bb); - break; - case DU_ALIAS: - if (!tb[SET_CONFIG_UUID]) { - blob_buf_free(&bb); - return UBUS_STATUS_INVALID_ARGUMENT; - } - - snprintf(alias, sizeof(alias), "%s", blobmsg_get_string(tb[SET_CONFIG_VALUE])); - swmod_set_du_alias(env, blobmsg_get_string(tb[SET_CONFIG_UUID]), alias, &bb); - break; - case EU_ALIAS: - if (!tb[SET_CONFIG_EU_NAME]) { - blob_buf_free(&bb); - return UBUS_STATUS_INVALID_ARGUMENT; - } - - snprintf(alias, sizeof(alias), "%s", blobmsg_get_string(tb[SET_CONFIG_VALUE])); - swmod_set_eu_alias(env, blobmsg_get_string(tb[SET_CONFIG_EU_NAME]), alias, &bb); - break; - case EU_REQUESTED_STATE: - if (!tb[SET_CONFIG_EU_NAME]) { - blob_buf_free(&bb); - return UBUS_STATUS_INVALID_ARGUMENT; - } - - if (strcmp(blobmsg_get_string(tb[SET_CONFIG_VALUE]), "Idle") == 0) { - swmod_set_service_state(env, blobmsg_get_string(tb[SET_CONFIG_EU_NAME]), false, &bb); - } else if (strcmp(blobmsg_get_string(tb[SET_CONFIG_VALUE]), "Active") == 0) { - swmod_set_service_state(env, blobmsg_get_string(tb[SET_CONFIG_EU_NAME]), true, &bb); - } else { - blob_buf_free(&bb); - return UBUS_STATUS_INVALID_ARGUMENT; - } - break; - case EU_AUTOSTART: - if (!tb[SET_CONFIG_EU_NAME]) { - blob_buf_free(&bb); - return UBUS_STATUS_INVALID_ARGUMENT; - } - - enable = uci_str_to_bool(blobmsg_get_string(tb[SET_CONFIG_VALUE])); - swmod_set_eu_autostart(env, blobmsg_get_string(tb[SET_CONFIG_EU_NAME]), enable, &bb); - break; - default: - blob_buf_free(&bb); - return UBUS_STATUS_INVALID_ARGUMENT; - } - - ubus_send_reply(ctx, req, bb.head); - blob_buf_free(&bb); + swmod_perform_du_operation(ubus_ctx, &pkg, sizeof(pkg)); return 0; } static const struct ubus_method swmod_object_methods[] = { - UBUS_METHOD_NOARG("ee_list", swmod_environment), - UBUS_METHOD_NOARG("reload", swmod_reload_config), - UBUS_METHOD("du_list", swmod_du_list, eu_du_list_policy), - UBUS_METHOD("eu_list", swmod_eu_list, eu_du_list_policy), + UBUS_METHOD_NOARG("ee_class", swmod_ee_class), + UBUS_METHOD_NOARG("reload", swmod_reload), UBUS_METHOD("du_install", swmod_du_install, du_install_policy), - UBUS_METHOD("du_update", swmod_du_update, du_update_policy), - UBUS_METHOD("du_uninstall", swmod_du_uninstall, du_uninstall_policy), - UBUS_METHOD("set_config", swmod_set_config, set_config_policy), }; static struct ubus_object_type swmod_object_type = UBUS_OBJECT_TYPE("swmodules", swmod_object_methods); @@ -1112,12 +169,39 @@ static struct ubus_object swmod_object = { static int swmod_pre_init(void) { + int ret = -1; + /* get config */ memset(&swmod_config, 0, sizeof(ConfigParams)); - get_swmod_config_params(&swmod_config); - // Populate ExecEnv details - populate_environments(); + if (swmod_uci_init(STD_UCI_PATH) != 0) + return ret; + + struct uci_section *s = NULL; + swmod_uci_foreach_section(SWMOD_UCI_FILE, "globals", s) { + if (strcmp(s->e.name, "globals") == 0) { + const char *vendor = swmod_uci_get_value_by_section(s, "vendor"); + snprintf(swmod_config.ee_class_vendor, MAX_LEN_128, "%s", vendor); + + const char *name = swmod_uci_get_value_by_section(s, "name"); + snprintf(swmod_config.ee_class_name, MAX_LEN_256, "%s", name); + break; + } + } + + swmod_uci_fini(SWMOD_UCI_FILE); + + snprintf(swmod_config.ee_class_version, MAX_LEN_32, "%s", version); + + ret = swmod_check_capability(swmod_config.ee_cap); + if (ret) + return ret; + + // If any du pending uninstallation, do it + swmod_du_pending_uninstallation(); + + // Sync existing envs + swmod_sync_envs(); return 0; } @@ -1174,10 +258,14 @@ int main(int argc, char **argv) return -1; } - swmod_pre_init(); - ubus_add_uloop(ubus_ctx); + ret = swmod_pre_init(); + if (ret) { + fprintf(stderr, "Failed in pre_init\n"); + goto out; + } + ret = swmod_init(ubus_ctx); if (ret) goto out; diff --git a/src/swmod.h b/src/swmod.h index ed93e5e..1f284d2 100644 --- a/src/swmod.h +++ b/src/swmod.h @@ -18,9 +18,6 @@ #include "swmod_common.h" -#define HOST_SYSTEM "OpenWRT_Linux" -#define MAX_ENV 8 //Max Environment -#define MAX_EU 256 //Max Execution Unit #define UBUS_TIMEOUT 5000 // 5 seconds #define MAX_BUFFER_LEN (102400) #define MAX_LEN_16 16 @@ -33,82 +30,37 @@ #define MAX_LEN_1024 1024 typedef enum { - EE_TYPE_UNKNOWN, - EE_TYPE_HOST, - EE_TYPE_LXC, - EE_TYPE_CRUN, - EE_TYPE_MAX -} EE_TYPE_t; + DU_TYPE_CRUN, + DU_TYPE_LXC, + DU_TYPE_MAX +} DU_TYPE_t; typedef struct { - bool exists; - unsigned int parent_eeid; - unsigned int eeid; - EE_TYPE_t ee_type; - int pause; - int autoboot; - unsigned long allocated_disk_space; //AllocatedDiskSpace - unsigned long available_disk_space; //AvailableDiskSpace - unsigned long allocated_memory; //AllocatedMemory - unsigned long available_memory; //AvailableMemory - struct list_head eu_list; - char status[MAX_LEN_32]; //Status - char name[MAX_LEN_32]; //Name - char type[MAX_LEN_64]; //Type - char vendor[MAX_LEN_128]; //Vendor - char version[MAX_LEN_16]; //Version - char alias[MAX_LEN_65]; //Version -} ExecEnv_t; - -typedef struct ExecUnit { - bool eu_exists; - char euid[MAX_LEN_65]; //EUID - int disk_space; //DiskSpaceInUse - int memory_space; //MemoryInUse - char name[MAX_LEN_32]; // //Execution Unit Name - char state[MAX_LEN_32]; // //Execution Unit Name - char command[MAX_LEN_32]; //Execution Unit Command - char vendor[MAX_LEN_128]; //Execution Unit Vendor - char config[MAX_LEN_32]; //Config File - char version[MAX_LEN_32]; //Version - char description[MAX_LEN_1024]; //Description - char environment[MAX_LEN_32]; //Environment Name - char req_state[MAX_LEN_16]; - char du_name[MAX_LEN_64]; // //Deployment Unit Name - char eu_alias[MAX_LEN_65]; - bool autostart; - char fault_code[MAX_LEN_32]; -} ExecUnit; - -typedef struct EuNode { - ExecUnit eu; - struct list_head list; -} EuNode; - -typedef struct ExecEnvNode { - ExecEnv_t env; - struct list_head list; -} ExecEnvNode; + char spec[MAX_LEN_16]; + char ver[MAX_LEN_32]; + char uri[MAX_LEN_256]; +} ExecEnvCap_t; typedef struct swmodConfig { - char oci_bundle_root[MAX_LEN_32]; - char lxc_bundle_root[MAX_LEN_32]; + char ee_class_name[MAX_LEN_256]; + char ee_class_vendor[MAX_LEN_128]; + char ee_class_version[MAX_LEN_32]; + ExecEnvCap_t ee_cap[DU_TYPE_MAX]; } ConfigParams; -struct du_info { - char du_type[MAX_LEN_16]; - char name[MAX_LEN_64]; - char version[MAX_LEN_64]; - char desc[256]; - char eu_name[33]; -}; +typedef struct duInfo { + char du_name[MAX_LEN_256]; + char execenv[MAX_LEN_256]; + char eu_runlevel[6]; + int du_type; +} duInfo_t; + +typedef struct duNode { + duInfo_t du; + struct list_head list; +} duInfoNode_t; extern struct ubus_context *ubus_ctx; -extern ExecEnv_t g_environments[MAX_ENV]; extern ConfigParams swmod_config; -void swmod_send_event_du_state_change(bool failed, int code, time_t start, time_t end, - const char *uuid, const char *ver, int action, const char *err); -ExecEnv_t* get_ee_from_name(char *ename); -ExecEnv_t* get_ee_from_eeid(unsigned int eid); #endif //SWMOD_H diff --git a/src/swmod_api.c b/src/swmod_api.c index ab51e6f..fe9abbf 100644 --- a/src/swmod_api.c +++ b/src/swmod_api.c @@ -13,10 +13,9 @@ * from host or lxc sub-system */ -#include "opkg_utils.h" -#include "swmod_opkg.h" -#include "swmod_host.h" +#include "swmod.h" #include "tools.h" // run_cmd +#include "swmod_uci.h" #ifdef SWMOD_LXC #include "swmod_lxc.h" @@ -26,502 +25,173 @@ #include "swmod_crun.h" #endif -int swmod_run_cmd(ExecEnv_t *ee, char *cmd, char *output, int out_len) +int swmod_get_container_type(const char *du_type) { - /* Get Config from package_name.list */ - int ret = 0; + int i; - if (cmd == NULL || ee->exists == false) { - PRINT_ERR("Either cmd is null or ee is disabled"); + if (!du_type) return -1; - } - - switch(ee->ee_type) { - case EE_TYPE_HOST: - { - ret = run_cmd(cmd, output, out_len); - } - break; - case EE_TYPE_LXC: - { -#ifdef SWMOD_LXC - ret = lxc_run_cmd(ee, cmd, output, out_len); -#endif - } - break; - default: - { - PRINT_ERR("Invalid ee type %d", ee->ee_type); - } - } - - return ret; -} - -int swmod_install_package(ExecEnv_t *env, PkgInfo *pkg, char *output, int outlen) -{ - int ret = -1; - - if (output == NULL) { - PRINT_ERR("output buffer is NULL"); - return ret; - } - - if (pkg == NULL) { - snprintf(output, outlen, "Internal Error"); - return ret; - } - - if (env->exists == false) { - snprintf(output, outlen, "ExecEnv not exists"); - return ret; - } - - PRINT_INFO("Installing [%s] in[%s]", pkg->url, env->name); - switch (env->ee_type) { - case EE_TYPE_HOST: -#ifdef SWMOD_CRUN - ret = swmod_crun_perform_install(pkg, output, outlen); -#endif - break; - case EE_TYPE_LXC: -#ifdef SWMOD_LXC - ret = swmod_lxc_install_update_remove_package(pkg, output, outlen, env->name, SWMOD_INSTALL); -#else - ret = -1; -#endif - break; - default: - ret = -1; + for (i = 0; i < DU_TYPE_MAX; i++) { + if (strcmp(du_type, swmod_config.ee_cap[i].spec) == 0) + return i; } - return ret; + return -1; } -int swmod_update_package(ExecEnv_t *env, PkgInfo *pkg, char *output, int outlen) +bool swmod_du_type_capable(int type) { - int ret = -1; - - if (env == NULL || output == NULL) { - PRINT_ERR("No environment or output buffer"); - return ret; - } - - if (pkg == NULL) { - snprintf(output, outlen, "Internal Error"); - return ret; - } - - if (env->exists == false) { - snprintf(output, outlen, "ExecEnv not exists"); - return ret; - } - - PRINT_INFO("update [%s] in[%s]", pkg->url, env->name); - switch (env->ee_type) { - case EE_TYPE_HOST: -#ifdef SWMOD_CRUN - snprintf(output, outlen, "DU update not supported on Host system"); -#endif - break; - case EE_TYPE_LXC: -#ifdef SWMOD_LXC - ret = swmod_lxc_install_update_remove_package(pkg, output, outlen, env->name, SWMOD_UPDATE); -#else - ret = -1; -#endif - break; - default: - ret = -1; - } + if (strlen(swmod_config.ee_cap[type].spec) != 0) + return true; - return ret; + return false; } -int swmod_remove_package(ExecEnv_t *env, const PkgInfo *pkg, char *output, int outlen) +int swmod_check_capability(ExecEnvCap_t *capab) { int ret = -1; + int i; + char buff[256] = {0}; - if (env == NULL || output == NULL) { - PRINT_ERR("No environment or output buffer"); + if (capab == NULL) return ret; - } - - if (pkg == NULL) { - snprintf(output, outlen, "Internal Error"); - return ret; - } - if (env->exists == false) { - snprintf(output, outlen, "ExecEnv not exists"); - return ret; - } - - PRINT_INFO("remove [%s] from[%s]", pkg->url, env->name); - switch (env->ee_type) { - case EE_TYPE_HOST: -#ifdef SWMOD_CRUN - ret = swmod_crun_perform_remove(pkg->url, output, outlen); -#endif - break; - case EE_TYPE_LXC: + for (i = 0; i < DU_TYPE_MAX; i++) { + memset(&capab[i], 0, sizeof(ExecEnvCap_t)); + + switch (i) { + case DU_TYPE_CRUN: + run_cmd("crun -V 2>/dev/null | grep spec:", buff, sizeof(buff)); + if (strlen(buff) != 0) { + sscanf(buff, "spec: %255s", capab[i].ver); + snprintf(capab[i].spec, sizeof(capab[i].spec), "OCIImage"); + snprintf(capab[i].uri, sizeof(capab[i].uri), + "https://github.com/opencontainers/runtime-spec/releases/download/v%s", capab[i].ver); + ret = 0; + } + break; + case DU_TYPE_LXC: #ifdef SWMOD_LXC - ret = swmod_lxc_install_update_remove_package(pkg, output, outlen, env->name, SWMOD_REMOVE); -#else - ret = -1; + snprintf(capab[i].ver, sizeof(capab[i].ver), "%s", swmod_get_lxc_version()); + snprintf(capab[i].spec, sizeof(capab[i].spec), "LXC"); + snprintf(capab[i].uri, sizeof(capab[i].uri), "https://linuxcontainers.org/lxc"); + ret = 0; #endif - break; - default: - ret = -1; + break; + default: + ret = -1; + } } return ret; } -void swmod_change_ee_state(ExecEnv_t *env, char *state, struct blob_buf *bb) -{ - if (bb == NULL) - return; - if (env == NULL || state == NULL) { - blobmsg_add_u8(bb, "status", false); - blobmsg_add_string(bb, "reason", "Insufficient information"); - return; - } - - if (env->exists == false) { - blobmsg_add_u8(bb, "status", false); - blobmsg_add_string(bb, "reason", "ExecEnv not exists"); - return; - } - - switch (env->ee_type) { - case EE_TYPE_HOST: - { - blobmsg_add_u8(bb, "status", false); - blobmsg_add_string(bb, "reason", "request can not be performed on host system"); - break; - } - case EE_TYPE_LXC: - { -#ifdef SWMOD_LXC - int err; - - PRINT_INFO("changing state of [%s] to [%s]", env->name, state); - err = swmod_set_lxc_ee_state(env, state, swmod_config.lxc_bundle_root); - blobmsg_add_u8(bb, "status", (err == 0) ? true : false); - blobmsg_add_string(bb, "reason", ee_state_failure_reason(err)); -#else - blobmsg_add_u8(bb, "status", false); - blobmsg_add_string(bb, "reason", "LXC service not present"); -#endif - break; - } - default: - break; - } - - return; -} - -void populate_execution_unit(ExecEnv_t *env) +void swmod_sync_envs(void) { - if (env == NULL) - return; + struct uci_section *s = NULL; + struct uci_section *d = NULL; + struct list_head du_head; - if (env->exists == false) - return; - - INIT_LIST_HEAD(&env->eu_list); - switch (env->ee_type) { - case EE_TYPE_HOST: - /* Host system */ -#ifdef SWMOD_CRUN - populate_crun_eu(env, swmod_config.oci_bundle_root); -#endif - break; - case EE_TYPE_LXC: - /* Linux containers */ -#ifdef SWMOD_LXC - populate_lxc_eu(env, swmod_config.lxc_bundle_root); -#endif - break; - default: - break; - } -} - -void swmod_get_pid_detail(ExecEnv_t *env, int pid, char *cmdline, int cmd_len, int *vsize) -{ - if (env == NULL || cmdline == NULL || vsize == NULL) + if (swmod_uci_init(STD_UCI_PATH) != 0) return; - switch (env->ee_type) { - case EE_TYPE_LXC: -#ifdef SWMOD_LXC - get_pid_details_lxc(env, pid, cmdline, cmd_len, vsize); -#endif - break; - case EE_TYPE_HOST: - break; - default: - break; - } -} + memset(&du_head, 0, sizeof(struct list_head)); + INIT_LIST_HEAD(&du_head); -void swmod_set_service_state(ExecEnv_t *env, char *name, bool state, struct blob_buf *bb) -{ - if (bb == NULL) { - PRINT_ERR("Status buffer is null"); - return; - } + swmod_uci_foreach_section(SWMOD_UCI_FILE, "execenv", s) { + const char *name = swmod_uci_get_value_by_section(s, "name"); - if (env == NULL) { - PRINT_ERR("No environment info received"); - return; - } + if (!dir_exist(name)) { + swmod_uci_foreach_section(SWMOD_UCI_FILE, "du_eu_assoc", d) { + const char *ee_name = swmod_uci_get_value_by_section(d, "ee_name"); - if (env->exists == false) { - PRINT_ERR("No environment exists"); - return; - } - - if (name == NULL) { - PRINT_ERR("No eu name found"); - return; - } + if (strcmp(ee_name, name) != 0) + continue; - int err = -1; - switch (env->ee_type) { - case EE_TYPE_HOST: -#ifdef SWMOD_CRUN - err = swmod_set_crun_service_state(env, name, state, swmod_config.oci_bundle_root); -#endif - break; - case EE_TYPE_LXC: -#ifdef SWMOD_LXC - err = swmod_set_lxc_service_state(env, name, state, swmod_config.lxc_bundle_root); -#endif - break; - default: - break; - } + swmod_uci_delete_by_section(d, NULL, NULL); + } - if (err != 0) { - blobmsg_add_u8(bb, "status", false); - blobmsg_add_string(bb, "reason", "Internal Error"); - } else { - blobmsg_add_u8(bb, "status", true); - blobmsg_add_string(bb, "reason", ""); + swmod_uci_delete_by_section(s, NULL, NULL); + } else { + /* EE exist in device, check if all DU-EUs are updated and reset run level */ + const char *eu_runlevel = swmod_uci_get_value_by_section(s, "initial_eu_runlevel"); + swmod_reset_ee_runlevel(s); + swmod_get_du_list(name, eu_runlevel, &du_head); + } } - return; -} - -void swmod_get_env_info(ExecEnv_t *env) -{ - if (env == NULL) - return; + swmod_update_du_eu_assoc(&du_head); + swmod_uci_fini(SWMOD_UCI_FILE); - switch (env->ee_type) { - case EE_TYPE_LXC: -#ifdef SWMOD_LXC - get_lxc_environment_info(env, swmod_config.lxc_bundle_root); -#endif - break; - case EE_TYPE_HOST: - get_host_system_info(env); - break; - default: - break; - } + swmod_free_du_list(&du_head); } -void swmod_set_ee_alias(ExecEnv_t *env, const char *alias, struct blob_buf *bb) +void swmod_du_pending_uninstallation(void) { + struct uci_section *s = NULL; - if (bb == NULL) + if (swmod_uci_init(STD_UCI_PATH) != 0) return; - if (env == NULL || alias == NULL) { - blobmsg_add_u8(bb, "status", false); - blobmsg_add_string(bb, "reason", "Insufficient information"); - return; - } - - if (env->exists == false) { - blobmsg_add_u8(bb, "status", false); - blobmsg_add_string(bb, "reason", "ExecEnv not exists"); - return; - } + swmod_uci_foreach_section(SWMOD_UCI_FILE, "du_eu_assoc", s) { + const char *status = swmod_uci_get_value_by_section(s, "status"); - switch (env->ee_type) { - case EE_TYPE_HOST: - blobmsg_add_u8(bb, "status", false); - blobmsg_add_string(bb, "reason", "Set alias for Host is not allowed"); - break; - case EE_TYPE_LXC: - { -#ifdef SWMOD_LXC - int ret = set_lxc_alias(env->name, alias, swmod_config.lxc_bundle_root); - if (ret != 0) { - blobmsg_add_u8(bb, "status", false); - blobmsg_add_string(bb, "reason", "ExecEnv is unknown"); - } else { - blobmsg_add_u8(bb, "status", true); - blobmsg_add_string(bb, "reason", ""); + if (strcmp(status, "Uninstalling") == 0) { + swmod_du_remove(s); } -#else - blobmsg_add_u8(bb, "status", false); - blobmsg_add_string(bb, "reason", "ExecEnv is unknown"); -#endif - } - break; - default: - blobmsg_add_u8(bb, "status", false); - blobmsg_add_string(bb, "reason", "ExecEnv is unknown"); } - return; + swmod_uci_fini(SWMOD_UCI_FILE); } -void swmod_set_du_alias(ExecEnv_t *env, const char *uuid, const char *alias, struct blob_buf *bb) +void swmod_execenv_actions(void) { - int ret = -1; + struct uci_section *s = NULL; - if (bb == NULL) + if (swmod_uci_init(STD_UCI_PATH) != 0) return; - if (env == NULL || alias == NULL || uuid == NULL) { - blobmsg_add_u8(bb, "status", false); - blobmsg_add_string(bb, "reason", "Insufficient information"); - return; - } + swmod_uci_foreach_section(SWMOD_UCI_FILE, "execenv", s) { + const char *action = swmod_uci_get_value_by_section(s, "action"); - if (env->exists == false) { - blobmsg_add_u8(bb, "status", false); - blobmsg_add_string(bb, "reason", "ExecEnv not exists"); - return; - } + if (strcmp(action, "add") == 0) { + swmod_execenv_add(s); + continue; + } - switch (env->ee_type) { - case EE_TYPE_HOST: -#ifdef SWMOD_CRUN - ret = set_du_alias_to_config(env->name, uuid, alias, - swmod_config.oci_bundle_root, SWMOD_OCI_DU_UCI); -#endif - break; - case EE_TYPE_LXC: -#ifdef SWMOD_LXC - ret = set_du_alias_to_config(env->name, uuid, alias, - swmod_config.lxc_bundle_root, SWMOD_LXC_DU_UCI); -#endif - break; - default: - PRINT_ERR("Unknown ENV type"); - } + if (strcmp(action, "remove") == 0) { + swmod_execenv_remove(s, false); + continue; + } - if (ret != 0) { - blobmsg_add_u8(bb, "status", false); - blobmsg_add_string(bb, "reason", "DU is unknown"); - } else { - blobmsg_add_u8(bb, "status", true); - blobmsg_add_string(bb, "reason", ""); + if (strcmp(action, "force_remove") == 0) { + swmod_execenv_remove(s, true); + continue; + } } - return; + swmod_uci_fini(SWMOD_UCI_FILE); } -void swmod_set_eu_alias(ExecEnv_t *env, const char *eu_name, const char *alias, struct blob_buf *bb) +void swmod_stop_execunit(const char *env, const char *eu_name, const char *du_type) { - int ret = -1; - - if (bb == NULL) - return; - - if (env == NULL || alias == NULL || eu_name == NULL) { - blobmsg_add_u8(bb, "status", false); - blobmsg_add_string(bb, "reason", "Insufficient information"); + if (!eu_name || !env || !du_type) return; - } - if (env->exists == false) { - blobmsg_add_u8(bb, "status", false); - blobmsg_add_string(bb, "reason", "ExecEnv not exists"); - return; - } + int type = swmod_get_container_type(du_type); - switch (env->ee_type) { - case EE_TYPE_HOST: -#ifdef SWMOD_CRUN - ret = set_eu_alias_to_config(env->name, eu_name, alias, - swmod_config.oci_bundle_root, SWMOD_OCI_DU_UCI); -#endif + switch (type) { + case DU_TYPE_CRUN: + swmod_set_crun_state(eu_name, EU_STOP); break; - case EE_TYPE_LXC: + case DU_TYPE_LXC: #ifdef SWMOD_LXC - ret = set_eu_alias_to_config(env->name, eu_name, alias, - swmod_config.lxc_bundle_root, SWMOD_LXC_DU_UCI); + swmod_set_lxc_state(eu_name, env, EU_STOP); #endif break; - default: - PRINT_ERR("Unknown ENV type"); - } - - if (ret != 0) { - blobmsg_add_u8(bb, "status", false); - blobmsg_add_string(bb, "reason", "EU is unknown"); - } else { - blobmsg_add_u8(bb, "status", true); - blobmsg_add_string(bb, "reason", ""); } return; } -void swmod_set_eu_autostart(ExecEnv_t *env, const char *eu_name, bool enable, struct blob_buf *bb) -{ - int ret = -1; - - if (bb == NULL) - return; - - if (env == NULL || eu_name == NULL) { - blobmsg_add_u8(bb, "status", false); - blobmsg_add_string(bb, "reason", "Insufficient information"); - return; - } - - if (env->exists == false) { - blobmsg_add_u8(bb, "status", false); - blobmsg_add_string(bb, "reason", "ExecEnv not exists"); - return; - } - - switch (env->ee_type) { - case EE_TYPE_HOST: -#ifdef SWMOD_CRUN - ret = set_eu_autostart_to_config(env->name, eu_name, enable, - swmod_config.oci_bundle_root, SWMOD_OCI_DU_UCI); -#endif - break; - case EE_TYPE_LXC: -#ifdef SWMOD_LXC - ret = set_eu_autostart_to_config(env->name, eu_name, enable, - swmod_config.lxc_bundle_root, SWMOD_LXC_DU_UCI); -#endif - break; - default: - PRINT_ERR("Unknown ENV type"); - } - - if (ret != 0) { - blobmsg_add_u8(bb, "status", false); - blobmsg_add_string(bb, "reason", "EU is unknown"); - } else { - blobmsg_add_u8(bb, "status", true); - blobmsg_add_string(bb, "reason", ""); - } - - return; -} diff --git a/src/swmod_api.h b/src/swmod_api.h index 32b93bd..dfe5780 100644 --- a/src/swmod_api.h +++ b/src/swmod_api.h @@ -10,22 +10,14 @@ #ifndef __SWMOD_API_H #define __SWMOD_API_H -#include <stdbool.h> #include "swmod.h" -#include "tools.h" -int swmod_run_cmd(ExecEnv_t *ee, const char *cmd, char *output, int out_len); -int swmod_install_package(ExecEnv_t *env, PkgInfo *pkg, char *output, int outlen); -int swmod_update_package(ExecEnv_t *env, PkgInfo *pkg, char *output, int outlen); -int swmod_remove_package(ExecEnv_t *env, const PkgInfo *pkg, char *output, int outlen); -void swmod_change_ee_state(ExecEnv_t *env, char *state, struct blob_buf *bb); -void populate_execution_unit(ExecEnv_t *env); -void swmod_get_pid_detail(ExecEnv_t *env, int pid, char *cmdline, int cmd_len, int *vsize); -void swmod_set_service_state(ExecEnv_t *env, char *name, bool state, struct blob_buf *bb); -void swmod_get_env_info(ExecEnv_t *env); -void swmod_set_ee_alias(ExecEnv_t *env, const char *alias, struct blob_buf *bb); -void swmod_set_du_alias(ExecEnv_t *env, const char *uuid, const char *alias, struct blob_buf *bb); -void swmod_set_eu_alias(ExecEnv_t *env, const char *eu_name, const char *alias, struct blob_buf *bb); -void swmod_set_eu_autostart(ExecEnv_t *env, const char *eu_name, bool enable, struct blob_buf *bb); +int swmod_check_capability(ExecEnvCap_t *capab); +void swmod_sync_envs(void); +void swmod_execenv_actions(void); +void swmod_du_pending_uninstallation(void); +bool swmod_du_type_capable(int type); +void swmod_stop_execunit(const char *env, const char *eu, const char *du_type); +int swmod_get_container_type(const char *du_type); #endif //__SWMOD_API_H diff --git a/src/swmod_common.h b/src/swmod_common.h index 261119b..8df03fa 100644 --- a/src/swmod_common.h +++ b/src/swmod_common.h @@ -11,12 +11,13 @@ #ifndef SWMOD_COMMON_H #define SWMOD_COMMON_H -#include <uci.h> +#include <stdbool.h> -#define PARENT_EEID 1 -#define PROC_PATH "/proc" -#define DW_TMP_DIR_PATH "/tmp" -#define DW_PKG_LOCAL_PATH DW_TMP_DIR_PATH"/dw_package.ipk" +enum eu_state { + EU_STOP, + EU_START, + __SWMOD_EU_STATE_MAX +}; enum swmod_du_opration_enum { SWMOD_INSTALL, @@ -26,14 +27,16 @@ enum swmod_du_opration_enum { }; typedef struct { - time_t start; char url[2049]; char uname[257]; char psw[257]; char uuid[37]; - char env_name[32]; + char du_name[256]; + char version[32]; + char execenv[256]; + int du_type; int operation; - struct uci_section *section; + bool autostart; } PkgInfo; bool memory_available(unsigned long req_kb, const char *dst); diff --git a/src/swmod_crun.c b/src/swmod_crun.c index bb01720..05304f4 100644 --- a/src/swmod_crun.c +++ b/src/swmod_crun.c @@ -9,747 +9,28 @@ */ #include <stdio.h> -#include <stdbool.h> -#include <unistd.h> -#include <sys/sysinfo.h> -#include <sys/utsname.h> -#include <sys/statvfs.h> +#include <stdlib.h> +#include <string.h> -#include "tools.h" -#include "swmod_uci.h" -#include "swmod_crun.h" #include "swmod_common.h" +#include "swmod_crun.h" +#include "tools.h" -static char* get_container_status(const char *c_name) -{ - if (c_name == NULL) { - return "Error"; - } - - char cmd[MAX_BUFFER_LEN] = {0}; - char output[MAX_BUFFER_LEN] = {0}; - - snprintf(cmd, sizeof(cmd), "crun state %s 2>&1 | grep status", c_name); - - if (run_cmd(cmd, output, sizeof(output)) != 0) { - PRINT_ERR("Failed to read container status"); - return "Error"; - } - - if (strlen(output) == 0) { - PRINT_ERR("Container status not found"); - return "Error"; - } - - if (strstr(output, "error opening") != NULL) { - return "Error"; - } - - if (strstr(output, "\"status\": \"created\"") != NULL) { - return "Disabled"; - } - - if (strstr(output, "\"status\": \"paused\"") != NULL) { - return "Paused"; - } - - return "Up"; -} - -static int get_container_pid(const char *c_name) -{ - if (c_name == NULL) { - return -1; - } - - char cmd[MAX_BUFFER_LEN] = {0}; - char output[MAX_BUFFER_LEN] = {0}; - - snprintf(cmd, sizeof(cmd), "crun state %s 2>&1 | grep pid", c_name); - - if (run_cmd(cmd, output, sizeof(output)) != 0) { - PRINT_ERR("Failed to read container pid"); - return -1; - } - - if (strlen(output) == 0) { - PRINT_DEBUG("Container pid not found"); - return -1; - } - - if (strstr(output, "error opening") != NULL) { - return -1; - } - - int pid = -1; - char *tmp = strstr(output, "\"pid\":"); - if (tmp != NULL) { - sscanf(tmp, "\"pid\": %d", &pid); - } - - return pid; -} - -static int crun_run_cmd(const char *ct_name, char *sub_cmd, char *output, size_t len) -{ - if (ct_name == NULL || sub_cmd == NULL) { - return -1; - } - - char cmd[MAX_BUFFER_LEN] = {0}; - if ((strlen(ct_name) + strlen(sub_cmd) + 11) >= sizeof(cmd)) { - PRINT_ERR("Command length too large"); - return -1; - } - - snprintf(cmd, sizeof(cmd), "crun exec %s %s", ct_name, sub_cmd); - return run_cmd(cmd, output, len); -} - -static void get_memory_info(const char *ct_name, int *avail_mem, int *alloc_mem) -{ - char cmd[1024] = {0}; - char output[1024] = {0}; - - if (ct_name == NULL) { - return; - } - - snprintf(cmd, sizeof(cmd), "grep MemTotal /proc/meminfo"); - if (crun_run_cmd(ct_name, cmd, output, sizeof(output)) != 0) { - return; - } - - if (strstr(output, "MemTotal:") != NULL) { - sscanf(output, "MemTotal:%d", alloc_mem); - } - - memset(output, 0, sizeof(output)); - snprintf(cmd, sizeof(cmd), "grep MemFree /proc/meminfo"); - if (crun_run_cmd(ct_name, cmd, output, sizeof(output)) != 0) { - return; - } - - if (strstr(output, "MemFree:") != NULL) { - sscanf(output, "MemFree:%d", avail_mem); - } -} - -static void get_disk_space_info(const char *ct_name, int *avail_disk, int *alloc_disk) -{ - char cmd[1024] = {0}; - char output[MAX_BUFFER_LEN] = {0}; - - if (ct_name == NULL) { - return; - } - - snprintf(cmd, sizeof(cmd), "df -P / | tail -n +2"); - if (crun_run_cmd(ct_name, cmd, output, sizeof(output)) != 0) { - return; - } - - if (strlen(output) == 0) - return; - - char filesystem[255] = {0}; - int used_disk = 0; - sscanf(output, "%254s %d %d %d", filesystem, alloc_disk, &used_disk, avail_disk); -} - -static void get_host_info(const char *ct_name, char *vendor, int vend_len, char *ver, int ver_len) -{ - char cmd[1024] = {0}; - char output[MAX_BUFFER_LEN] = {0}; - - if (ct_name == NULL || vendor == NULL || ver == NULL) { - return; - } - - snprintf(cmd, sizeof(cmd), "uname -n"); - if (crun_run_cmd(ct_name, cmd, output, sizeof(output)) != 0) { - return; - } - - if (strlen(output) != 0) { - strncpy(vendor, output, vend_len); - remove_new_line(vendor); - } - - memset(output, 0, sizeof(output)); - snprintf(cmd, sizeof(cmd), "uname -r"); - if (crun_run_cmd(ct_name, cmd, output, sizeof(output)) != 0) { - return; - } - - if (strlen(output) != 0) { - strncpy(ver, output, ver_len); - remove_new_line(ver); - } -} - -static bool validate_args(const char *url, char *output, int out_len) -{ - if (output == NULL || out_len <= 0) { - return false; - } - - if (url == NULL) { - snprintf(output, out_len, "Package path not given"); - return false; - } - - if (url[0] == '\0') { - snprintf(output, out_len, "Package path not given"); - return false; - } - - return true; -} - -static int get_filename_from_url(const char *url, char *filename, int len) -{ - if (url == NULL || filename == NULL) - return -1; - - memset(filename, 0, len); - - char *tmp = strrchr(url, '/'); - if (tmp == NULL) { - tmp = (char*)url; - } else { - if (tmp == (url + strlen(url) - 1)) { - return -1; - } else { - tmp = tmp + 1; - } - } - - snprintf(filename, len, "%s", tmp); - char *tmp2 = strchr(filename, ':'); - if (tmp2) - *tmp2 = '\0'; - - tmp2 = strchr(filename, '.'); - if (tmp2) - *tmp2 = '\0'; - - tmp2 = strchr(filename, '@'); /* for docker image there could be @sha after name */ - if (tmp2) - *tmp2 = '\0'; - - return 0; -} - -static int swmod_crun_install_tar_package(const PkgInfo *pkg, const char *name, char *output, int out_len) -{ - int ret = -1; - char package_path[2049] = {0}; - bool remote_file = false; - - if (pkg == NULL || name == NULL || output == NULL) { - return ret; - } - - if (strlen(pkg->url) == 0) { - snprintf(output, out_len, "Package URL not found"); - return ret; - } - - if (strlen(pkg->uuid) == 0) { - snprintf(output, out_len, "Package UUID not found"); - return ret; - } - - if (pkg->section == NULL) { - snprintf(output, out_len, "Internal Error"); - return ret; - } - - swmod_uci_set_value_by_section(pkg->section, "du_status", "Installing_start"); - - if (strstr(pkg->url, "file://") != NULL) { - //local package - snprintf(package_path, sizeof(package_path), "%s", pkg->url+6); - if (strlen(package_path) == 0) { - snprintf(output, out_len, "Invalid package name"); - return ret; - } - - // get filesize - unsigned long size = get_file_size_kb(package_path); - if (size == 0) { - snprintf(output, out_len, "Failed to read package info or package not exist"); - return ret; - } - - /* we need atleast twice the pkg size space in bundle root to extract the tar */ - if (!memory_available(size * 2, swmod_config.oci_bundle_root)) { - snprintf(output, out_len, "No enough space in system to extract the package"); - return ret; - } - } else { - remote_file = true; - unsigned long size = get_remote_file_size(pkg->url, pkg->uname, pkg->psw); - if (size == 0) { - snprintf(output, out_len, "Failed to read package info or package is empty"); - return ret; - } - - if (!memory_available(size, DW_TMP_DIR_PATH)) { - snprintf(output, out_len, "No enough space in system to download the package"); - return ret; - } - - /* we need atleast twice the pkg size space in bundle root to extract the tar */ - if (!memory_available(size * 2, swmod_config.oci_bundle_root)) { - snprintf(output, out_len, "No enough space in system to extract the package"); - return ret; - } - - snprintf(package_path, sizeof(package_path), "%s/%s.tar", DW_TMP_DIR_PATH, name); - if (0 != download_remote_package(pkg->url, pkg->uname, pkg->psw, package_path)) { - snprintf(output, out_len, "Package download failed from %s", pkg->url); - goto err; - } - } - - char bundle_path[MAX_LEN_1024] = {0}; - snprintf(bundle_path, sizeof(bundle_path), "%s/%s", swmod_config.oci_bundle_root, name); - if (dir_exist(bundle_path)) { - snprintf(output, out_len, "DU name %s already exist", name); - goto err; - } - - if (!create_dir(bundle_path)) { - snprintf(output, out_len, "Failed to create dir %s", bundle_path); - goto err; - } - - char cmd[MAX_LEN_256] = {0}; - snprintf(cmd, sizeof(cmd), "tar -xf %s -C %s", package_path, bundle_path); - if (0 != run_cmd_no_output(cmd)) { - snprintf(output, out_len, "Failed to extract package at %s", bundle_path); - snprintf(cmd, sizeof(cmd), "rm -rf %s", bundle_path); - run_cmd_no_output(cmd); - goto err; - } - - ret = 0; - snprintf(output, out_len, "Tar %s installed", name); - -err: - if (remote_file && (strlen(package_path) != 0) && file_exists(package_path)) - remove(package_path); - - return ret; -} - -struct service_input_arg { - const char *instance; - char *error; - int buf_size; -}; - -void read_fault_code(struct ubus_request *req, int type, struct blob_attr *msg) -{ - if (req == NULL || msg == NULL) - return; - - struct service_input_arg *args = (struct service_input_arg *)req->priv; - if (args == NULL) - return; - - if (args->instance == NULL || args->error == NULL) - return; - - snprintf(args->error, args->buf_size, "NoFault"); - - enum { - SERVICE_NAME, - __SERVICE_MAX - }; - - enum { - P_RUN, - __P_MAX - }; - - const struct blobmsg_policy service_policy[__SERVICE_MAX] = { - [SERVICE_NAME] = { .name = "crun", .type = BLOBMSG_TYPE_TABLE }, - }; - - const struct blobmsg_policy p[__P_MAX] = { - [P_RUN] = { .name = "running", .type = BLOBMSG_TYPE_BOOL }, - }; - - struct blob_attr *tb[ARRAY_SIZE(service_policy)]; - - if (blobmsg_parse(service_policy, ARRAY_SIZE(service_policy), tb, blob_data(msg), blob_len(msg)) != 0) - return; - - if (!tb[SERVICE_NAME]) - return; - - struct blob_attr *data = tb[SERVICE_NAME]; - struct blob_attr *instances, *inst; - size_t rem, rem2; - - blobmsg_for_each_attr(instances, data, rem) { - if (strcmp(blobmsg_name(instances), "instances") != 0) - continue; - - blobmsg_for_each_attr(inst, instances, rem2) { - if (strcmp(blobmsg_name(inst), args->instance) != 0) - continue; - - struct blob_attr *tb2[__P_MAX] = {NULL}; - if (blobmsg_parse(p, __P_MAX, tb2, blobmsg_data(inst), blobmsg_len(inst)) != 0) - break; - - if (tb2[P_RUN] && blobmsg_get_bool(tb2[P_RUN]) == false) - snprintf(args->error, args->buf_size, "FailureOnStart"); - - break; - } - break; - } -} - -static void get_crun_fault_code(const char *name, char *fault, int buf_len) -{ - uint32_t id; - struct service_input_arg input; - - if (fault == NULL) - return; - - memset(fault, 0, buf_len); - - if (name == NULL) - return; - - if (ubus_ctx == NULL) - return; - - memset(&input, 0, sizeof(struct service_input_arg)); - input.instance = name; - input.error = fault; - input.buf_size = buf_len; - - struct blob_buf b; - memset(&b, 0, sizeof(struct blob_buf)); - - blob_buf_init(&b, 0); - blobmsg_add_string(&b, "name", "crun"); - - if (!ubus_lookup_id(ubus_ctx, "service", &id)) - ubus_invoke(ubus_ctx, id, "list", b.head, read_fault_code, &input, UBUS_TIMEOUT); - - blob_buf_free(&b); -} - -int swmod_crun_perform_install(const PkgInfo *pkg, char *output, int out_len) -{ - int ret = -1; - char filename[64] = {0}; - - if (output == NULL) - return ret; - - if (pkg == NULL) { - snprintf(output, out_len, "Internal Error"); - return ret; - } - - if (validate_args(pkg->url, output, out_len) == false) - return ret; - - if (get_filename_from_url(pkg->url, filename, sizeof(filename)) != 0) { - snprintf(output, out_len, "Invalid filename in %s", pkg->url); - return ret; - } - - char bundle_path[MAX_LEN_1024] = {0}; - snprintf(bundle_path, sizeof(bundle_path), "%s/%s", swmod_config.oci_bundle_root, filename); - - if (dir_exist(bundle_path)) { - snprintf(output, out_len, "DU name %s already exist", filename); - return ret; - } - - snprintf(output, out_len, "Container %s to be installed", filename); - ret = 0; - - char *tmp = strrchr(pkg->url, '.'); - if (tmp != NULL && strcmp(tmp, ".tar") == 0) { - /* This is a tar package so need to extract */ - PRINT_DEBUG("Doing DU install with tar"); - ret = swmod_crun_install_tar_package(pkg, filename, output, out_len); - } - - return ret; -} - -int swmod_crun_perform_remove(const char *ct_name, char *output, int out_len) -{ - (void)ct_name; - if (output == NULL || out_len == 0) - return -1; - - // Bundle will be deleted externally - snprintf(output, out_len, "Container %s uninstalled", ct_name); - return 0; -} - -void populate_crun_eu(ExecEnv_t *ee, const char *oci_uci_path) -{ - if (ee == NULL) { - PRINT_ERR("No environment information given"); - return; - } - - if (ee->name[0] == '\0') { - PRINT_ERR("Environment name unknown"); - return; - } - - if (oci_uci_path == NULL || strlen(oci_uci_path) == 0) { - PRINT_ERR("OCI DU UCI file unknown"); - return; - } - - if (0 != swmod_uci_init(oci_uci_path)) { - return; - } - - struct uci_section *s = NULL, *stmp = NULL; - swmod_uci_foreach_section_safe(SWMOD_OCI_DU_UCI, "du_eu_assoc", stmp, s) { - const char *type = swmod_uci_get_value_by_section(s, "type"); - const char *status = swmod_uci_get_value_by_section(s, "du_status"); - if (strcmp(type, "crun") == 0 && strcmp(status, "Installed") == 0) { - ExecUnit new; - memset(&new, 0, sizeof(ExecUnit)); - new.eu_exists = true; - - const char *name = swmod_uci_get_value_by_section(s, "eu_name"); - swmod_strncpy(new.name, name, sizeof(new.name)); - - const char *alias = swmod_uci_get_value_by_section(s, "eu_alias"); - swmod_strncpy(new.eu_alias, alias, sizeof(new.eu_alias)); - - const char *ee_name = swmod_uci_get_value_by_section(s, "ee_name"); - swmod_strncpy(new.environment, ee_name, sizeof(new.environment)); - - const char *du_name = swmod_uci_get_value_by_section(s, "name"); - swmod_strncpy(new.du_name, du_name, sizeof(new.du_name)); - - const char *req_state = swmod_uci_get_value_by_section(s, "requested_state"); - swmod_strncpy(new.req_state, req_state, sizeof(new.req_state)); - - const char *auto_start = swmod_uci_get_value_by_section(s, "autostart"); - new.autostart = uci_str_to_bool(auto_start); - - int pid = get_container_pid(name); - if (pid == -1) { - snprintf(new.euid, sizeof(new.euid), "Unknown"); - } else { - snprintf(new.euid, sizeof(new.euid), "%d", pid); - } - - char *ct_status = get_container_status(name); - if (strcmp(ct_status, "Up") == 0) { - swmod_strncpy(new.state, "Active", sizeof(new.state)); - - /* get memory space limits */ - int avail_memory = 0, alloc_memory = 0; - get_memory_info(name, &avail_memory, &alloc_memory); - new.memory_space = alloc_memory; - - /* get disk space info */ - int avail_disk = 0, alloc_disk = 0; - get_disk_space_info(name, &avail_disk, &alloc_disk); - new.disk_space = alloc_disk; - - /* get vendor and version info */ - get_host_info(name, new.vendor, sizeof(new.vendor), new.version, sizeof(new.version)); - } else { - swmod_strncpy(new.state, "Idle", sizeof(new.state)); - } - - swmod_strncpy(new.description, "This is a CRUN container", sizeof(new.description)); - get_crun_fault_code(name, new.fault_code, sizeof(new.fault_code)); - swmod_add_eu_in_list(&ee->eu_list, &new); - } - } - - swmod_uci_fini(SWMOD_OCI_DU_UCI); -} - -int swmod_set_crun_service_state(ExecEnv_t *ee, char *eu, bool state, const char *oci_uci_path) -{ - int ret = -1; - - if (ee == NULL) { - PRINT_ERR("No environment information given"); - return ret; - } - - if (ee->name[0] == '\0') { - PRINT_ERR("Environment name unknown"); - return ret; - } - - if (eu == NULL) { - PRINT_ERR("No eu name information"); - return ret; - } - - if (oci_uci_path == NULL || strlen(oci_uci_path) == 0) { - PRINT_ERR("OCI DU uci path unknown"); - return ret; - } - - if (0 != swmod_uci_init(oci_uci_path)) { - return ret; - } - - struct uci_section *s = NULL, *stmp = NULL; - swmod_uci_foreach_section_safe(SWMOD_OCI_DU_UCI, "du_eu_assoc", stmp, s) { - const char *name = swmod_uci_get_value_by_section(s, "eu_name"); - const char *ee_name = swmod_uci_get_value_by_section(s, "ee_name"); - - if (strcmp(name, eu) == 0 && strcmp(ee->name, ee_name) == 0) { - if (state) { - swmod_uci_set_value_by_section(s, "requested_state", "Active"); - ret = 0; - } else { - swmod_uci_set_value_by_section(s, "requested_state", "Idle"); - ret = 0; - } - - break; - } - } - - swmod_uci_fini(SWMOD_OCI_DU_UCI); - if (ret == 0) { - swmod_uci_commit("crun"); - } - - return ret; -} - -enum du_status { - E_DU_INSTALL_SUCCESS, - E_DU_INSTALL_FAILED, - E_DU_UNINSTALL_SUCCESS, - E_DU_UNINSTALL_FAILED, - __DU_STATUS_MAX -}; - -char du_status_string[][MAX_LEN_64] = { - "Installing_success", - "Installing_failed", - "Uninstalling_success", - "Uninstalling_failed", -}; - -static int get_du_status(const char *str) +void swmod_set_crun_state(const char *cont, int state) { - int i; - - if (str == NULL) - return __DU_STATUS_MAX; + char cmd[2056] = {0}; - for (i = E_DU_INSTALL_SUCCESS; i < __DU_STATUS_MAX; i++) { - if (strcmp(str, du_status_string[i]) == 0) - return i; - } - - return __DU_STATUS_MAX; -} - -static void swmod_handle_crun_du_state(struct uci_section *s) -{ - if (s == NULL) + if (!cont) return; - int code = 7002; - const char *fault_code = NULL, *fault_str = NULL; - - const char *s_time = swmod_uci_get_value_by_section(s, "start_time"); - const char *uuid = swmod_uci_get_value_by_section(s, "uuid"); - const char *version = swmod_uci_get_value_by_section(s, "version"); - const char *status = swmod_uci_get_value_by_section(s, "du_status"); - - time_t start_time = convert_str_to_time(s_time); - time_t end_time = time(NULL); - - int state = get_du_status(status); - switch (state) { - case E_DU_INSTALL_SUCCESS: - swmod_uci_set_value_by_section(s, "du_status", "Installed"); - swmod_send_event_du_state_change(false, 0, start_time, end_time, uuid, - version, SWMOD_INSTALL, ""); - break; - case E_DU_INSTALL_FAILED: - PRINT_ERR("DU Installation failed"); - fault_code = swmod_uci_get_value_by_section(s, "fault_code"); - fault_str = swmod_uci_get_value_by_section(s, "fault_string"); - swmod_uci_delete_by_section(s, NULL, NULL); - - if (strlen(fault_code) != 0) - code = (int)strtoul(fault_code, NULL, 10); - - if (strlen(fault_str) == 0) - fault_str = "Internal Error, see log for more details"; - - swmod_send_event_du_state_change(true, code, start_time, end_time, uuid, - version, SWMOD_INSTALL, fault_str); + case EU_STOP: + snprintf(cmd, sizeof(cmd), "crun kill %s 9 2>/dev/null", cont); + run_cmd_no_output(cmd); break; - case E_DU_UNINSTALL_SUCCESS: - swmod_uci_delete_by_section(s, NULL, NULL); - swmod_send_event_du_state_change(false, 0, start_time, end_time, uuid, - version, SWMOD_REMOVE, ""); + case EU_START: break; - case E_DU_UNINSTALL_FAILED: - PRINT_ERR("DU Uninstallation failed"); - fault_code = swmod_uci_get_value_by_section(s, "fault_code"); - fault_str = swmod_uci_get_value_by_section(s, "fault_string"); - swmod_uci_set_value_by_section(s, "du_status", "Installed"); - - if (strlen(fault_code) != 0) - code = (int)strtoul(fault_code, NULL, 10); - - if (strlen(fault_str) == 0) - fault_str = "Internal Error, see log for more details"; - - swmod_send_event_du_state_change(true, code, start_time, end_time, uuid, - version, SWMOD_REMOVE, fault_str); - break; - default: - PRINT_DEBUG("This sate has nothing to do"); } } -void swmod_change_crun_du_state(const char *oci_uci_path) -{ - if (0 != swmod_uci_init(oci_uci_path)) { - return; - } - - struct uci_section *s = NULL, *stmp = NULL; - swmod_uci_foreach_section_safe(SWMOD_OCI_DU_UCI, "du_eu_assoc", stmp, s) { - const char *type = swmod_uci_get_value_by_section(s, "type"); - if (strcmp(type, "crun") != 0) { - continue; - } - - swmod_handle_crun_du_state(s); - } - swmod_uci_fini(SWMOD_OCI_DU_UCI); - return; -} diff --git a/src/swmod_crun.h b/src/swmod_crun.h index 7ed0962..a23e327 100644 --- a/src/swmod_crun.h +++ b/src/swmod_crun.h @@ -13,12 +13,6 @@ #include "swmod_common.h" -int swmod_crun_perform_install(const PkgInfo *pkg, char *output, int out_len); -int swmod_crun_perform_remove(const char *ct_name, char *output, int outlen); -void populate_crun_eu(ExecEnv_t *ee, const char *oci_uci_path); -int swmod_set_crun_service_state(ExecEnv_t *ee, char *eu, bool state, const char *oci_uci_path); -void swmod_perform_crun_install(char *section, int len); -void swmod_change_crun_du_state(const char *oci_uci_path); -void read_fault_code(struct ubus_request *req, int type, struct blob_attr *msg); +void swmod_set_crun_state(const char *cont, int state); #endif // SWMOD_CRUN_H diff --git a/src/swmod_host.c b/src/swmod_host.c deleted file mode 100644 index 74cd87a..0000000 --- a/src/swmod_host.c +++ /dev/null @@ -1,67 +0,0 @@ -/* - * swmod_host.c: SWMOD deamon - * - * Copyright (C) 2020-2023 IOPSYS Software Solutions AB. All rights reserved. - * - * Author: Amin Ben Ramdhane <amin.benramdhane@pivasoftware.com> - * - * See LICENSE file for license related information. - */ - -#include <stdio.h> -#include <stdbool.h> -#include <sys/sysinfo.h> -#include <sys/utsname.h> -#include <sys/statvfs.h> - -#include "tools.h" -#include "swmod_uci.h" -#include "swmod_host.h" -#include "swmod.h" - -void get_host_system_info(ExecEnv_t *host_ee) -{ - if (host_ee == NULL) - return; - - struct utsname utsname; - - if (uname(&utsname) >= 0) { - swmod_strncpy(host_ee->type, "Virtual_EE", MAX_LEN_64); - swmod_strncpy(host_ee->vendor, utsname.nodename, MAX_LEN_128); - swmod_strncpy(host_ee->version, utsname.release, MAX_LEN_16); - } - - struct sysinfo sinfo; - - if (sysinfo(&sinfo) == 0) { - host_ee->allocated_memory = (sinfo.totalram / 1024); - host_ee->available_memory = (sinfo.freeram / 1024); - } - - struct statvfs dinfo; - if (statvfs("/", &dinfo) == 0) { - host_ee->allocated_disk_space = (dinfo.f_bsize * dinfo.f_blocks) / 1024; - host_ee->available_disk_space = (dinfo.f_bsize * dinfo.f_bfree) / 1024; - } else { - host_ee->allocated_disk_space = 0; - host_ee->available_disk_space = 0; - } -} - -void populate_host_system_environment(struct list_head *ee_head) -{ - ExecEnv_t host_ee; - memset(&host_ee, 0, sizeof(ExecEnv_t)); - - host_ee.exists = true; - host_ee.pause = 0; - host_ee.ee_type = EE_TYPE_HOST; - host_ee.autoboot = 1; - host_ee.eeid = PARENT_EEID; - host_ee.parent_eeid = 0; - swmod_strncpy(host_ee.name, HOST_SYSTEM, MAX_LEN_32); - swmod_strncpy(host_ee.status, "Up", MAX_LEN_32); - - swmod_add_ee_in_list(ee_head, &host_ee); -} diff --git a/src/swmod_host.h b/src/swmod_host.h deleted file mode 100644 index ce2164d..0000000 --- a/src/swmod_host.h +++ /dev/null @@ -1,19 +0,0 @@ -/* - * swmod_host.h: Host specific details - * - * Copyright (C) 2020-2023 IOPSYS Software Solutions AB. All rights reserved. - * - * Author: Amin Ben Ramdhane <amin.benramdhane@pivasoftware.com> - * - * See LICENSE file for license related information. - */ - -#ifndef HOST_H -#define HOST_H -#include "swmod.h" -#include <libubox/list.h> - -void populate_host_system_environment(struct list_head *ee_list); -void get_host_system_info(ExecEnv_t *host_ee); - -#endif //HOST_H diff --git a/src/swmod_lxc.c b/src/swmod_lxc.c index 2f626ad..176dc32 100644 --- a/src/swmod_lxc.c +++ b/src/swmod_lxc.c @@ -13,813 +13,55 @@ #endif #include <stdio.h> -#include <unistd.h> -#include <sys/sysinfo.h> -#include <sys/statvfs.h> -#include <sys/utsname.h> -#include <errno.h> -#include <fcntl.h> +#include <stdlib.h> -#include "tools.h" -#include "swmod_uci.h" -#include "swmod_opkg.h" -#include "swmod.h" +#include "swmod_common.h" #include "swmod_lxc.h" -#include "swmod_api.h" - -#define LXC_CONFIG_PATH "/etc/lxc/lxc.conf" -#define LXC_PATH "lxc.lxcpath" - -static char g_lxc_buff[MAX_BUFFER_LEN]; - -typedef struct lxc_attach_args { - const char *lxcpath; - const char *value; - int action; - int pid; - int fd; - const char *user; - const char *pwd; - const char *service; -} lxc_attach_args; - -struct service_state { - char *name; - bool state; -}; - -const char *get_lxc_path_from_config(void) -{ - return lxc_get_global_config_item(LXC_PATH); -} - -bool lxc_is_supported(const char **lxcpath) -{ - if (!file_exists(LXC_CONFIG_PATH)) - return false; - - *lxcpath = get_lxc_path_from_config(); - - if (!(*lxcpath) || !file_exists(*lxcpath)) - return false; - - return true; -} - -static int lxc_attach_func(struct lxc_container *ct, lxc_attach_exec_t exec_function, - lxc_attach_args *command, bool get_output) -{ - int ret; - pid_t pid; - int pipefd[2]; - lxc_attach_options_t attach_options = LXC_ATTACH_OPTIONS_DEFAULT; - lxc_attach_args lxc_input; - - memset(&lxc_input, 0, sizeof(lxc_attach_args)); - - g_lxc_buff[0] = '\0'; - ret = pipe2(pipefd, O_NONBLOCK); - if (ret < 0) { - PRINT_ERR("Failed to create pipe"); - return -1; - } - - if (command) { - lxc_input.lxcpath = command->lxcpath; - lxc_input.value = command->value; - lxc_input.action = command->action; - lxc_input.pid = command->pid; - lxc_input.user = command->user; - lxc_input.pwd = command->pwd; - lxc_input.service = command->service; - } - lxc_input.fd = pipefd[1]; - - const char *state = ct->state(ct); - - if (strcmp(state, "RUNNING") != 0) { - PRINT_ERR("Container might be frozen"); - goto err; - } - - ret = ct->attach(ct, exec_function, &lxc_input, &attach_options, &pid); - if (ret < 0) - goto err; - - wait_for_pid(pid); - - if (get_output == true) { - ret = read(pipefd[0], &g_lxc_buff, sizeof(g_lxc_buff)-1); - if (ret != -1) { // error on read - g_lxc_buff[ret] = '\0'; - } - PRINT_DEBUG("== Attach Result buff [%s] ##", g_lxc_buff); - } - -err: - close(pipefd[0]); - close(pipefd[1]); - return ret; -} - -static void dump_output_fd(int fd, const char *str) -{ - if (str == NULL) - return; - - write(fd, str, strlen(str)); - close(fd); -} - -/************************** Execution Environments **************************/ -static int lxc_attach_run_env_func(void *args) -{ - char buff[MAX_LEN_1024]; - struct utsname utsname; - char vendor[MAX_LEN_128] = {0}, version[MAX_LEN_16] = {0}; - lxc_attach_args *data = (lxc_attach_args *) args; - - if (uname(&utsname) >= 0) { - swmod_strncpy(vendor, utsname.nodename, MAX_LEN_128); - swmod_strncpy(version, utsname.release, MAX_LEN_16); - } - - struct sysinfo sinfo; - unsigned long alloc_mem = 0, avail_mem = 0; - - if (sysinfo(&sinfo) == 0) { - alloc_mem = (sinfo.totalram / 1024); - avail_mem = (sinfo.freeram / 1024); - } - - struct statvfs dinfo; - unsigned long allocated_disk_space = 0; - unsigned long available_disk_space = 0; - - if (statvfs("/", &dinfo) == 0) { - allocated_disk_space = (dinfo.f_bsize * dinfo.f_blocks) / 1024; - available_disk_space = (dinfo.f_bsize * dinfo.f_bfree) / 1024; - } - - /* lxc_attach_result buffer format */ - /* type=<ENV_TYPE> vendor=<ENV_VENDOR> version=<ENV_VERSION> - * alloc_mem=<ENV_ALLOCATED_MEMORY> avail_mem=<ENV_AVAILABLE_MEMORY> */ - snprintf(buff, sizeof(buff), "vendor=%s version=%s alloc_mem=%lu avail_mem=%lu alloc_disk=%lu avail_disk=%lu", - vendor, version, alloc_mem, avail_mem, allocated_disk_space, available_disk_space); - - dump_output_fd(data->fd, buff); - - return 0; -} - -unsigned long long lxc_get_cgroup_item_ull(struct lxc_container *ct, const char *config) -{ - unsigned long long value = 0; - char buffer[MAX_LEN_32] = {0}; - - int res = ct->get_cgroup_item(ct, config, buffer, sizeof(buffer)); - if (res >= 0) { - sscanf(buffer, "%llu", &value); - } - return value; -} - -void get_lxc_environment_info(ExecEnv_t *ee, const char *lxc_uci_path) -{ - if (lxc_uci_path == NULL || strlen(lxc_uci_path) == 0) - return; - - if (ee == NULL) - return; - - struct lxc_container *ct = lxc_container_new(ee->name, NULL); - if (!ct) { - swmod_strncpy(ee->status, "Error", MAX_LEN_32); - PRINT_ERR("Failed in opening container: %s", ee->name); - return; - } - - bool ct_running = ct->is_running(ct); - - ee->autoboot = get_autoboot_from_config_file(ct->name, lxc_uci_path); - swmod_strncpy(ee->status, ct_running ? "Up" : "Disabled", MAX_LEN_32); - - if (ct_running && ((strcmp(ct->state(ct), "FROZEN") == 0) || - strcmp(ct->state(ct), "FREEZING") == 0)) { - ee->pause = 1; - } - - if (!ct_running || ee->pause) { - PRINT_INFO("lxc container not running or frozen"); - lxc_container_put(ct); - return; - } - - /* get memory space limit in cgroup */ - unsigned long long val = 0; - val = lxc_get_cgroup_item_ull(ct, "memory.limit_in_bytes"); - ee->allocated_memory = val / 1024; - - /* get free space from lxc info */ - val = lxc_get_cgroup_item_ull(ct, "memory.usage_in_bytes"); - ee->available_memory = ee->allocated_memory - val / 1024; - - int ret = lxc_attach_func(ct, lxc_attach_run_env_func, NULL, true); - if (ret >= 0 && strlen(g_lxc_buff)) { - sscanf(g_lxc_buff, "vendor=%127s version=%15s alloc_mem=%lu avail_mem=%lu alloc_disk=%lu avail_disk=%lu", - ee->vendor, ee->version, &ee->allocated_memory, &ee->available_memory, - &ee->allocated_disk_space, &ee->available_disk_space); - } - - if (ret == -1) { - swmod_strncpy(ee->status, "Error", MAX_LEN_32); - } - - lxc_container_put(ct); -} - -void populate_lxc_environment(struct list_head *ee_head, const char *lxc_uci_path) -{ - const char *lxcpath = NULL; - - if (lxc_uci_path == NULL) - return; - - if (strlen(lxc_uci_path) == 0) - return; - - if (!lxc_is_supported(&lxcpath)) - return; - - if (0 != swmod_uci_init(lxc_uci_path)) - return; - - struct uci_section *s = NULL, *stmp = NULL; - swmod_uci_foreach_section_safe(SWMOD_LXC_DU_UCI, "container", stmp, s) { - const char *name = swmod_uci_get_value_by_section(s, "name"); - const char *type = swmod_uci_get_value_by_section(s, "type"); - const char *eeid = swmod_uci_get_value_by_section(s, "eeid"); - const char *alias = swmod_uci_get_value_by_section(s, "alias"); - - if (strlen(name) != 0 && strcmp(type, "lxc") == 0) { - ExecEnv_t ee; - memset(&ee, 0, sizeof(ExecEnv_t)); - - ee.exists = true; - ee.ee_type = EE_TYPE_LXC; - ee.parent_eeid = PARENT_EEID; - - if (strlen(eeid) != 0) - ee.eeid = strtol(eeid, NULL, 10); - - swmod_strncpy(ee.type, "Linux Container", MAX_LEN_64); - swmod_strncpy(ee.name, name, MAX_LEN_32); - swmod_strncpy(ee.alias, alias, MAX_LEN_65); - swmod_add_ee_in_list(ee_head, &ee); - } - } - - swmod_uci_fini(SWMOD_LXC_DU_UCI); -} - -void lxc_service_get_cb(struct ubus_request *req, int type, struct blob_attr *msg) -{ - char *str; - lxc_attach_args *input = (lxc_attach_args *) req->priv; - - str = blobmsg_format_json(msg, true); - if (str != NULL) { - write(input->fd, str, strlen(str)); - free(str); - } -} - -static int lxc_attach_pid(void *args) -{ - char buff[MAX_LEN_1024]; - char cmdline[MAX_LEN_32] = {0}; - int vsize = 0; - lxc_attach_args *lxc_input = (lxc_attach_args *) args; - - get_pid_details(lxc_input->pid, cmdline, MAX_LEN_32, &vsize); - /* lxc_attach_result buffer format */ - /* type=<ENV_TYPE> vendor=<ENV_VENDOR> version=<ENV_VERSION> - * alloc_mem=<ENV_ALLOCATED_MEMORY> avail_mem=<ENV_AVAILABLE_MEMORY> */ - snprintf(buff, sizeof(buff), "cmdline=%s vsize=%d", cmdline, vsize); - - dump_output_fd(lxc_input->fd, buff); - - return 0; -} - -void get_pid_details_lxc(ExecEnv_t *env, int pid, char *cmdline, int cmd_len, int *vsize) -{ - if (env == NULL || cmdline == NULL || cmd_len < MAX_LEN_32 || vsize == NULL) - return; - - if (env->name[0] == '\0') - return; - - struct lxc_container *ct = lxc_container_new(env->name, NULL); - if (!ct) { - PRINT_ERR("Failed in opening container: %s", env->name); - return; - } - - if (!ct->is_running(ct)) { - lxc_container_put(ct); - return; - } - - lxc_attach_args lxc_data; - - memset(&lxc_data, 0, sizeof(lxc_attach_args)); - lxc_data.pid = pid; - int ret = lxc_attach_func(ct, lxc_attach_pid, &lxc_data, true); - if (ret >= 0 && strlen(g_lxc_buff)) { - sscanf(g_lxc_buff, "cmdline=%31s vsize=%d", cmdline, vsize); - } - - lxc_container_put(ct); -} +#include "tools.h" -static int lxc_attach_eu_list(void *args) +const char *swmod_get_lxc_version(void) { - get_service_list("service", "list", lxc_service_get_cb, args); - return 0; + return lxc_get_version(); } -void populate_lxc_eu(ExecEnv_t *env, const char *lxc_uci_path) +void swmod_set_lxc_state(const char *cont, const char *execenv, int state) { - struct blob_buf bb; - - if (lxc_uci_path == NULL || strlen(lxc_uci_path) == 0) { - PRINT_ERR("LXC DU uci path unknown"); - return; - } - - if (env == NULL) { - PRINT_ERR("No environment information given"); - return; - } + int timeout = 300; + int ret = 0; + struct lxc_container *ct = NULL; - if (env->name[0] == '\0' || env->exists == false) { - PRINT_ERR("Environment name unknown or not exists"); + if (!cont || !execenv) return; - } - struct lxc_container *ct = lxc_container_new(env->name, NULL); + ct = lxc_container_new(cont, execenv); if (!ct) { - PRINT_ERR("Failed in opening container: %s", env->name); - return; - } - - if (!ct->is_running(ct)) { - lxc_container_put(ct); + PRINT_ERR("Failed in opening container: %s", cont); return; } - if (0 != swmod_uci_init(lxc_uci_path)) { - lxc_container_put(ct); - return; - } - - struct uci_section *s = NULL, *stmp = NULL; - swmod_uci_foreach_section_safe(SWMOD_LXC_DU_UCI, "du_eu_assoc", stmp, s) { - const char *type = swmod_uci_get_value_by_section(s, "type"); - const char *status = swmod_uci_get_value_by_section(s, "du_status"); - - if (strcmp(type, "lxc") == 0 && strcmp(status, "Installed") == 0) { - const char *eu_name = swmod_uci_get_value_by_section(s, "eu_name"); - if (strlen(eu_name) == 0) - continue; - - const char *ee_name = swmod_uci_get_value_by_section(s, "ee_name"); - if (strcmp(ee_name, env->name) != 0) - continue; - - const char *req_state = swmod_uci_get_value_by_section(s, "requested_state"); - const char *auto_start = swmod_uci_get_value_by_section(s, "autostart"); - const char *du_name = swmod_uci_get_value_by_section(s, "name"); - const char *eu_alias = swmod_uci_get_value_by_section(s, "eu_alias"); - - lxc_attach_args lxc_data; - memset(&lxc_data, 0, sizeof(lxc_attach_args)); - lxc_data.service = eu_name; - int ret = lxc_attach_func(ct, lxc_attach_eu_list, (lxc_attach_args *)&lxc_data, true); - if (ret >= 0 && strlen(g_lxc_buff)) { - memset(&bb, 0, sizeof(struct blob_buf)); - blob_buf_init(&bb, 0); - blobmsg_add_json_from_string(&bb, g_lxc_buff); - - ExecUnit node; - memset(&node, 0, sizeof(ExecUnit)); - if (0 == update_eu_from_blob(env, bb.head, &node)) { - if (req_state) - swmod_strncpy(node.req_state, req_state, sizeof(node.req_state)); - - if (du_name) - swmod_strncpy(node.du_name, du_name, sizeof(node.du_name)); - - if (eu_alias) - swmod_strncpy(node.eu_alias, eu_alias, sizeof(node.eu_alias)); - - node.autostart = uci_str_to_bool(auto_start); - - swmod_add_eu_in_list(&env->eu_list, &node); - } - blob_buf_free(&bb); - } - } - } - - swmod_uci_fini(SWMOD_LXC_DU_UCI); - lxc_container_put(ct); -} - -/************************** Deployment/Execution Unit **************************/ -/************************** Install/Remove **************************/ -static int lxc_attach_run_opkg_method_func(void *args) -{ - lxc_attach_args *data = (lxc_attach_args *)args; - - if (!data || *(data->value) == '\0') { - PRINT_ERR("No data available"); - return -1; - } - - int err = -1; - - char output[MAX_LEN_1024] = {0}; - if (data->action == SWMOD_INSTALL) - err = swmod_perform_installation(data->value, data->user, data->pwd, output, sizeof(output)); - else if (data->action == SWMOD_UPDATE) - err = swmod_perform_upgrade(data->value, data->user, data->pwd, output, sizeof(output)); - else if (data->action == SWMOD_REMOVE) - err = swmod_perform_uninstall(data->value, output, sizeof(output)); - else - err = -1; - - dump_output_fd(data->fd, output); - return err; -} - -int swmod_lxc_install_update_remove_package(const PkgInfo *pkg, char *out, int outlen, const char *ct_name, int action) -{ - int err = -1; - struct lxc_container *ct = NULL; - - if (out == NULL) { - PRINT_ERR("No output buffer"); - return err; - } - - if (pkg == NULL) { - snprintf(out, outlen, "Internal Error"); - PRINT_ERR("No package information"); - return err; - } - - if (ct_name == NULL) { - snprintf(out, outlen, "No ExecEnv information received"); - PRINT_ERR("No environment information given"); - return err; - } - - if (ct_name[0] == '\0') { - snprintf(out, outlen, "ExecEnv name unknown"); - PRINT_ERR("No environment name given"); - return err; - } - - ct = lxc_container_new(ct_name, NULL); - if (!ct) { - snprintf(out, outlen, "Error in opening container: %s", ct_name); - PRINT_ERR("Failed in opening container: %s", ct_name); - return err; - } - - if (!ct->is_running(ct)) { - snprintf(out, outlen, "ExecEnv not running"); - lxc_container_put(ct); - return err; - } - - PRINT_DEBUG("## Container %s", ct->name); - lxc_attach_args lxc_args = (lxc_attach_args){.value = pkg->url, .action = action, .user = pkg->uname, .pwd = pkg->psw}; - err = lxc_attach_func(ct, lxc_attach_run_opkg_method_func, &lxc_args, true); - PRINT_DEBUG("# Reading i/u/r %d, lxc[%s], err %d", action, ct->name, err); - if (err >= 0 && strlen(g_lxc_buff)) { - err = 0; - snprintf(out, outlen, "%s", g_lxc_buff); - } - - lxc_container_put(ct); - - return err; -} - -static int lxc_attach_service_state_func(void *args) -{ - struct service_state *st = (struct service_state *)args; - - return ubus_call_service_state(st->name, st->state); -} - -int swmod_set_lxc_ee_state(ExecEnv_t *env, char *state, const char *lxc_uci_path) -{ - int timeout; - int ret = SUCCESS; - - if (lxc_uci_path == NULL || strlen(lxc_uci_path) == 0) { - ret = INVALID_REQUEST; - PRINT_ERR("LXC DU uci path unknown"); - return ret; - } - - struct lxc_container *ct = NULL; - if (env == NULL) { - ret = INVALID_REQUEST; - PRINT_ERR("No environment information given"); - return ret; - } - - if (env->name[0] == '\0'|| state == NULL) { - ret = INVALID_REQUEST; - PRINT_ERR("No environment information or state given"); - return ret; - } - - ct = lxc_container_new(env->name, NULL); - if (!ct) { - ret = NOT_FOUND; - PRINT_ERR("Failed in opening container: %s", env->name); - return ret; - } - - int req_state = get_requested_container_state(state); - - switch (req_state) { - case CONT_START: - set_autoboot_to_config_file(ct->name, true, lxc_uci_path); - - if (ct->is_running(ct)) { - ret = ALREADY_RUNNING; - break; - } - - ct->want_close_all_fds(ct, true); - ret = ct->start(ct, 0, NULL) ? SUCCESS: FAILURE; + switch (state) { + case EU_START: break; - case CONT_STOP: - timeout = get_timeout_from_config_file(ct->name, lxc_uci_path); - - set_autoboot_to_config_file(ct->name, false, lxc_uci_path); - + case EU_STOP: if (!ct->is_running(ct)) { - ret = NOT_RUNNING; break; } if (strcmp(ct->state(ct), "FROZEN") == 0 || strcmp(ct->state(ct), "FREEZING") == 0) { /* to stop a frozen container first need to unfreeze it */ if (!ct->unfreeze(ct)) { - ret = FAILURE; break; } } - ret = ct->shutdown(ct, timeout) ? SUCCESS : FAILURE; - if (ret == FAILURE) { + ret = ct->shutdown(ct, timeout); + if (ret == 0) { PRINT_DEBUG("Going to force stop [%s]", ct->name); - ret = ct->stop(ct) ? SUCCESS : FAILURE; + ct->stop(ct); } break; - case CONT_PAUSE: - if (!ct->is_running(ct)) { - ret = NOT_RUNNING; - break; - } - - ret = ct->freeze(ct) ? SUCCESS : FAILURE; - break; - case CONT_RESUME: - if (!ct->is_running(ct)) { - ret = NOT_RUNNING; - break; - } - - ret = ct->unfreeze(ct) ? SUCCESS : FAILURE; - break; - default: - ret = INVALID_REQUEST; } lxc_container_put(ct); - - return ret; } -int swmod_set_lxc_service_state(ExecEnv_t *env, char *name, bool state, const char *lxc_uci_path) -{ - int ret = -1; - struct lxc_container *ct = NULL; - - if (lxc_uci_path == NULL || strlen(lxc_uci_path) == 0) { - PRINT_ERR("LXC DU uci path unknown"); - return ret; - } - - if (env == NULL) { - PRINT_ERR("No environment info"); - return ret; - } - - if (env->name[0] == '\0') { - PRINT_ERR("No ExecEnv name found"); - return ret; - } - - if (name == NULL) { - PRINT_ERR("No eu name information"); - return ret; - } - - if (0 != swmod_uci_init(lxc_uci_path)) { - PRINT_ERR("Failed to write the requested value"); - return ret; - } - - struct uci_section *s = NULL, *stmp = NULL; - bool found = false; - swmod_uci_foreach_section_safe(SWMOD_LXC_DU_UCI, "du_eu_assoc", stmp, s) { - const char *eu = swmod_uci_get_value_by_section(s, "eu_name"); - const char *ee_name = swmod_uci_get_value_by_section(s, "ee_name"); - - if (strcmp(name, eu) == 0 && strcmp(env->name, ee_name) == 0) { - found = true; - if (state) { - swmod_uci_set_value_by_section(s, "requested_state", "Active"); - } else { - swmod_uci_set_value_by_section(s, "requested_state", "Idle"); - } - - break; - } - } - - swmod_uci_fini(SWMOD_LXC_DU_UCI); - - if (found == false) { - PRINT_ERR("No DU exist with name: %s in ExecEnv: %s", name, env->name); - return ret; - } - - ct = lxc_container_new(env->name, NULL); - if (!ct) { - PRINT_ERR("Failed in opening container: %s", env->name); - return ret; - } - - if (!ct->is_running(ct)) { - PRINT_INFO("lxc container not running"); - lxc_container_put(ct); - return ret; - } - - struct service_state st; - st.name = name; - st.state = state; - ret = lxc_attach_func(ct, lxc_attach_service_state_func, (lxc_attach_args *)&st, false); - lxc_container_put(ct); - - return ret; -} - -static int lxc_attach_run_cmd(void *args) -{ - lxc_attach_args *lxc_input = (lxc_attach_args *) args; - FILE *pp; // program pointer - const char *cmd; - - cmd = lxc_input->value; - if (cmd == NULL) { // null command to run, silently ignore - PRINT_ERR("Empty command to run"); - return 0; - } - - pp = popen(cmd, "r"); - if (pp != NULL) { - char line[MAX_LEN_512] = {0}; - - while(fgets(line, sizeof(line), pp) != NULL) { - write(lxc_input->fd, line, strlen(line)); - } - pclose(pp); - } - - return 0; -} - -int lxc_run_cmd(ExecEnv_t *ee, const char *cmd, char *output, int out_len) -{ - struct lxc_container *ct; - lxc_attach_args lxc_data; - - if (ee->exists == false || ee->ee_type != EE_TYPE_LXC) { - PRINT_ERR("lxc not enabled"); - return -1; - } - - memset(&lxc_data, 0, sizeof(lxc_attach_args)); - lxc_data.value = cmd; - ct = lxc_container_new(ee->name, NULL); - if (!ct) { - PRINT_ERR("failed to open container"); - return -1; - } - - if (!ct->is_running(ct)) { - PRINT_ERR("container not running"); - lxc_container_put(ct); - return -1; - } - - int ret = lxc_attach_func(ct, lxc_attach_run_cmd, &lxc_data, true); - if (ret >= 0 && strlen(g_lxc_buff)) { - snprintf(output, out_len, "%s", g_lxc_buff); - } - - lxc_container_put(ct); - - return ret; -} - -void get_service_list(char *object, char *method, ubus_data_handler_t callback, void *data) -{ - /* This function will be called inside LXC, so need a new ubux ctx */ - uint32_t id; - int fault = 0; - struct ubus_context *ctx = ubus_connect(NULL); - struct blob_buf bb; - - fault = ubus_lookup_id(ctx, object, &id); - if (fault) { - PRINT_ERR("ubus service not found %d", fault); - ubus_free(ctx); - return; - } - - lxc_attach_args *input = (lxc_attach_args *)data; - if (input == NULL) { - PRINT_ERR("Service not found"); - ubus_free(ctx); - return; - } - - if (input->service == NULL) { - PRINT_ERR("Service name not found"); - ubus_free(ctx); - return; - } - - memset(&bb, 0, sizeof(struct blob_buf)); - blob_buf_init(&bb, 0); - blobmsg_add_string(&bb, "name", input->service); - - // Invoke Ubus to get data from uspd - fault = ubus_invoke(ctx, id, method, bb.head, callback, data, UBUS_TIMEOUT); - - blob_buf_free(&bb); - ubus_free(ctx); -} - -int set_lxc_alias(const char *ee_name, const char *alias, const char *bundle) -{ - int ret = -1; - - if (ee_name == NULL || alias == NULL || bundle == NULL) - return ret; - - if (strlen(bundle) == 0) - return ret; - - if (swmod_uci_init(bundle) != 0) - return ret; - - struct uci_section *s = NULL, *stmp = NULL; - swmod_uci_foreach_section_safe(SWMOD_LXC_DU_UCI, "container", stmp, s) { - char *name = swmod_uci_get_value_by_section(s, "name"); - char *type = swmod_uci_get_value_by_section(s, "type"); - - if (strcmp(ee_name, name) == 0 && strcmp(type, "lxc") == 0) { - swmod_uci_set_value_by_section(s, "alias", alias); - ret = 0; - break; - } - } - - swmod_uci_fini(SWMOD_LXC_DU_UCI); - - return ret; -} diff --git a/src/swmod_lxc.h b/src/swmod_lxc.h index f47fdac..1c9b2d2 100644 --- a/src/swmod_lxc.h +++ b/src/swmod_lxc.h @@ -18,18 +18,7 @@ #include "swmod_common.h" -bool lxc_is_supported(const char **lxcpath); -const char *get_lxc_path_from_config(void); -void populate_lxc_environment(struct list_head *ee_list, const char *lxc_oci_path); -void populate_lxc_du(void); -int swmod_lxc_install_update_remove_package(const PkgInfo *pkg, char *out, int outlen, const char *ct_name, int action); -void populate_lxc_eu(ExecEnv_t *env, const char *lxc_uci_path); -void get_pid_details_lxc(ExecEnv_t *env, int pid, char *cmdline, int cmd_len, int *vsize); -int swmod_set_lxc_service_state(ExecEnv_t *env, char *name, bool state, const char *lxc_uci_path); -int swmod_set_lxc_ee_state(ExecEnv_t *env, char *state, const char *lxc_uci_path); -int lxc_run_cmd(ExecEnv_t *ee, const char *cmd, char *output, int out_len); -void get_lxc_environment_info(ExecEnv_t *ee, const char *lxc_uci_path); -void get_service_list(char *object, char *method, ubus_data_handler_t callback, void *data); -int set_lxc_alias(const char *ee_name, const char *alias, const char *bundle); +const char *swmod_get_lxc_version(void); +void swmod_set_lxc_state(const char *cont, const char *execenv, int state); #endif //LXC_H diff --git a/src/swmod_opkg.c b/src/swmod_opkg.c deleted file mode 100644 index 0582f2c..0000000 --- a/src/swmod_opkg.c +++ /dev/null @@ -1,145 +0,0 @@ -/* - * swmod_opkg.c: SWMOD deamon - * - * Copyright (C) 2020-2023 IOPSYS Software Solutions AB. All rights reserved. - * - * Author: Amin Ben Ramdhane <amin.benramdhane@pivasoftware.com> - * - * See LICENSE file for license related information. - */ - -#include "tools.h" -#include "swmod.h" -#include "swmod_uci.h" -#include "swmod_opkg.h" -#include "swmod_common.h" -#include "opkg_utils.h" -#include "swmod_api.h" - -static bool validate_args(const char *url, char *output, int out_len) -{ - if (output == NULL || out_len <= 0) { - return false; - } - - if (url == NULL) { - snprintf(output, out_len, "Package path not given"); - return false; - } - - if (url[0] == '\0') { - snprintf(output, out_len, "Package path not given"); - return false; - } - - return true; -} - -int swmod_perform_installation(const char *url, const char *uname, const char *pwd, char *output, int out_len) -{ - int err = -1; - char package_path[2049] = {0}; - - if (validate_args(url, output, out_len) == false) - return err; - - if (strstr(url, "file://") != NULL) { - /* This is a local file */ - snprintf(package_path, sizeof(package_path), "%s", url+6); - } else { - unsigned long size = get_remote_file_size(url, uname, pwd); - if (size == 0) { - snprintf(output, out_len, "Failed to read package info or package is empty"); - return err; - } - - if (!memory_available(size, DW_TMP_DIR_PATH)) { - snprintf(output, out_len, "No enough space in system to download the package"); - return err; - } - - /* This is a remote package, need to download first */ - if(0 != download_remote_package(url, uname, pwd, DW_PKG_LOCAL_PATH)) { - snprintf(output, out_len, "Package download failed from %s", url); - goto end; - } - - snprintf(package_path, sizeof(package_path), "%s", DW_PKG_LOCAL_PATH); - } - - if (strlen(package_path) == 0) { - snprintf(output, out_len, "Invalid package name"); - goto end; - } - - err = opkg_install_pkg(package_path, output, out_len); - if (0 != err) { - snprintf(output, out_len, "Internal Error"); - } - -end: - /* Remove the downloaded package if it is in local dir of host or container */ - if (file_exists(DW_PKG_LOCAL_PATH)) { - remove(DW_PKG_LOCAL_PATH); - } - - return err; -} - -int swmod_perform_upgrade(const char *url, const char *uname, const char *pwd, char *output, int out_len) -{ - int err = -1; - char package_path[2049] = {0}; - - if (validate_args(url, output, out_len) == false) - return err; - - if (strchr(url, ':') != NULL) { - /* This is a remote package, need to download first */ - if(0 != download_remote_package(url, uname, pwd, DW_PKG_LOCAL_PATH)) { - snprintf(output, out_len, "Package download failed from %s", url); - return err; - } - - snprintf(package_path, sizeof(package_path), "%s", DW_PKG_LOCAL_PATH); - } else { - snprintf(package_path, sizeof(package_path), "%s", url); - } - - err = opkg_update_pkg(package_path, output, out_len); - if (0 != err) { - snprintf(output, out_len, "Internal Error"); - } - - /* Remove the downloaded package if it is in local dir of host or container */ - if (file_exists(DW_PKG_LOCAL_PATH)) { - remove(DW_PKG_LOCAL_PATH); - } - - return err; -} - -int swmod_perform_uninstall(const char *pname, char *output, int outlen) -{ - int err = -1; - - if (validate_args(pname, output, outlen) == false) - return err; - - char version[MAX_LEN_64] = {0}; - char line[MAX_LEN_512] = {0}; - opkg_get_version(pname, version, sizeof(version)); - snprintf(line, sizeof(line), "\nPackage Name:%s Version:%s\n", pname, version); - - err = opkg_remove_pkg(pname, output, outlen); - if (0 != err) { - snprintf(output, outlen, "Internal Error"); - } - - int line_len = strlen(line); - if (strlen(output) + line_len < outlen) { - strncat(output, line, line_len); - } - - return err; -} diff --git a/src/swmod_opkg.h b/src/swmod_opkg.h deleted file mode 100644 index 5b67674..0000000 --- a/src/swmod_opkg.h +++ /dev/null @@ -1,18 +0,0 @@ -/* - * swmod_opkg.h: opkg utilities - * - * Copyright (C) 2020-2023 IOPSYS Software Solutions AB. All rights reserved. - * - * Author: Amin Ben Ramdhane <amin.benramdhane@pivasoftware.com> - * - * See LICENSE file for license related information. - */ - -#ifndef __SWMOD_OPKG_H -#define __SWMOD_OPKG_H - -int swmod_perform_installation(const char *url, const char *uname, const char *pwd, char *output, int out_len); -int swmod_perform_upgrade(const char *url, const char *uname, const char *pwd, char *output, int out_len); -int swmod_perform_uninstall(const char *pname, char *output, int out_len); - -#endif //__SWMOD_OPKG_H diff --git a/src/swmod_uci.c b/src/swmod_uci.c index 8bfee0a..847a599 100644 --- a/src/swmod_uci.c +++ b/src/swmod_uci.c @@ -267,7 +267,7 @@ char *swmod_uci_set_value_by_section_list(struct uci_section *section, const cha return ""; } -struct uci_section *swmod_uci_add_section(const char *package, const char *section_type, bool rename) +struct uci_section *swmod_uci_add_section(const char *package, const char *section_type, const char *sec_name) { struct uci_ptr ptr; struct uci_section *s = NULL; @@ -287,14 +287,14 @@ struct uci_section *swmod_uci_add_section(const char *package, const char *secti return NULL; } - if (rename == true) { + if (sec_name) { ptr.package = s->package->e.name; ptr.p = s->package; ptr.section = s->e.name; ptr.s = s; - ptr.value = section_type; + ptr.value = sec_name; ptr.target = UCI_TYPE_SECTION; if (uci_lookup_ptr(uci_ctx_swmod, &ptr, NULL, true) == UCI_OK) { @@ -327,9 +327,9 @@ int swmod_uci_delete_by_section(struct uci_section *section, const char *option, return 0; } -bool check_section_exist_by_option(const char *section, const char *section_type, const char *option, const char *val_check, struct uci_section **s) +bool check_section_exist_by_option(const char *package, const char *section_type, const char *option, const char *val_check, struct uci_section **s) { - swmod_uci_foreach_section(section, section_type, *s) { + swmod_uci_foreach_section(package, section_type, *s) { const char *val = swmod_uci_get_value_by_section(*s, option); if (strcmp(val, val_check) == 0) diff --git a/src/swmod_uci.h b/src/swmod_uci.h index 3454b26..456e1ee 100644 --- a/src/swmod_uci.h +++ b/src/swmod_uci.h @@ -16,7 +16,7 @@ int swmod_uci_init(const char *conf_path); int swmod_uci_fini(const char *package_name); -struct uci_section *swmod_uci_add_section(const char *package, const char *section_type, bool rename); +struct uci_section *swmod_uci_add_section(const char *package, const char *section_type, const char *sec_name); int swmod_uci_delete_by_section(struct uci_section *section, const char *option, const char *value); char *swmod_uci_get_value_by_section(struct uci_section *section, const char *option); diff --git a/src/tools.c b/src/tools.c index 53d3037..3885acc 100644 --- a/src/tools.c +++ b/src/tools.c @@ -15,6 +15,8 @@ #include <stdlib.h> #include <dirent.h> #include <unistd.h> +#include <ctype.h> +#include <sys/prctl.h> #include <sys/stat.h> #include <sys/statvfs.h> #include <sys/types.h> @@ -28,9 +30,6 @@ #include <curl/curl.h> #include "swmod_uci.h" -#include "swmod_opkg.h" -#include "opkg_utils.h" -#include "swmod_host.h" #include "tools.h" #include "swmod_api.h" @@ -38,38 +37,38 @@ static unsigned char gLogLevel = DEFAULT_LOG_LEVEL; -int get_requested_container_state(char *state) +static int get_filename_from_url(const char *url, char *filename, int len) { - if (strcmp(state, "start") == 0) { - return CONT_START; - } else if (strcmp(state, "stop") == 0) { - return CONT_STOP; - } else if (strcmp(state, "pause") == 0) { - return CONT_PAUSE; - } else if (strcmp(state, "resume") == 0) { - return CONT_RESUME; + if (url == NULL || filename == NULL) + return -1; + + memset(filename, 0, len); + + char *tmp = strrchr(url, '/'); + if (tmp == NULL) { + tmp = (char*)url; } else { - return __CONT_STATE_MAX; + if (tmp == (url + strlen(url) - 1)) { + return -1; + } else { + tmp = tmp + 1; + } } -} -char ee_set_state_error_msg[__ERROR_MAX][MAX_LEN_64] = { - "", - "internal failure", - "LXC not supported", - "ExecEnv not found", - "ExecEnv already running", - "ExecEnv not running", - "invalid request", - "CRUN not supported", -}; - -const char *ee_state_failure_reason(int err) -{ - if (err >= __ERROR_MAX || err < 0) - return "unknown"; + snprintf(filename, len, "%s", tmp); + char *tmp2 = strchr(filename, ':'); + if (tmp2) + *tmp2 = '\0'; - return ee_set_state_error_msg[err]; + tmp2 = strchr(filename, '.'); + if (tmp2) + *tmp2 = '\0'; + + tmp2 = strchr(filename, '@'); /* for docker image there could be @sha after name */ + if (tmp2) + *tmp2 = '\0'; + + return 0; } // Logging utilities @@ -198,6 +197,49 @@ bool create_dir(const char *path) return true; } +void remove_dir(const char *path) +{ + DIR *dir; + struct stat stat_path, stat_entry; + struct dirent *entry; + + stat(path, &stat_path); + + if (S_ISDIR(stat_path.st_mode) == 0) { + return; + } + + if ((dir = opendir(path)) == NULL) { + return; + } + + // iteration through entries in the directory + while ((entry = readdir(dir)) != NULL) { + // skip entries "." and ".." + if (!strcmp(entry->d_name, ".") || !strcmp(entry->d_name, "..")) + continue; + + // determinate a full path of an entry + char full_path[5096] = {0}; + snprintf(full_path, sizeof(full_path), "%s/%s", path, entry->d_name); + + // stat for the entry + stat(full_path, &stat_entry); + + // recursively remove a nested directory + if (S_ISDIR(stat_entry.st_mode) != 0) { + remove_dir(full_path); + continue; + } + + // remove a file object + unlink(full_path); + } + + rmdir(path); + closedir(dir); +} + void swmod_strncpy(char *dst, const char *src, size_t n) { strncpy(dst, src, n - 1); @@ -215,28 +257,26 @@ char *generate_uuid(void) return uuid; } -char *generate_duid(bool sysnchronise, int number) +char *generate_duid(const char *ee_name, const char *du_name) { - const char buf[] = "0123456789abcdefghijklmnopqrstuvwxyz"; - int div = sizeof(buf) - 1; - char euid[16] = {0}; - int i; - - srand(time(NULL)); - if (sysnchronise) { - char euid_num[8] = {0}; - - for (i = 0; i < 3; i++) - euid[i] = buf[rand() % div]; - snprintf(euid_num, sizeof(euid_num), "%04d", number); - strncat(euid, euid_num, 4); - } else { - for (i = 0; i < 7; i++) - euid[i] = buf[rand() % div]; + char duid[512] = {0}; + int i = 0; + + if (ee_name == NULL || du_name == NULL) + return strdup(duid); + + snprintf(duid, sizeof(duid), "%s_%s", ee_name, du_name); + while (duid[i] != '\0') { + if (isalnum(duid[i]) || duid[i] == '_') { + i++; + continue; + } + + duid[i] = '_'; + i++; } - euid[7] = '\0'; - return strdup(euid); + return strdup(duid); } /* @@ -297,147 +337,7 @@ int run_cmd_no_output(const char *cmd) return 0; } -int get_env_type(const char *type) -{ - if (strcmp(type, "lxc") == 0) - return EE_TYPE_LXC; - else if (strcmp(type, "host") == 0) - return EE_TYPE_HOST; - else - return EE_TYPE_UNKNOWN; -} - -void sync_eeid_with_uci(struct list_head *ee_list, ExecEnv_t *environments, const char *lxc_uci_path) -{ - if (list_empty(ee_list)) - return; - - if (lxc_uci_path == NULL) - return; - - if (strlen(lxc_uci_path) == 0) - return; - - if (0 != swmod_uci_init(lxc_uci_path)) { - return; - } - - char eeid_str[12] = {0}; - unsigned int new_eeid = 3; - struct uci_section *s = NULL, *stmp = NULL; - int index = 0; - bool global_context_exist = false; - - swmod_uci_foreach_section_safe(SWMOD_LXC_DU_UCI, "globals", stmp, s) { - if (strcmp(s->e.name, "globals") == 0) { - const char *next_eeid = swmod_uci_get_value_by_section(s, "next_eeid"); - if (next_eeid != NULL && strlen(next_eeid) != 0) { - new_eeid = (unsigned int)strtoul(next_eeid, NULL, 10); - } - - global_context_exist = true; - break; - } - } - - /* check the ee that has valid eeid, then put it in g_environments (upto MAX_ENV) */ - ExecEnvNode *iter = NULL; - list_for_each_entry(iter, ee_list, list) { - if (iter->env.eeid != 0) { - if (index < MAX_ENV) { - memcpy(&environments[index], &iter->env, sizeof(ExecEnv_t)); - index ++; - } - } - } - - /* now those have no eeid, initialize eeid and put in g_environments (upto MAX_ENV), - * as well make entry in uci file. - */ - iter = NULL; - list_for_each_entry(iter, ee_list, list) { - if (index == MAX_ENV) - break; - - if (iter->env.eeid == 0) { - struct uci_section *sc = NULL, *sctmp = NULL; - swmod_uci_foreach_section_safe(SWMOD_LXC_DU_UCI, "container", sctmp, sc) { - const char *name = swmod_uci_get_value_by_section(sc, "name"); - const char *type = swmod_uci_get_value_by_section(sc, "type"); - if (strcmp(name, iter->env.name) == 0 && iter->env.ee_type == get_env_type(type)) { - iter->env.eeid = new_eeid; - new_eeid = new_eeid + 1; - - snprintf(eeid_str, sizeof(eeid_str), "%u", iter->env.eeid); - swmod_uci_set_value_by_section(sc, "eeid", eeid_str); - memcpy(&environments[index], &iter->env, sizeof(ExecEnv_t)); - index ++; - break; - } - } - } - } - - PRINT_DEBUG("Total %d number of ExecEnv populated", index); - /* now keep the record for next eeid, so that if any ee is removed or added then the - * eeid of newly created ee shall be synchronised */ - if (global_context_exist == false) { - s = swmod_uci_add_section(SWMOD_LXC_DU_UCI, "globals", true); - } - - snprintf(eeid_str, sizeof(eeid_str), "%u", new_eeid); - swmod_uci_set_value_by_section(s, "next_eeid", eeid_str); - - swmod_uci_fini(SWMOD_LXC_DU_UCI); -} - -void set_autoboot_to_config_file(const char *env, bool state, const char *lxc_uci_path) -{ - if (lxc_uci_path == NULL || strlen(lxc_uci_path) == 0) - return; - - if (0 != swmod_uci_init(lxc_uci_path)) - return; - - struct uci_section *s = NULL; - swmod_uci_foreach_section(SWMOD_LXC_DU_UCI, "container", s) { - const char *name = swmod_uci_get_value_by_section(s, "name"); - const char *type = swmod_uci_get_value_by_section(s, "type"); - if (strcmp(name, env) == 0 && strcmp(type, "lxc") == 0) { - swmod_uci_set_value_by_section(s, "autostart", state ? "1" : "0"); - swmod_uci_set_value_by_section(s, "timeout", "300"); - break; - } - } - - swmod_uci_fini(SWMOD_LXC_DU_UCI); -} - -bool get_autoboot_from_config_file(const char *env, const char *lxc_uci_path) -{ - bool found = false; - - if (lxc_uci_path == NULL || strlen(lxc_uci_path) == 0) - return found; - - if (swmod_uci_init(lxc_uci_path) != 0) - return found; - - struct uci_section *s = NULL; - swmod_uci_foreach_section(SWMOD_LXC_DU_UCI, "container", s) { - const char *name = swmod_uci_get_value_by_section(s, "name"); - const char *type = swmod_uci_get_value_by_section(s, "type"); - const char *autostart = swmod_uci_get_value_by_section(s, "autostart"); - if (strcmp(name, env) == 0 && strcmp(type, "lxc") == 0 && uci_str_to_bool(autostart)) { - found = true; - break; - } - } - - swmod_uci_fini(SWMOD_LXC_DU_UCI); - return found; -} - +#if 0 int get_pid_details(int pid, char *cmdline, int cmd_len, int *vsize) { char fcmd[512]; @@ -487,6 +387,7 @@ int get_pid_details(int pid, char *cmdline, int cmd_len, int *vsize) return 0; } +#endif int wait_for_pid(pid_t pid) { @@ -510,79 +411,6 @@ again: return 0; } -int update_eu_from_blob(ExecEnv_t *env, struct blob_attr *msg, ExecUnit *node) -{ - struct blob_attr *service, *instances, *inst; - size_t rem, rem2, rem3; - enum { - P_RUN, - P_PID, - __P_MAX - }; - const struct blobmsg_policy p[__P_MAX] = { - { "running", BLOBMSG_TYPE_BOOL }, - { "pid", BLOBMSG_TYPE_INT32 }, - }; - - if (env == NULL) { - PRINT_ERR("Environment info not provided"); - return -1; - } - - if (env->exists == false) { - PRINT_ERR("Environment not exists"); - return -1; - } - - if (node == NULL) { - PRINT_ERR("Node not provided"); - return -1; - } - - blobmsg_for_each_attr(service, msg, rem) { - blobmsg_for_each_attr(instances, service, rem2) { - memset(node, 0, sizeof(ExecUnit)); - node->eu_exists = true; - swmod_strncpy(node->name, blobmsg_name(service), sizeof(node->name)); - swmod_strncpy(node->environment, env->name, sizeof(node->environment)); - node->disk_space = -1; - - blobmsg_for_each_attr(inst, instances, rem3) { - struct blob_attr *tb[__P_MAX] = {NULL}; - - if (blobmsg_parse(p, __P_MAX, tb, blobmsg_data(inst), blobmsg_len(inst)) != 0) - continue; - - if (tb[P_PID]) { - int euid = blobmsg_get_u32(tb[P_PID]); - snprintf(node->euid, sizeof(node->euid), "%d", euid); - swmod_get_pid_detail(env, euid, node->command, sizeof(node->command), &node->memory_space); - } else { - snprintf(node->euid, sizeof(node->euid), "Unknown"); - } - - if (tb[P_RUN] && blobmsg_get_bool(tb[P_RUN])) { - swmod_strncpy(node->state, "Active", sizeof(node->state)); - } else { - swmod_strncpy(node->state, "Idle", sizeof(node->state)); - } - - swmod_strncpy(node->vendor, "", sizeof(node->vendor)); // TODO - break; - } - - return 0; - } - } - /* - swmod_strncpy(exec_units[0].version[nbr], version, 32); - exec_units[0].disk_space[nbr] = disk_space; - swmod_strncpy(exec_units[0].description[nbr], spch+14, 1024); - swmod_strncpy(exec_units[0].config[nbr], spch+12, 32); - */ - return -1; -} - int ubus_call_service_state(char *service, bool state) { uint32_t id; @@ -610,299 +438,35 @@ int ubus_call_service_state(char *service, bool state) return rc; } -int get_timeout_from_config_file(const char *env, const char *lxc_uci_path) -{ - long timeout = 300; /* default timeout */ - - if (lxc_uci_path == NULL || strlen(lxc_uci_path) == 0) { - return timeout; - } - - if (swmod_uci_init(lxc_uci_path) != 0) { - return timeout; - } - - struct uci_section *s = NULL; - swmod_uci_foreach_section(SWMOD_LXC_DU_UCI, "container", s) { - const char *name = swmod_uci_get_value_by_section(s, "name"); - const char *type = swmod_uci_get_value_by_section(s, "type"); - if (strcmp(name, env) == 0 && strcmp(type, "lxc") == 0) { - const char *time = swmod_uci_get_value_by_section(s, "timeout"); - if (time != NULL && time[0] != '\0') { - timeout = strtol(time, NULL, 10); - } - break; - } - } - - swmod_uci_fini(SWMOD_LXC_DU_UCI); - return timeout; -} - -void swmod_add_ee_in_list(struct list_head *ee_list, ExecEnv_t *ee) -{ - if (ee == NULL) { - return; - } - - ExecEnvNode *node = (ExecEnvNode *)malloc(sizeof(ExecEnvNode)); - if (node == NULL) { - PRINT_ERR("Out of memory"); - return; - } - - memcpy(&node->env, ee, sizeof(ExecEnv_t)); - INIT_LIST_HEAD(&node->list); - list_add_tail(&node->list, ee_list); -} - -void swmod_delete_ee_list(struct list_head *ee_list) -{ - ExecEnvNode *iter = NULL, *node = NULL; - - list_for_each_entry_safe (iter, node, ee_list, list) { - list_del(&iter->list); - free(iter); - } -} - -void swmod_add_eu_in_list(struct list_head *eu_list, ExecUnit *eu) -{ - if (eu == NULL) { - return; - } - - EuNode *node = (EuNode *)malloc(sizeof(EuNode)); - if (node == NULL) { - PRINT_ERR("Out of memory"); - return; - } - - memcpy(&node->eu, eu, sizeof(ExecUnit)); - INIT_LIST_HEAD(&node->list); - list_add_tail(&node->list, eu_list); -} - -void swmod_delete_eu_list(struct list_head *eu_list) -{ - EuNode *iter = NULL, *node; - - list_for_each_entry_safe (iter, node, eu_list, list) { - list_del(&iter->list); - free(iter); - } -} - -void get_swmod_config_params(ConfigParams *cfg) -{ - if (cfg == NULL) - exit(0); - - if (swmod_uci_init(STD_UCI_PATH) != 0) - exit(0); - - struct uci_section *s = NULL; - swmod_uci_foreach_section(SWMOD_UCI_FILE, "globals", s) { - if (strcmp(s->e.name, "globals") == 0) { - const char *oci_bundle_root = swmod_uci_get_value_by_section(s, "oci_bundle_root"); - snprintf(cfg->oci_bundle_root, MAX_LEN_32, "%s", oci_bundle_root); - - const char *lxc_bundle_root = swmod_uci_get_value_by_section(s, "lxc_bundle_root"); - snprintf(cfg->lxc_bundle_root, MAX_LEN_32, "%s", lxc_bundle_root); - break; - } - } - swmod_uci_fini(SWMOD_UCI_FILE); - - if (strlen(cfg->oci_bundle_root) == 0) - exit(0); - - if (!dir_exist(cfg->oci_bundle_root)) - exit(0); - - char oci_du_uci[MAX_LEN_256] = {0}; - snprintf(oci_du_uci, sizeof(oci_du_uci), "%s/%s", cfg->oci_bundle_root, SWMOD_OCI_DU_UCI); - if (!file_exists(oci_du_uci)) { - /* oci du uci file not present so create an empty one */ - FILE *fp = fopen(oci_du_uci, "w"); - if (fp == NULL) - exit(0); - fclose(fp); - } - - if (strlen(cfg->lxc_bundle_root) == 0) - exit(0); - - if (!dir_exist(cfg->lxc_bundle_root)) - exit(0); - - char lxc_du_uci[MAX_LEN_256] = {0}; - snprintf(lxc_du_uci, sizeof(lxc_du_uci), "%s/%s", cfg->lxc_bundle_root, SWMOD_LXC_DU_UCI); - if (!file_exists(lxc_du_uci)) { - /* lxc container uci file not present so create an empty one */ - FILE *fp = fopen(lxc_du_uci, "w"); - if (fp == NULL) - exit(0); - fclose(fp); - } - - return; -} - -static bool validate_uuid_in_uci(const char *uuid, const char *uci_path, const char *uci_file) +bool valid_uuid(char *uuid) { bool ret = true; - if (uuid == NULL || uci_path == NULL || uci_file == NULL || - strlen(uci_file) == 0 || strlen(uci_path) == 0) { + if (uuid == NULL) + return !ret; + + int len = strlen(uuid); + if (len != 36) return !ret; - } - if (swmod_uci_init(uci_path) != 0) + /* check if already exists */ + if (swmod_uci_init(STD_UCI_PATH) != 0) return !ret; struct uci_section *s = NULL, *stmp = NULL; - swmod_uci_foreach_section_safe(uci_file, "du_eu_assoc", stmp, s) { + swmod_uci_foreach_section_safe(SWMOD_UCI_FILE, "du_eu_assoc", stmp, s) { char *id = swmod_uci_get_value_by_section(s, "uuid"); if (strcmp(id, uuid) == 0) { ret = false; break; } } - swmod_uci_fini(uci_file); - - return ret; -} -bool valid_uuid(char *uuid, const char *lxc_uci_path, const char *oci_uci_path) -{ - bool ret = true; - - if (uuid == NULL) - return !ret; - - int len = strlen(uuid); - if (len != 36 && len != 0) - return !ret; - - if (len != 0) { - /* check if already exists */ - if (lxc_uci_path != NULL && strlen(lxc_uci_path) != 0) { - ret = validate_uuid_in_uci(uuid, lxc_uci_path, SWMOD_LXC_DU_UCI); - } - - if (oci_uci_path != NULL && strlen(oci_uci_path) != 0) { - ret &= validate_uuid_in_uci(uuid, oci_uci_path, SWMOD_OCI_DU_UCI); - } - } + swmod_uci_fini(SWMOD_UCI_FILE); return ret; } -void get_opkg_description(ExecEnv_t *env, const char *pkg_name, char *desc, size_t desc_size) -{ - char cmd[MAX_LEN_256]; - char output[MAX_LEN_1024]; - - if (env == NULL || pkg_name == NULL || desc == NULL) - return; - - memset(desc, 0, desc_size); - memset(cmd, 0, sizeof(cmd)); - memset(output, 0, sizeof(output)); - - snprintf(cmd, sizeof(cmd), "grep Description: /usr/lib/opkg/info/%s.control", pkg_name); - swmod_run_cmd(env, cmd, output, sizeof(output)); - char *spch = strstr(output, "Description:"); - if (spch) { - remove_new_line(spch); - snprintf(desc, desc_size, "%s", spch+14); - } -} - -void buffer_add_line(struct list_head *head, char *entry) -{ - struct buffer_list *node = NULL; - - if (entry == NULL) - return; - - node = (struct buffer_list *) malloc(sizeof(*node)); - if (!node) { - PRINT_ERR("Out of memory!"); - return; - } - - swmod_strncpy(node->line, entry, MAX_LEN_128); - - INIT_LIST_HEAD(&node->list); - list_add_tail(&node->list, head); -} - -void create_buffer_list(struct list_head *opkg_list, char *buffer) -{ - char *token = NULL; - - if (buffer == NULL) - return; - - if (strlen(buffer) == 0) - return; - - token = strtok(buffer, "\n"); - while (token != NULL) { - buffer_add_line(opkg_list, token); - token = strtok(NULL, "\n"); - } -} - -void delete_buffer_list(struct list_head *opkg_list) -{ - struct buffer_list *iter, *node; - - list_for_each_entry_safe (iter, node, opkg_list, list) { - list_del(&iter->list); - free(iter); - } -} - -void get_opkg_service_name(ExecEnv_t *env, const char *pkg_name, char *service, size_t serv_size) -{ - char cmd[MAX_LEN_256]; - char output[MAX_LEN_1024]; - - if (env == NULL || pkg_name == NULL || service == NULL) - return; - - memset(service, 0, serv_size); - memset(cmd, 0, sizeof(cmd)); - memset(output, 0, sizeof(output)); - - snprintf(cmd, sizeof(cmd), "opkg files %s 2>&1", pkg_name); - swmod_run_cmd(env, cmd, output, sizeof(output)); - - if (strlen(output) == 0) - return; - - LIST_HEAD(opkg_files_list); - create_buffer_list(&opkg_files_list, output); - - if (!list_empty(&opkg_files_list)) { - struct buffer_list *iter; - - list_for_each_entry(iter, &opkg_files_list, list) { - char *spch = strstr(iter->line, SWMOD_INIT_PATH); - if (spch) { - remove_new_line(spch); - snprintf(service, serv_size, "%s", spch+strlen(SWMOD_INIT_PATH)); - break; - } - } - } - - delete_buffer_list(&opkg_files_list); -} - time_t convert_str_to_time(const char *time) { unsigned long tm = 0; @@ -1027,141 +591,750 @@ int download_remote_package(const char *url, const char *username, const char *p return -1; } -int swmod_ee_uci_init(ExecEnv_t *env, char *uci_file, int len) +void swmod_reset_ee_runlevel(struct uci_section *sec) { - int ret = -1; + if (sec == NULL) + return; - if (env == NULL || uci_file == NULL) - return ret; + const char *cur_level = swmod_uci_get_value_by_section(sec, "current_runlevel"); + if (strcmp(cur_level, "-1") != 0) { + const char *init_level = swmod_uci_get_value_by_section(sec, "initial_runlevel"); + swmod_uci_set_value_by_section(sec, "current_runlevel", init_level); + } +} - switch (env->ee_type) { - case EE_TYPE_HOST: -#ifdef SWMOD_CRUN - if (strlen(swmod_config.oci_bundle_root) != 0) { - snprintf(uci_file, len, "%s", SWMOD_OCI_DU_UCI); - ret = swmod_uci_init(swmod_config.oci_bundle_root); +void swmod_update_du_eu_assoc(struct list_head *du_head) +{ + struct uci_section *d = NULL; + bool found = false; + duInfoNode_t *iter = NULL; + time_t now; + char ctime[MAX_LEN_32] = {0}; + char *duid = NULL; + + swmod_uci_foreach_section(SWMOD_UCI_FILE, "du_eu_assoc", d) { + /* if du installation is pending, nothing to do */ + const char *du_status = swmod_uci_get_value_by_section(d, "status"); + if (strcmp(du_status, "Installing") == 0) + continue; + + /* If du not exist in list then remove from uci */ + if (list_empty(du_head)) { + swmod_uci_delete_by_section(d, NULL, NULL); + continue; } -#endif - break; - case EE_TYPE_LXC: -#ifdef SWMOD_LXC - if (strlen(swmod_config.lxc_bundle_root) != 0) { - snprintf(uci_file, len, "%s", SWMOD_LXC_DU_UCI); - ret = swmod_uci_init(swmod_config.lxc_bundle_root); + + const char *execenv = swmod_uci_get_value_by_section(d, "execenv"); + found = false; + iter = NULL; + + list_for_each_entry(iter, du_head, list) { + if (strcmp(iter->du.du_name, d->e.name) == 0 && + strcmp(iter->du.execenv, execenv) == 0) { + found = true; + break; + } + } + + if (found == false) + swmod_uci_delete_by_section(d, NULL, NULL); + else { + /* If du type is not in capability */ + bool du_capable = false; + const char *type = swmod_uci_get_value_by_section(d, "du_type"); + + if (strcmp(type, "OCIImage") == 0) + du_capable = swmod_du_type_capable(DU_TYPE_CRUN); + else if (strcmp(type, "LXC") == 0) + du_capable = swmod_du_type_capable(DU_TYPE_LXC); + + if (!du_capable) + swmod_du_remove(d); } -#endif - break; - default: - ret = -1; } - return ret; + /* Now if any new du found in build-root then add it in uci */ + if (list_empty(du_head)) + return; + + iter = NULL; + list_for_each_entry(iter, du_head, list) { + found = false; + swmod_uci_foreach_section(SWMOD_UCI_FILE, "du_eu_assoc", d) { + if (strcmp(iter->du.du_name, d->e.name) == 0) { + found = true; + break; + } + } + + if (found == false) { + if (!swmod_du_type_capable(iter->du.du_type)) { + char path[2056] = {0}; + snprintf(path, sizeof(path), "%s/%s", iter->du.execenv, iter->du.du_name); + remove_dir(path); + continue; + } + + duid = generate_duid(iter->du.execenv, iter->du.du_name); + + struct uci_section *s = swmod_uci_add_section(SWMOD_UCI_FILE, "du_eu_assoc", iter->du.du_name); + swmod_uci_set_value_by_section(s, "uuid", generate_uuid()); + swmod_uci_set_value_by_section(s, "duid", duid); + swmod_uci_set_value_by_section(s, "status", "Installed"); + swmod_uci_set_value_by_section(s, "url", ""); + swmod_uci_set_value_by_section(s, "description", ""); + swmod_uci_set_value_by_section(s, "version", ""); + swmod_uci_set_value_by_section(s, "du_type", (iter->du.du_type == DU_TYPE_CRUN) ? "OCIImage" : "LXC"); + now = time(NULL); + strftime(ctime, sizeof(ctime), "%Y-%m-%dT%H:%M:%SZ", gmtime(&now)); + swmod_uci_set_value_by_section(s, "installed_at", ctime); + swmod_uci_set_value_by_section(s, "eu_autostart", "1"); + swmod_uci_set_value_by_section(s, "eu_runlevel", strlen(iter->du.eu_runlevel) ? iter->du.eu_runlevel : "0"); + swmod_uci_set_value_by_section(s, "execenv", iter->du.execenv); + FREE(duid); + } + } } -int set_du_alias_to_config(const char *ee_name, const char *uuid, - const char *alias, const char *bundle, const char *uci_file) +int swmod_du_type(char *du_path) { - int ret = -1; + char conf_path[5012] = {0}; + int du_type; + int flag = 0; - if (ee_name == NULL || uuid == NULL || alias == NULL || - bundle == NULL || uci_file == NULL) - return ret; + if (!du_path) + return DU_TYPE_MAX; - if (strlen(bundle) == 0) - return ret; + snprintf(conf_path, sizeof(conf_path), "%s/%s", du_path, "config.json"); + if (file_exists(conf_path)) { + du_type = DU_TYPE_CRUN; + flag++; + } - if (strlen(uci_file) == 0) - return ret; + snprintf(conf_path, sizeof(conf_path), "%s/%s", du_path, "config"); + if (file_exists(conf_path)) { + du_type = DU_TYPE_LXC; + flag++; + } + + if (flag != 1) + return DU_TYPE_MAX; - if (swmod_uci_init(bundle) != 0) - return ret; + return du_type; +} - struct uci_section *s = NULL, *stmp = NULL; - swmod_uci_foreach_section_safe(uci_file, "du_eu_assoc", stmp, s) { - char *name = swmod_uci_get_value_by_section(s, "ee_name"); - char *du_uuid = swmod_uci_get_value_by_section(s, "uuid"); +void swmod_get_du_list(const char *base_path, const char *eu_runlevel, struct list_head *du_head) +{ + struct dirent *dp; + DIR *dir; - if (strcmp(ee_name, name) == 0 && strcmp(uuid, du_uuid) == 0) { - swmod_uci_set_value_by_section(s, "du_alias", alias); - ret = 0; - break; + if (!base_path || !du_head) + return; + + dir = opendir(base_path); + if (dir == NULL) + return; + + while ((dp = readdir(dir)) != NULL) { + char full_path[2056] = {0}; + int du_type = DU_TYPE_MAX; + + // skip entries "." and ".." + if (!strcmp(dp->d_name, ".") || !strcmp(dp->d_name, "..")) + continue; + + snprintf(full_path, sizeof(full_path), "%s/%s", base_path, dp->d_name); + du_type = swmod_du_type(full_path); + + if (dir_exist(full_path) && du_type != DU_TYPE_MAX) { + duInfoNode_t *node = (duInfoNode_t *)malloc(sizeof(duInfoNode_t)); + if (node == NULL) + continue; + + snprintf(node->du.du_name, sizeof(node->du.du_name), "%s", dp->d_name); + snprintf(node->du.eu_runlevel, sizeof(node->du.eu_runlevel), "%s", eu_runlevel); + node->du.du_type = du_type; + snprintf(node->du.execenv, sizeof(node->du.execenv), "%s", base_path); + + INIT_LIST_HEAD(&node->list); + list_add_tail(&node->list, du_head); } } +} - swmod_uci_fini(uci_file); +void swmod_free_du_list(struct list_head *du_head) +{ + duInfoNode_t *iter = NULL, *node = NULL; - return ret; + list_for_each_entry_safe(iter, node, du_head, list) { + list_del(&iter->list); + FREE(iter); + } } -int set_eu_alias_to_config(const char *ee_name, const char *eu_name, - const char *alias, const char *bundle, const char *uci_file) +int swmod_du_remove(struct uci_section *sec) { - int ret = -1; + char path[2056] = {0}; - if (ee_name == NULL || eu_name == NULL || alias == NULL || - bundle == NULL || uci_file == NULL) - return ret; + if (!sec) + return -1; - if (strlen(bundle) == 0) - return ret; + const char *execenv = swmod_uci_get_value_by_section(sec, "execenv"); - if (strlen(uci_file) == 0) - return ret; + snprintf(path, sizeof(path), "%s/%s", execenv, sec->e.name); + remove_dir(path); + swmod_uci_delete_by_section(sec, NULL, NULL); - if (swmod_uci_init(bundle) != 0) - return ret; + return 0; +} - struct uci_section *s = NULL, *stmp = NULL; - swmod_uci_foreach_section_safe(uci_file, "du_eu_assoc", stmp, s) { - char *ee = swmod_uci_get_value_by_section(s, "ee_name"); - char *eu = swmod_uci_get_value_by_section(s, "eu_name"); +void swmod_execenv_add(struct uci_section *sec) +{ + struct list_head du_head; + duInfoNode_t *iter = NULL, *node = NULL; + struct uci_section *d; + char *duid = NULL; + char ctime[MAX_LEN_32] = {0}; + + if (!sec) + return; + + const char *name = swmod_uci_get_value_by_section(sec, "name"); + if (strlen(name) == 0) { + return; + } + + if (!dir_exist(name)) { + /* Create non existing execenv */ + if (!create_dir(name)) + swmod_uci_set_value_by_section(sec, "status", "Error"); + + swmod_uci_set_value_by_section(sec, "action", ""); + return; + } + + const char *eu_runlevel = swmod_uci_get_value_by_section(sec, "initial_eu_runlevel"); + /* dir already exists, need to sync DUs */ + memset(&du_head, 0, sizeof(struct list_head)); + INIT_LIST_HEAD(&du_head); + + swmod_get_du_list(name, eu_runlevel, &du_head); + + list_for_each_entry_safe(iter, node, &du_head, list) { + bool found = false; + swmod_uci_foreach_section(SWMOD_UCI_FILE, "du_eu_assoc", d) { + if (strcmp(iter->du.du_name, d->e.name) == 0) { + found = true; + break; + } + } + + if (found == false) { + if (!swmod_du_type_capable(iter->du.du_type)) { + char path[2056] = {0}; + snprintf(path, sizeof(path), "%s/%s", iter->du.execenv, iter->du.du_name); + remove_dir(path); + continue; + } + + duid = generate_duid(iter->du.execenv, iter->du.du_name); + + struct uci_section *s = swmod_uci_add_section(SWMOD_UCI_FILE, "du_eu_assoc", iter->du.du_name); + swmod_uci_set_value_by_section(s, "uuid", generate_uuid()); + swmod_uci_set_value_by_section(s, "duid", duid ? duid : ""); + swmod_uci_set_value_by_section(s, "status", "Installed"); + swmod_uci_set_value_by_section(s, "url", ""); + swmod_uci_set_value_by_section(s, "description", ""); + swmod_uci_set_value_by_section(s, "version", ""); + swmod_uci_set_value_by_section(s, "du_type", (iter->du.du_type == DU_TYPE_CRUN) ? "OCIImage" : "LXC"); + time_t now = time(NULL); + strftime(ctime, sizeof(ctime), "%Y-%m-%dT%H:%M:%SZ", gmtime(&now)); + swmod_uci_set_value_by_section(s, "installed_at", ctime); + swmod_uci_set_value_by_section(s, "eu_autostart", "1"); + swmod_uci_set_value_by_section(s, "eu_runlevel", strlen(iter->du.eu_runlevel) ? iter->du.eu_runlevel : "0"); + swmod_uci_set_value_by_section(s, "execenv", iter->du.execenv); + FREE(duid); + } + } + + swmod_free_du_list(&du_head); + swmod_uci_set_value_by_section(sec, "action", ""); +} + +void swmod_execenv_remove(struct uci_section *sec, bool force) +{ + struct uci_section *d; + int du_count = 0; + bool env_busy = false; + + if (!sec) + return; + + const char *name = swmod_uci_get_value_by_section(sec, "name"); + if (strlen(name) == 0) { + swmod_uci_set_value_by_section(sec, "action", ""); + return; + } + + if (!dir_exist(name)) { + swmod_uci_delete_by_section(sec, NULL, NULL); + return; + } + + swmod_uci_foreach_section(SWMOD_UCI_FILE, "du_eu_assoc", d) { + const char *execenv = swmod_uci_get_value_by_section(d, "execenv"); + if (strcmp(execenv, name) == 0) { + du_count++; + char *du_status = swmod_uci_get_value_by_section(d, "status"); + if (strcmp(du_status, "Installed") != 0) { + env_busy = true; + break; + } + } + } + + if (env_busy || (du_count > 0 && force == false)) { + swmod_uci_set_value_by_section(sec, "action", ""); + return; + } + + if (du_count == 0) { + swmod_uci_delete_by_section(sec, NULL, NULL); + remove_dir(name); + return; + } + + /* Stop all EUs then remove execenv */ + swmod_uci_foreach_section(SWMOD_UCI_FILE, "du_eu_assoc", d) { + const char *execenv = swmod_uci_get_value_by_section(d, "execenv"); + const char *type = swmod_uci_get_value_by_section(d, "du_type"); + if (strcmp(execenv, name) == 0) { + swmod_stop_execunit(execenv, d->e.name, type); + swmod_uci_delete_by_section(d, NULL, NULL); + } + } + + swmod_uci_delete_by_section(sec, NULL, NULL); + remove_dir(name); +} + +void swmod_perform_du_operation(struct ubus_context *ubus_ctx, PkgInfo *pkg, size_t size) +{ + int fd[2]; + + if (!pkg) { + PRINT_ERR("No package info!"); + return; + } + + if (pipe(fd) < 0) { + PRINT_ERR("Pipe failed!"); + return; + } + + pid_t child = fork(); + if (child == -1) { + PRINT_ERR("Fork error!"); + return; + } else if(child != 0) { + // parent + close(fd[0]); + write(fd[1], pkg, size); + close(fd[1]); + } else { + // child + prctl(PR_SET_NAME, "swmod_du_operation"); + ubus_shutdown(ubus_ctx); + uloop_done(); + close(fd[1]); + + char fault[256] = {0}; + int fault_code = 0; + PkgInfo p_info; + time_t start; + + memset(&p_info, 0, sizeof(PkgInfo)); + if (read(fd[0], &p_info, sizeof(PkgInfo)) == -1) { + close(fd[0]); + PRINT_ERR("Package info read failed!"); + exit(EXIT_FAILURE); + } + + close(fd[0]); + + start = time(NULL); + fault_code = invalid_du_request(&p_info, fault); + + if (fault_code) { + swmod_send_event_du_state_change(&p_info, fault_code, fault, start); + exit(EXIT_SUCCESS); + } - if (strcmp(ee_name, ee) == 0 && strcmp(eu_name, eu) == 0) { - swmod_uci_set_value_by_section(s, "eu_alias", alias); - ret = 0; + switch (p_info.operation) { + case SWMOD_INSTALL: + swmod_perform_du_install(&p_info, start); + break; + case SWMOD_REMOVE: break; } + + exit(EXIT_SUCCESS); } +} - swmod_uci_fini(uci_file); +void swmod_send_event_du_state_change(PkgInfo *pkg, int err_code, char *msg, time_t start) +{ + char start_time[MAX_LEN_32] = {0}; + char end_time[MAX_LEN_32] = {0}; + time_t end; + struct ubus_context *ctx; // This function will be invoked from child so need ubus context */ + char *operation = NULL; + char *state = NULL; + struct blob_buf bb; + unsigned int id; + + if (!pkg) + return; - return ret; + ctx = ubus_connect(NULL); + + if (!ctx) + return; + + end = time(NULL); + + strftime(start_time, sizeof(start_time), "%Y-%m-%dT%H:%M:%SZ", gmtime(&start)); + strftime(end_time, sizeof(end_time), "%Y-%m-%dT%H:%M:%SZ", gmtime(&end)); + + switch (pkg->operation) { + case SWMOD_INSTALL: + operation = "Install"; + state = (err_code) ? "Failed" : "Installed"; + break; + case SWMOD_REMOVE: + operation = "Uninstall"; + state = (err_code) ? "Failed" : "Installed"; + break; + } + + memset(&bb, 0, sizeof(struct blob_buf)); + blob_buf_init(&bb, 0); + + blobmsg_add_string(&bb, "name", "Device.SoftwareModules.DUStateChange!"); + + void *tbl = blobmsg_open_table(&bb, "input"); + blobmsg_add_string(&bb, "UUID", pkg->uuid); + blobmsg_add_string(&bb, "Version", pkg->version); + blobmsg_add_string(&bb, "CurrentState", state); + blobmsg_add_string(&bb, "Resolved", err_code ? "0" : "1"); + blobmsg_add_string(&bb, "StartTime", start_time); + blobmsg_add_string(&bb, "CompleteTime", end_time); + blobmsg_add_string(&bb, "OperationPerformed", operation); + blobmsg_add_u32(&bb, "Fault.FaultCode", err_code); + blobmsg_add_string(&bb, "Fault.FaultString", err_code ? msg : ""); + + blobmsg_close_table(&bb, tbl); + + if (!ubus_lookup_id(ctx, "bbfdm", &id)) + ubus_invoke(ctx, id, "notify_event", bb.head, NULL, NULL, UBUS_TIMEOUT); + + blob_buf_free(&bb); + ubus_free(ctx); + + return; } -int set_eu_autostart_to_config(const char *ee_name, const char *eu_name, - bool enable, const char *bundle, const char *uci_file) +int invalid_du_request(PkgInfo *pkg, char *fault) { - int ret = -1; + char du_name[256] = {0}; + char du_path[2056] = {0}; + struct uci_section *sec = NULL; - if (ee_name == NULL || eu_name == NULL || - bundle == NULL || uci_file == NULL) - return ret; + if (!pkg) { + snprintf(fault, MAX_LEN_256, "Internal error"); + return 7002; + } - if (strlen(bundle) == 0) - return ret; + switch (pkg->operation) { + case SWMOD_INSTALL: + if (swmod_uci_init(STD_UCI_PATH) != 0) { + snprintf(fault, MAX_LEN_256, "Internal error"); + return 7002; + } - if (strlen(uci_file) == 0) - return ret; + if (strlen(pkg->url) == 0) { + snprintf(fault, MAX_LEN_256, "DU URL is empty"); + swmod_uci_fini(SWMOD_UCI_FILE); + return 7002; + } - if (swmod_uci_init(bundle) != 0) - return ret; + /* extract du name from url and validate */ + if (get_filename_from_url(pkg->url, du_name, sizeof(du_name)) != 0) { + snprintf(fault, MAX_LEN_256, "DU name invalid"); + swmod_uci_fini(SWMOD_UCI_FILE); + return 7002; + } - struct uci_section *s = NULL, *stmp = NULL; - swmod_uci_foreach_section_safe(uci_file, "du_eu_assoc", stmp, s) { - char *ee = swmod_uci_get_value_by_section(s, "ee_name"); - char *eu = swmod_uci_get_value_by_section(s, "eu_name"); + snprintf(du_path, sizeof(du_path), "%s/%s", pkg->execenv, du_name); + if (dir_exist(du_path)) { + snprintf(fault, MAX_LEN_256, "DU with name (%s) already exist.", du_name); + swmod_uci_fini(SWMOD_UCI_FILE); + return 7226; + } + + sec = NULL; + swmod_uci_foreach_section(SWMOD_UCI_FILE, "du_eu_assoc", sec) { + if (strcmp(du_name, sec->e.name) == 0) { + snprintf(fault, MAX_LEN_256, "DU with name (%s) already exist.", du_name); + swmod_uci_fini(SWMOD_UCI_FILE); + return 7226; + } + } + + snprintf(pkg->du_name, sizeof(pkg->du_name), "%s", du_name); + + /* Check if URL has user info */ + if (strncmp(pkg->url, "docker://", 9) != 0 && strchr(pkg->url, '@') != NULL) { + /* In docker link there could be '@' for specific sha */ + snprintf(fault, MAX_LEN_256, "URL contains user info"); + swmod_uci_fini(SWMOD_UCI_FILE); + return 7004; + } + + if (strlen(pkg->execenv) == 0) { + snprintf(fault, MAX_LEN_256, "No suitable execution environment, may be all are busy as of now."); + swmod_uci_fini(SWMOD_UCI_FILE); + return 7225; + } else { + /* Check if the execenv exists then it is enabled and not busy in any operation */ + int err_code = 7223; + sec = NULL; + + snprintf(fault, MAX_LEN_256, "Unknown execution environment."); + + swmod_uci_foreach_section(SWMOD_UCI_FILE, "execenv", sec) { + const char *execenv = swmod_uci_get_value_by_section(sec, "name"); + + if (strcmp(execenv, pkg->execenv) == 0) { + const char *enable = swmod_uci_get_value_by_section(sec, "enable"); + const char *action = swmod_uci_get_value_by_section(sec, "action"); + if (strlen(action) == 0 && enable[0] == '1') + err_code = 0; + else { + snprintf(fault, MAX_LEN_256, "Execution environment is busy or disabled."); + err_code = 7002; + } + + break; + } + + } + + if (err_code != 0) { + swmod_uci_fini(SWMOD_UCI_FILE); + return err_code; + } + } + + swmod_uci_fini(SWMOD_UCI_FILE); + if (!valid_uuid(pkg->uuid)) { + snprintf(fault, MAX_LEN_256, "Invalid UUID."); + return 7002; + } + + break; + case SWMOD_REMOVE: + break; + } + + return 0; +} + +void swmod_perform_du_install(PkgInfo *pkg, time_t start) +{ + int err = 7002; + char msg[256] = {0}; + char *duid = NULL; + struct uci_section *sec = NULL; + char ctime[MAX_LEN_32] = {0}; + + snprintf(msg, sizeof(msg), "Internal error!"); + + if (swmod_uci_init(STD_UCI_PATH) != 0) { + swmod_send_event_du_state_change(pkg, err, msg, start); + return; + } + + duid = generate_duid(pkg->execenv, pkg->du_name); + + sec = swmod_uci_add_section(SWMOD_UCI_FILE, "du_eu_assoc", pkg->du_name); + swmod_uci_set_value_by_section(sec, "url", pkg->url); + swmod_uci_set_value_by_section(sec, "uuid", pkg->uuid); + swmod_uci_set_value_by_section(sec, "status", "Installing"); + swmod_uci_set_value_by_section(sec, "duid", duid ? duid : ""); + swmod_uci_set_value_by_section(sec, "execenv", pkg->execenv); + + err = swmod_install_package(pkg); - if (strcmp(ee_name, ee) == 0 && strcmp(eu_name, eu) == 0) { - swmod_uci_set_value_by_section(s, "autostart", enable ? "1" : "0"); - ret = 0; + time_t now = time(NULL); + strftime(ctime, sizeof(ctime), "%Y-%m-%dT%H:%M:%SZ", gmtime(&now)); + + if (!err) { + struct uci_section *env = NULL; + + swmod_uci_set_value_by_section(sec, "status", "Installed"); + swmod_uci_set_value_by_section(sec, "du_type", (pkg->du_type == DU_TYPE_CRUN) ? "OCIImage" : "LXC"); + swmod_uci_set_value_by_section(sec, "installed_at", ctime); + swmod_uci_set_value_by_section(sec, "eu_autostart", pkg->autostart ? "1" : "0"); + + check_section_exist_by_option("swmodd", "execenv", "name", pkg->execenv, &env); + if (env) { + const char *eu_runlevel = swmod_uci_get_value_by_section(env, "initial_eu_runlevel"); + swmod_uci_set_value_by_section(sec, "eu_runlevel", eu_runlevel); + } + + swmod_send_event_du_state_change(pkg, err, "", start); + } else { + switch (err) { + case 7227: + snprintf(msg, sizeof(msg), "Memory not available."); + break; + case 7225: + snprintf(msg, sizeof(msg), "DU type to execution environment mismatch"); + break; + case 7033: + snprintf(msg, sizeof(msg), "Download failure from server"); + break; + case 7035: + snprintf(msg, sizeof(msg), "Corrupt of empty package or the package is not available."); break; } + + swmod_send_event_du_state_change(pkg, err, msg, start); + swmod_uci_delete_by_section(sec, NULL, NULL); } - swmod_uci_fini(uci_file); + FREE(duid); + swmod_uci_fini(SWMOD_UCI_FILE); +} + +int swmod_install_package(PkgInfo *pkg) +{ + int ret = 0; + + if (!pkg) + return 7002; + + char *tmp = strrchr(pkg->url, '.'); + if (tmp != NULL && strcmp(tmp, ".tar") == 0) { + char path[2056] = {0}; + bool remote_file = false; + + /* This is a tar package need to extract */ + if (strstr(pkg->url, "file://") == NULL) { + // remote tar package download + remote_file = true; + ret = download_remote_du(pkg); + snprintf(path, sizeof(path), "/tmp/%s.tar", pkg->du_name); + } else { + snprintf(path, sizeof(path), "%s", pkg->url+6); + } + + if (ret) + return ret; - if (ret == 0) - swmod_uci_commit("crun"); + ret = install_du_package(path, pkg); + if (remote_file && file_exists(path)) + remove(path); + } else { + // registry image + } return ret; } + +int install_du_package(char *url, PkgInfo *pkg) +{ + char cmd[2056] = {0}; + char bundle_dir[515] = {0}; + + if (!url || strlen(url) == 0 || !pkg || strlen(pkg->execenv) == 0) + return 7002; + + unsigned long size = get_file_size_kb(url); + if (size == 0) + return 7035; + + if (!memory_available(size * 2, pkg->execenv)) + return 7227; + + snprintf(bundle_dir, sizeof(bundle_dir), "%s/%s", pkg->execenv, pkg->du_name); + if (!create_dir(bundle_dir)) + return 7002; + + snprintf(cmd, sizeof(cmd), "tar -xf %s -C %s", url, bundle_dir); + + if (0 != run_cmd_no_output(cmd)) { + remove_dir(bundle_dir); + return 7002; + } + + pkg->du_type = swmod_du_type(bundle_dir); + if (pkg->du_type == DU_TYPE_MAX || !swmod_du_type_capable(pkg->du_type)) { + remove_dir(bundle_dir); + return 7225; + } + + return 0; +} + +int download_remote_du(PkgInfo *pkg) +{ + char path[515] = {0}; + + if (!pkg) + return 7002; + + unsigned long size = get_remote_file_size(pkg->url, pkg->uname, pkg->psw); + if (size == 0) + return 7002; + + if (!memory_available(size, "/tmp")) + return 7227; + + snprintf(path, sizeof(path), "/tmp/%s.tar", pkg->du_name); + if (0 != download_remote_package(pkg->url, pkg->uname, pkg->psw, path)) { + if (file_exists(path)) + remove(path); + + return 7033; + } + + return 0; +} + +char *swmod_select_env(void) +{ + /* Select an execenv which is not busy and enabled */ + char *env = NULL; + struct uci_section *sec = NULL; + + if (swmod_uci_init(STD_UCI_PATH) != 0) { + return env; + } + + swmod_uci_foreach_section(SWMOD_UCI_FILE, "execenv", sec) { + const char *execenv = swmod_uci_get_value_by_section(sec, "name"); + const char *enable = swmod_uci_get_value_by_section(sec, "enable"); + const char *action = swmod_uci_get_value_by_section(sec, "action"); + + if (strlen(action) == 0 && enable[0] == '1') { + env = strdup(execenv); + break; + } + } + + swmod_uci_fini(STD_UCI_PATH); + + return env; +} diff --git a/src/tools.h b/src/tools.h index 07b0122..bfba140 100644 --- a/src/tools.h +++ b/src/tools.h @@ -16,55 +16,17 @@ #include <time.h> #include <libubox/list.h> #include <syslog.h> +#include <uci.h> #include "swmod.h" -#define OPKG_INFO_PATH "/usr/lib/opkg/info/" #define STD_UCI_PATH "/etc/config/" #define SWMOD_UCI_FILE "swmodd" -#define SWMOD_OCI_DU_UCI "ocicontainer" -#define SWMOD_LXC_DU_UCI "lxccontainer" -#define SWMOD_INIT_PATH "/etc/init.d/" - -#define SYSFS_FOREACH_FILE(path, dir, ent) \ - if ((dir = opendir(path)) == NULL) return 0; \ - while ((ent = readdir (dir)) != NULL) \ #ifndef FREE #define FREE(x) do { if(x) {free(x); x = NULL;} } while (0) #endif -enum swmod_action_enum { - SWMOD_DEPLOYMENT_UNIT, - SWMOD_EXECUTION_UNIT -}; - -enum { - SUCCESS, - FAILURE, - LXC_NOT_SUPPORTED, - NOT_FOUND, - ALREADY_RUNNING, - NOT_RUNNING, - INVALID_REQUEST, - CRUN_NOT_SUPPORTED, - __ERROR_MAX -}; - -enum { - CONT_START, - CONT_STOP, - CONT_PAUSE, - CONT_RESUME, - __CONT_STATE_MAX -}; - -struct buffer_list -{ - struct list_head list; - char line[MAX_LEN_128]; -}; - bool file_exists(const char *path); unsigned long get_file_size_kb(const char *path); bool create_dir(const char *path); @@ -74,7 +36,7 @@ void remove_new_line(char *buf); void create_file(const char *path); void swmod_strncpy(char *dst, const char *src, size_t n); char *generate_uuid(void); -char *generate_duid(bool sysnchronise, int number); +char *generate_duid(const char *ee_name, const char *du_name); int wait_for_pid(pid_t pid); void configure_debug_level(unsigned char level); @@ -82,36 +44,29 @@ void print_error(const char *format, ...); void print_warning(const char *format, ...); void print_info(const char *format, ...); void print_debug(const char *format, ...); -int get_pid_details(int pid, char *cmdline, int cmd_len, int *vsize); -int update_eu_from_blob(ExecEnv_t *env, struct blob_attr *msg, ExecUnit *node); +//int get_pid_details(int pid, char *cmdline, int cmd_len, int *vsize); int ubus_call_service_state(char *service, bool state); bool dir_exist(const char *dir); -bool get_autoboot_from_config_file(const char *env, const char *lxc_uci_path); -void set_autoboot_to_config_file(const char *env, bool state, const char *lxc_uci_path); -int get_timeout_from_config_file(const char *env, const char *lxc_uci_path); -void swmod_add_eu_in_list(struct list_head *eu_list, ExecUnit *eu); -void swmod_delete_eu_list(struct list_head *eu_list); -void swmod_add_ee_in_list(struct list_head *ee_list, ExecEnv_t *eu); -void swmod_delete_ee_list(struct list_head *ee_list); -void sync_eeid_with_uci(struct list_head *ee_list, ExecEnv_t *environments, const char *lxc_uci_path); -void get_swmod_config_params(ConfigParams *cfg); -const char* ee_state_failure_reason(int err); -int get_requested_container_state(char *state); -int get_env_type(const char *type); -bool valid_uuid(char *uuid, const char *lxc_uci_path, const char *oci_uci_path); -void get_opkg_description(ExecEnv_t *env, const char *pkg_name, char *desc, size_t desc_size); -void get_opkg_service_name(ExecEnv_t *env, const char *pkg_name, char *service, size_t serv_size); -void buffer_add_line(struct list_head *head, char *entry); -void create_buffer_list(struct list_head *opkg_list, char *buffer); -void delete_buffer_list(struct list_head *opkg_list); +bool valid_uuid(char *uuid); time_t convert_str_to_time(const char *time); -int swmod_ee_uci_init(ExecEnv_t *env, char *uci_file, int len); -int set_du_alias_to_config(const char *ee_name, const char *uuid, - const char *alias, const char *bundle, const char *uci_file); -int set_eu_alias_to_config(const char *ee_name, const char *eu_name, - const char *alias, const char *bundle, const char *uci_file); -int set_eu_autostart_to_config(const char *ee_name, const char *eu_name, - bool enable, const char *bundle, const char *uci_file); + +void remove_dir(const char *path); +void swmod_reset_ee_runlevel(struct uci_section *sec); +void swmod_update_du_eu_assoc(struct list_head *du_head); +int swmod_du_type(char *du_path); +void swmod_get_du_list(const char *base_path, const char *eu_runlevel, struct list_head *du_head); +void swmod_free_du_list(struct list_head *du_head); +int swmod_du_remove(struct uci_section *sec); +void swmod_execenv_add(struct uci_section *sec); +void swmod_execenv_remove(struct uci_section *sec, bool force); +char *swmod_select_env(void); +void swmod_perform_du_operation(struct ubus_context *ubus_ctx, PkgInfo *pkg, size_t size); +int invalid_du_request(PkgInfo *pkg, char *fault); +void swmod_send_event_du_state_change(PkgInfo *pkg, int err_code, char *msg, time_t start); +void swmod_perform_du_install(PkgInfo *pkg, time_t start); +int swmod_install_package(PkgInfo *pkg); +int install_du_package(char *url, PkgInfo *pkg); +int download_remote_du(PkgInfo *pkg); #define PRINT_DEBUG(fmt, args...) \ print_debug("[%s:%d]"fmt, __func__, __LINE__, ##args) -- GitLab