/* copy the variables to shm mem */ int cfg_shmize(void) { cfg_group_t *group; cfg_block_t *block = NULL; int size; if (!cfg_group) return 0; /* Let us allocate one memory block that will contain all the variables */ for ( size=0, group = cfg_group; group; group=group->next ) { size = ROUND_POINTER(size); group->offset = size; size += group->size; } block = (cfg_block_t*)shm_malloc(sizeof(cfg_block_t)+size-1); if (!block) { LOG(L_ERR, "ERROR: cfg_clone_str(): not enough shm memory\n"); goto error; } memset(block, 0, sizeof(cfg_block_t)+size-1); cfg_block_size = size; /* copy the memory fragments to the single block */ for ( group = cfg_group; group; group=group->next ) { if (group->dynamic == 0) { /* clone the strings to shm mem */ if (cfg_shmize_strings(group)) goto error; /* copy the values to the new block */ memcpy(block->vars+group->offset, group->vars, group->size); } else { /* The group was declared with NULL values, * we have to fix it up. * The fixup function takes care about the values, * it fills up the block */ if (cfg_script_fixup(group, block->vars+group->offset)) goto error; /* Notify the drivers about the new config definition. * Temporary set the group handle so that the drivers have a chance to * overwrite the default values. The handle must be reset after this * because the main process does not have a local configuration. */ *(group->handle) = block->vars+group->offset; cfg_notify_drivers(group->name, group->name_len, group->mapping->def); *(group->handle) = NULL; } } /* try to fixup the selects that failed to be fixed-up previously */ if (cfg_fixup_selects()) goto error; /* install the new config */ cfg_install_global(block, NULL, NULL, NULL); cfg_shmized = 1; return 0; error: if (block) shm_free(block); return -1; }
/* allocates memory for a new config script variable * The value of the variable is not set! */ cfg_script_var_t *new_cfg_script_var(char *gname, char *vname, unsigned int type, char *descr) { cfg_group_t *group; cfg_script_var_t *var; int gname_len, vname_len, descr_len; LOG(L_DBG, "DEBUG: new_cfg_script_var(): declaring %s.%s\n", gname, vname); if (cfg_shmized) { LOG(L_ERR, "ERROR: new_cfg_script_var(): too late variable declaration, " "the config has been already shmized\n"); return NULL; } gname_len = strlen(gname); vname_len = strlen(vname); /* the group may have been already declared */ group = cfg_lookup_group(gname, gname_len); if (group) { if (group->dynamic == CFG_GROUP_STATIC) { /* the group has been already declared by a module or by the core */ LOG(L_ERR, "ERROR: new_cfg_script_var(): " "configuration group has been already declared: %s\n", gname); return NULL; } /* the dynamic or empty group is found */ /* verify that the variable does not exist */ for ( var = (cfg_script_var_t *)group->vars; var; var = var->next ) { if ((var->name_len == vname_len) && (memcmp(var->name, vname, vname_len) == 0)) { LOG(L_ERR, "ERROR: new_cfg_script_var(): variable already exists: %s.%s\n", gname, vname); return NULL; } } if (group->dynamic == CFG_GROUP_UNKNOWN) group->dynamic = CFG_GROUP_DYNAMIC; } else { /* create a new group with NULL values, we will fix it later, when all the variables are known */ group = cfg_new_group(gname, gname_len, 0 /* num */, NULL /* mapping */, NULL /* vars */, 0 /* size */, NULL /* handle */); if (!group) goto error; group->dynamic = CFG_GROUP_DYNAMIC; } switch (type) { case CFG_VAR_INT: group->size = ROUND_INT(group->size); group->size += sizeof(int); break; case CFG_VAR_STR: group->size = ROUND_POINTER(group->size); group->size += sizeof(str); break; default: LOG(L_ERR, "ERROR: new_cfg_script_var(): unsupported variable type\n"); return NULL; } group->num++; if (group->num > CFG_MAX_VAR_NUM) { LOG(L_ERR, "ERROR: new_cfg_script_var(): too many variables (%d) within a single group," " the limit is %d. Increase CFG_MAX_VAR_NUM, or split the group into multiple" " definitions.\n", group->num, CFG_MAX_VAR_NUM); return NULL; } var = (cfg_script_var_t *)pkg_malloc(sizeof(cfg_script_var_t)); if (!var) goto error; memset(var, 0, sizeof(cfg_script_var_t)); var->type = type; /* add the variable to the group */ var->next = (cfg_script_var_t *)(void *)group->vars; group->vars = (char *)(void *)var; /* clone the name of the variable */ var->name = (char *)pkg_malloc(sizeof(char) * (vname_len + 1)); if (!var->name) goto error; memcpy(var->name, vname, vname_len + 1); var->name_len = vname_len; if (descr) { /* save the description */ descr_len = strlen(descr); var->descr = (char *)pkg_malloc(sizeof(char) * (descr_len + 1)); if (!var->descr) goto error; memcpy(var->descr, descr, descr_len + 1); } return var; error: LOG(L_ERR, "ERROR: new_cfg_script_var(): not enough memory\n"); return NULL; }
/* copy the variables to shm mem */ int cfg_shmize(void) { cfg_group_t *group; cfg_block_t *block = NULL; int size; if (!cfg_group) return 0; /* Let us allocate one memory block that * will contain all the variables + meta-data * in the following form: * |-----------| * | meta-data | <- group A: meta_offset * | variables | <- group A: var_offset * |-----------| * | meta-data | <- group B: meta_offset * | variables | <- group B: var_offset * |-----------| * | ... | * |-----------| * * The additional array for the multiple values * of the same variable is linked to the meta-data. */ for ( size=0, group = cfg_group; group; group=group->next ) { size = ROUND_POINTER(size); group->meta_offset = size; size += sizeof(cfg_group_meta_t); size = ROUND_POINTER(size); group->var_offset = size; size += group->size; } block = (cfg_block_t*)shm_malloc(sizeof(cfg_block_t)+size-1); if (!block) { LOG(L_ERR, "ERROR: cfg_shmize(): not enough shm memory\n"); goto error; } memset(block, 0, sizeof(cfg_block_t)+size-1); cfg_block_size = size; /* copy the memory fragments to the single block */ for ( group = cfg_group; group; group=group->next ) { if (group->dynamic == CFG_GROUP_STATIC) { /* clone the strings to shm mem */ if (cfg_shmize_strings(group)) goto error; /* copy the values to the new block */ memcpy(CFG_GROUP_DATA(block, group), group->vars, group->size); } else if (group->dynamic == CFG_GROUP_DYNAMIC) { /* The group was declared with NULL values, * we have to fix it up. * The fixup function takes care about the values, * it fills up the block */ if (cfg_script_fixup(group, CFG_GROUP_DATA(block, group))) goto error; /* Notify the drivers about the new config definition. * Temporary set the group handle so that the drivers have a chance to * overwrite the default values. The handle must be reset after this * because the main process does not have a local configuration. */ *(group->handle) = CFG_GROUP_DATA(block, group); cfg_notify_drivers(group->name, group->name_len, group->mapping->def); *(group->handle) = NULL; } else { LOG(L_ERR, "ERROR: cfg_shmize(): Configuration group is declared " "without any variable: %.*s\n", group->name_len, group->name); goto error; } /* Create the additional group instances with applying the temporary list. */ if (apply_add_var_list(block, group)) goto error; } /* try to fixup the selects that failed to be fixed-up previously */ if (cfg_fixup_selects()) goto error; /* install the new config */ cfg_install_global(block, NULL, NULL, NULL); cfg_shmized = 1; return 0; error: if (block) shm_free(block); return -1; }
/* fix-up the dynamically declared group: * - allocate memory for the arrays * - set the values within the memory block */ int cfg_script_fixup(cfg_group_t *group, unsigned char *block) { cfg_mapping_t *mapping = NULL; cfg_def_t *def = NULL; void **handle = NULL; int i, offset; cfg_script_var_t *script_var, *script_var2; str s; mapping = (cfg_mapping_t *)pkg_malloc(sizeof(cfg_mapping_t)*group->num); if (!mapping) goto error; memset(mapping, 0, sizeof(cfg_mapping_t)*group->num); /* The variable definition array must look like as if it was declared * in C code, thus, add an additional slot at the end with NULL values */ def = (cfg_def_t *)pkg_malloc(sizeof(cfg_def_t)*(group->num + 1)); if (!def) goto error; memset(def, 0, sizeof(cfg_def_t)*(group->num + 1)); /* fill the definition and the mapping arrays */ offset = 0; for ( i = 0, script_var = (cfg_script_var_t *)group->vars; script_var; i++, script_var = script_var->next ) { /* there has been already memory allocated for the name */ def[i].name = script_var->name; def[i].type = script_var->type | (script_var->type << CFG_INPUT_SHIFT); def[i].descr = script_var->descr; def[i].min = script_var->min; def[i].max = script_var->max; mapping[i].def = &(def[i]); mapping[i].name_len = script_var->name_len; mapping[i].pos = i; switch (script_var->type) { case CFG_VAR_INT: offset = ROUND_INT(offset); mapping[i].offset = offset; *(int *)(block + offset) = script_var->val.i; offset += sizeof(int); break; case CFG_VAR_STR: offset = ROUND_POINTER(offset); mapping[i].offset = offset; if (cfg_clone_str(&(script_var->val.s), &s)) goto error; memcpy(block + offset, &s, sizeof(str)); mapping[i].flag |= cfg_var_shmized; offset += sizeof(str); break; } } /* allocate a handle even if it will not be used to directly access the variable, like handle->variable cfg_get_* functions access the memory block via the handle to make sure that it is always safe, thus, it must be created */ handle = (void **)pkg_malloc(sizeof(void *)); if (!handle) goto error; *handle = NULL; group->handle = handle; group->mapping = mapping; /* everything went fine, we can free the temporary list */ script_var = (cfg_script_var_t *)group->vars; group->vars = NULL; while (script_var) { script_var2 = script_var->next; if ((script_var->type == CFG_VAR_STR) && script_var->val.s.s) pkg_free(script_var->val.s.s); pkg_free(script_var); script_var = script_var2; } return 0; error: if (mapping) pkg_free(mapping); if (def) pkg_free(def); if (handle) pkg_free(handle); LOG(L_ERR, "ERROR: cfg_script_fixup(): not enough memory\n"); return -1; }