* This file is part of the oGRAC project.
* Copyright (c) 2024 Huawei Technologies Co.,Ltd.
*
* oGRAC is licensed under Mulan PSL v2.
* You can use this software according to the terms and conditions of the Mulan PSL v2.
* You may obtain a copy of Mulan PSL v2 at:
*
* http://license.coscl.org.cn/MulanPSL2
*
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
* See the Mulan PSL v2 for more details.
* -------------------------------------------------------------------------
*
* cm_config.c
*
*
* IDENTIFICATION
* src/common/cm_config.c
*
* -------------------------------------------------------------------------
*/
#include "cm_common_module.h"
#include "cm_config.h"
#include "cm_hash.h"
#include "cm_file.h"
#ifndef WIN32
#include <termios.h>
#else
#include <conio.h>
#endif
#ifdef __cplusplus
extern "C" {
#endif
static spinlock_t g_config_lock = 0;
static status_t cm_parse_config(config_t *config, char *buf, uint32 buf_len, bool32 is_ifile, bool32 set_alias);
static status_t cm_set_config_item(config_t *config, text_t *name, text_t *value, text_t *comment,
bool32 is_infile, bool32 set_alias);
static status_t cm_alloc_config_buf(config_t *config, uint32 size_input, char **buf)
{
uint32 size = size_input;
CM_POINTER2(config, buf);
errno_t errcode = 0;
if (config->value_buf == NULL) {
if (config->value_buf_size == 0) {
OG_THROW_ERROR(ERR_ALLOC_MEMORY, (uint64)config->value_buf_size, "config value");
return OG_ERROR;
}
config->value_buf = (char *)malloc(config->value_buf_size);
if (config->value_buf == NULL) {
OG_THROW_ERROR(ERR_ALLOC_MEMORY, (uint64)config->value_buf_size, "config value");
return OG_ERROR;
}
errcode = memset_sp(config->value_buf, (size_t)config->value_buf_size, 0, (size_t)config->value_buf_size);
if (errcode != EOK) {
CM_FREE_PTR(config->value_buf);
OG_THROW_ERROR(ERR_RESET_MEMORY, "config->value_buf");
return OG_ERROR;
}
}
size = CM_ALIGN4(size);
if (config->value_offset + size > config->value_buf_size) {
OG_THROW_ERROR(ERR_CONFIG_BUFFER_FULL);
return OG_ERROR;
}
*buf = config->value_buf + config->value_offset;
config->value_offset += size;
return OG_SUCCESS;
}
config_item_t* cm_get_config_item(const config_t *config, text_t *name, bool32 set_alias)
{
uint32 hash_value;
config_item_t *item = NULL;
CM_POINTER2(config, name);
hash_value = cm_hash_text(name, OG_CONFIG_HASH_BUCKETS);
item = config->name_map[hash_value];
while (item != NULL) {
if (cm_text_str_equal_ins(name, item->name)) {
if (set_alias) {
item->hit_alias = OG_FALSE;
}
return item;
}
item = item->hash_next;
}
hash_value = cm_hash_text(name, OG_CONFIG_ALIAS_HASH_BUCKETS);
item = config->alias_map[hash_value];
while (item != NULL) {
if (cm_text_str_equal_ins(name, item->alias)) {
if (set_alias) {
item->hit_alias = OG_TRUE;
}
return item;
}
item = item->hash_next2;
}
return NULL;
}
char *cm_get_config_value(const config_t *config, const char *name)
{
config_item_t *item = NULL;
text_t text;
CM_POINTER(config);
cm_str2text((char *)name, &text);
item = cm_get_config_item(config, &text, OG_FALSE);
if (item == NULL) {
OG_THROW_ERROR(ERR_INVALID_PARAMETER_NAME, name);
return NULL;
}
if (item->is_default) {
return item->default_value;
}
return item->value;
}
static status_t cm_get_fullpath(config_t *config, text_t *filepath, char *fullpath, uint32 len)
{
text_t text;
char buf[OG_FILE_NAME_BUFFER_SIZE];
bool32 is_fullpath = (filepath->len == 0 || CM_TEXT_FIRST(filepath) == '/' || CM_TEXT_FIRST(filepath) == '\\');
#ifdef WIN32
is_fullpath = is_fullpath || (cm_get_first_pos(filepath, ':') != OG_INVALID_ID32);
#endif
if (!is_fullpath) {
text.str = buf;
text.len = 0;
OG_RETURN_IFERR(cm_concat_string(&text, OG_FILE_NAME_BUFFER_SIZE, config->file_name));
text.len = cm_get_last_pos(&text, '/');
if ((text.len == OG_INVALID_ID32) || (text.len + filepath->len + 1 >= len)) {
return OG_ERROR;
}
text.len++;
cm_concat_text(&text, OG_FILE_NAME_BUFFER_SIZE, filepath);
buf[text.len] = '\0';
} else {
OG_RETURN_IFERR(cm_text2str(filepath, buf, sizeof(buf)));
}
#ifdef WIN32
(void)_fullpath(fullpath, buf, len);
#else
char resolved_path[PATH_MAX];
uint32 path_len;
errno_t errcode;
if (realpath(buf, resolved_path) == NULL) {
OG_THROW_ERROR(ERR_PATH_NOT_EXIST_OR_ACCESSABLE, buf);
return OG_ERROR;
}
path_len = (uint32)strlen(resolved_path);
if (path_len >= len) {
OG_THROW_ERROR(ERR_INVALID_FILE_NAME, resolved_path, len);
return OG_ERROR;
}
errcode = strncpy_s(fullpath, (size_t)len, resolved_path, (size_t)path_len);
if (errcode != EOK) {
OG_THROW_ERROR(ERR_SYSTEM_CALL, errcode);
return OG_ERROR;
}
#endif
return OG_SUCCESS;
}
static status_t cm_set_ifile_value(config_t *config, config_item_t *ifile, const char *file_name, uint32 file_name_len)
{
uint32 file_name_size;
errno_t errcode;
file_name_size = file_name_len + 1;
if (cm_alloc_config_buf(config, file_name_size, &ifile->value) != OG_SUCCESS) {
return OG_ERROR;
}
if (cm_alloc_config_buf(config, file_name_size, &ifile->pfile_value) != OG_SUCCESS) {
return OG_ERROR;
}
errcode = strncpy_s(ifile->value, (size_t)file_name_size, file_name, (size_t)file_name_len);
if (errcode != EOK) {
OG_THROW_ERROR(ERR_SYSTEM_CALL, errcode);
return OG_ERROR;
}
errcode = strncpy_s(ifile->pfile_value, (size_t)file_name_size, file_name, (size_t)file_name_len);
if (errcode != EOK) {
OG_THROW_ERROR(ERR_SYSTEM_CALL, errcode);
return OG_ERROR;
}
ifile->is_diff = OG_FALSE;
return OG_SUCCESS;
}
static inline status_t cm_config_check_ifile_exists(config_t *config, const char *file_name)
{
config_item_t *next_file = config->first_file;
while (next_file != NULL) {
if (cm_str_equal_ins(next_file->value, file_name)) {
OG_THROW_ERROR(ERR_DUPLICATE_FILE, file_name);
return OG_ERROR;
}
next_file = next_file->next_file;
}
return OG_SUCCESS;
}
static status_t cm_set_config_ifile(config_t *config, text_t *value, config_item_t **item)
{
char file_name[OG_FILE_NAME_BUFFER_SIZE];
config_item_t *ifile = NULL;
uint32 buf_len = OG_MAX_CONFIG_FILE_SIZE;
status_t status;
char *file_buf = (char*)malloc(OG_MAX_CONFIG_FILE_SIZE);
if (file_buf == NULL || memset_sp(file_buf, OG_MAX_CONFIG_FILE_SIZE, 0, OG_MAX_CONFIG_FILE_SIZE) != EOK) {
CM_FREE_PTR(file_buf);
return OG_ERROR;
}
if (cm_get_fullpath(config, value, file_name, sizeof(file_name)) != OG_SUCCESS) {
CM_FREE_PTR(file_buf);
return OG_ERROR;
}
if (cm_read_config_file(file_name, file_buf, &buf_len, OG_TRUE, OG_TRUE) != OG_SUCCESS) {
CM_FREE_PTR(file_buf);
return OG_ERROR;
}
if (cm_alloc_config_buf(config, sizeof(config_item_t), (char **)&ifile) != OG_SUCCESS) {
CM_FREE_PTR(file_buf);
return OG_ERROR;
}
ifile->name = (char *)"IFILE";
ifile->is_default = OG_FALSE;
ifile->attr = ATTR_READONLY;
ifile->flag = FLAG_NONE;
ifile->next = ifile->next_file = NULL;
(*item) = ifile;
if (cm_config_check_ifile_exists(config, file_name) != OG_SUCCESS) {
CM_FREE_PTR(file_buf);
return OG_ERROR;
}
if (cm_set_ifile_value(config, ifile, file_name, (uint32)strlen(file_name)) != OG_SUCCESS) {
CM_FREE_PTR(file_buf);
return OG_ERROR;
}
if (config->first_file == NULL) {
config->first_file = ifile;
config->last_file = ifile;
} else {
config->last_file->next_file = ifile;
config->last_file = ifile;
}
status = cm_parse_config(config, file_buf, buf_len, OG_TRUE, OG_FALSE);
CM_FREE_PTR(file_buf);
return status;
}
static inline status_t cm_get_cfg_item_by_name(text_t *name, bool32 is_infile, config_item_t **item)
{
while (*item != NULL) {
if (cm_text_str_equal_ins(name, (*item)->name) ||
((*item)->alias != NULL && cm_text_str_equal_ins(name, (*item)->alias))) {
if (!is_infile && ((*item)->flag & FLAG_ZFILE)) {
OG_THROW_ERROR(ERR_DUPLICATE_PARAMETER, (*item)->name);
return OG_ERROR;
}
break;
}
*item = (*item)->next;
}
return OG_SUCCESS;
}
static inline status_t cm_check_invalid_cfg_item(config_item_t *item, text_t *name, text_t *value)
{
if (value->len >= OG_PARAM_BUFFER_SIZE && !(item->attr & ATTR_READONLY)) {
OG_THROW_ERROR(ERR_PARAMETER_TOO_LARGE, T2S(name), (int64)OG_PARAM_BUFFER_SIZE - 1);
return OG_ERROR;
}
if (cm_str_equal(item->name, "HAVE_SSL") || cm_str_equal(item->name, "_FACTOR_KEY")) {
OG_THROW_ERROR(ERR_INVALID_PARAMETER_NAME, T2S(name));
return OG_ERROR;
}
return OG_SUCCESS;
}
static inline status_t cm_set_cfg_item_value(config_t *config, config_item_t *item, text_t *value)
{
uint32 buf_size = (value->len >= OG_PARAM_BUFFER_SIZE) ? value->len + 1 : OG_PARAM_BUFFER_SIZE;
if (buf_size > OG_PARAM_BUFFER_SIZE || item->is_default) {
OG_RETURN_IFERR(cm_alloc_config_buf(config, buf_size, &item->value));
OG_RETURN_IFERR(cm_alloc_config_buf(config, buf_size, &item->pfile_value));
OG_RETURN_IFERR(cm_alloc_config_buf(config, buf_size, &item->runtime_value));
}
OG_RETURN_IFERR(cm_text2str(value, item->value, buf_size));
OG_RETURN_IFERR(cm_text2str(value, item->pfile_value, buf_size));
OG_RETURN_IFERR(cm_text2str(value, item->runtime_value, buf_size));
item->is_diff = OG_FALSE;
return OG_SUCCESS;
}
static inline status_t cm_set_cfg_item_comment(config_t *config, config_item_t *item, text_t *comment)
{
if (comment->len > 0) {
uint32 buf_size = comment->len + 1;
if (cm_alloc_config_buf(config, buf_size, &item->comment) != OG_SUCCESS) {
return OG_ERROR;
}
OG_RETURN_IFERR(cm_text2str(comment, item->comment, buf_size));
}
return OG_SUCCESS;
}
static status_t cm_set_config_item(config_t *config, text_t *name, text_t *value, text_t *comment, bool32 is_infile,
bool32 set_alias)
{
bool32 ifile_item = OG_FALSE;
config_item_t *item = NULL;
config_item_t *temp = NULL;
CM_POINTER3(config, value, comment);
if (cm_text_str_equal_ins(name, "IFILE")) {
if (is_infile) {
OG_THROW_ERROR(ERR_UNSUPPORTED_EMBEDDED_PARAMETER, T2S(name));
return OG_ERROR;
}
OG_RETURN_IFERR(cm_set_config_ifile(config, value, &item));
temp = NULL;
ifile_item = OG_TRUE;
} else {
item = cm_get_config_item(config, name, set_alias);
temp = config->first_item;
ifile_item = OG_FALSE;
}
if (item == NULL) {
if (!config->ignore) {
OG_THROW_ERROR(ERR_INVALID_PARAMETER_NAME, T2S(name));
return OG_ERROR;
}
return OG_SUCCESS;
}
OG_RETURN_IFERR(cm_get_cfg_item_by_name(name, is_infile, &temp));
if (!cm_str_equal(item->name, "CPU_GROUP_INFO")) {
OG_RETURN_IFERR(cm_check_invalid_cfg_item(item, name, value));
}
if (!ifile_item) {
OG_RETURN_IFERR(cm_set_cfg_item_value(config, item, value));
}
OG_RETURN_IFERR(cm_set_cfg_item_comment(config, item, comment));
item->is_default = OG_FALSE;
if (is_infile) {
item->flag |= FLAG_INFILE;
return OG_SUCCESS;
}
item->flag = FLAG_ZFILE;
if (config->first_item == NULL) {
config->first_item = item;
config->last_item = item;
} else if (temp == NULL) {
config->last_item->next = item;
config->last_item = item;
}
return OG_SUCCESS;
}
status_t cm_read_config_file(const char *file_name, char *buf, uint32 *buf_len, bool32 is_ifile,
bool32 read_only)
{
int32 file_fd;
status_t status;
uint32 mode = (read_only || is_ifile) ? (O_RDONLY | O_BINARY) : (O_CREAT | O_RDWR | O_BINARY);
if (!cm_file_exist(file_name)) {
OG_THROW_ERROR(ERR_FILE_NOT_EXIST, "config", file_name);
return OG_ERROR;
}
if (cm_open_file(file_name, mode, &file_fd) != OG_SUCCESS) {
return OG_ERROR;
}
int64 size = cm_file_size(file_fd);
if (size == -1) {
cm_close_file(file_fd);
OG_THROW_ERROR(ERR_SEEK_FILE, 0, SEEK_END, errno);
return OG_ERROR;
}
if (size > (int64)(*buf_len)) {
cm_close_file(file_fd);
OG_THROW_ERROR(ERR_FILE_SIZE_TOO_LARGE, file_name);
return OG_ERROR;
}
if (cm_seek_file(file_fd, 0, SEEK_SET) != 0) {
cm_close_file(file_fd);
OG_THROW_ERROR(ERR_SEEK_FILE, 0, SEEK_SET, errno);
return OG_ERROR;
}
status = cm_read_file(file_fd, buf, (int32)size, (int32 *)buf_len);
cm_close_file(file_fd);
return status;
}
static status_t cm_parse_config(config_t *config, char *buf, uint32 buf_len, bool32 is_ifile, bool32 set_alias)
{
uint32 line_no;
text_t text;
text_t line;
text_t comment;
text_t name;
text_t value;
CM_POINTER(config);
text.len = buf_len;
text.str = buf;
comment.str = text.str;
comment.len = 0;
line_no = 0;
while (cm_fetch_text(&text, '\n', '\0', &line)) {
if (line.len == 0) {
continue;
}
line_no++;
cm_trim_text(&line);
if (line.len == 0 || *line.str == '#') {
continue;
}
comment.len = (uint32)(line.str - comment.str);
cm_split_text(&line, '=', '\0', &name, &value);
cm_text_upper(&name);
cm_trim_text(&name);
if (!cm_text_str_equal_ins(&name, "CPU_GROUP_INFO")) {
if (line.len >= OG_MAX_CONFIG_LINE_SIZE) {
OG_THROW_ERROR(ERR_LINE_SIZE_TOO_LONG, line_no);
return OG_ERROR;
}
}
if (name.len == 0) {
OG_THROW_ERROR(ERR_INVALID_PARAMETER_NAME, " ");
return OG_ERROR;
}
cm_trim_text(&value);
cm_trim_text(&comment);
if (cm_set_config_item(config, &name, &value, &comment, is_ifile, set_alias) != OG_SUCCESS) {
return OG_ERROR;
}
comment.str = text.str;
comment.len = 0;
}
return OG_SUCCESS;
}
void cm_init_config(config_item_t *items, uint32 item_count, config_t *config)
{
uint32 i;
uint32 hash_value;
config_item_t *item = NULL;
CM_POINTER2(items, config);
MEMS_RETVOID_IFERR(memset_sp(config, sizeof(config_t), 0, sizeof(config_t)));
config->items = items;
config->item_count = item_count;
config->value_buf_size = CM_ALIGN4(item_count) * SIZE_K(4);
for (i = 0; i < item_count; i++) {
item = &config->items[i];
item->next = NULL;
hash_value = cm_hash_string(item->name, OG_CONFIG_HASH_BUCKETS);
item->hash_next = config->name_map[hash_value];
config->name_map[hash_value] = item;
if (item->alias != NULL) {
hash_value = cm_hash_string(item->alias, OG_CONFIG_ALIAS_HASH_BUCKETS);
item->hash_next2 = config->alias_map[hash_value];
config->alias_map[hash_value] = item;
}
}
}
status_t cm_load_config(config_item_t *items, uint32 item_count, const char *file_name, config_t *config,
bool32 set_alias)
{
CM_POINTER3(items, file_name, config);
size_t name_len = strlen(file_name);
errno_t errcode;
cm_init_config(items, item_count, config);
errcode = strncpy_s(config->file_name, OG_FILE_NAME_BUFFER_SIZE, file_name, (size_t)name_len);
if (errcode != EOK) {
OG_THROW_ERROR(ERR_SYSTEM_CALL, errcode);
return OG_ERROR;
}
config->text_size = sizeof(config->file_buf);
if (cm_read_config_file(file_name, config->file_buf, &config->text_size, OG_FALSE, OG_FALSE) != OG_SUCCESS) {
return OG_ERROR;
}
return cm_parse_config(config, config->file_buf, config->text_size, OG_FALSE, set_alias);
}
static status_t cm_open_config_stream(config_t *config, config_stream_t *stream)
{
char backup_name[OG_FILE_NAME_BUFFER_SIZE] = { '\0' };
CM_POINTER2(stream, config);
stream->config = config;
stream->offset = 0;
PRTS_RETURN_IFERR(snprintf_s(backup_name, OG_FILE_NAME_BUFFER_SIZE, OG_FILE_NAME_BUFFER_SIZE - 1, "%s_bak",
config->file_name));
if (cm_copy_file(config->file_name, backup_name, OG_TRUE) != OG_SUCCESS) {
return OG_ERROR;
}
PRTS_RETURN_IFERR(snprintf_s(backup_name, OG_FILE_NAME_BUFFER_SIZE, OG_FILE_NAME_BUFFER_SIZE - 1, "%s_tmp",
config->file_name));
if (cm_open_file(backup_name, O_CREAT | O_RDWR | O_BINARY | O_SYNC | O_TRUNC, &config->file) != OG_SUCCESS) {
return OG_ERROR;
}
(void)cm_chmod_file(S_IRUSR | S_IWUSR, config->file);
return OG_SUCCESS;
}
static status_t cm_write_config_stream(config_stream_t *stream, const char *str)
{
uint32 len;
CM_POINTER2(stream, str);
if (str == NULL) {
return OG_SUCCESS;
}
len = (uint32)strlen(str);
if (len == 0) {
return OG_SUCCESS;
}
if (stream->offset + len > OG_MAX_CONFIG_FILE_SIZE) {
if (cm_write_file(stream->config->file, stream->config->file_buf, (int32)stream->offset) != OG_SUCCESS) {
return OG_ERROR;
}
stream->offset = 0;
}
MEMS_RETURN_IFERR(memcpy_sp(stream->config->file_buf + stream->offset,
(size_t)(OG_MAX_CONFIG_FILE_SIZE - stream->offset), str, (size_t)len));
stream->offset += len;
return OG_SUCCESS;
}
static status_t cm_close_config_stream(config_stream_t *stream)
{
CM_POINTER(stream);
if (stream->offset > 0) {
if (cm_write_file(stream->config->file, stream->config->file_buf, (int32)stream->offset) != OG_SUCCESS) {
return OG_ERROR;
}
stream->offset = 0;
}
cm_close_file(stream->config->file);
char temp_name[OG_FILE_NAME_BUFFER_SIZE];
PRTS_RETURN_IFERR(snprintf_s(temp_name, OG_FILE_NAME_BUFFER_SIZE, OG_FILE_NAME_BUFFER_SIZE - 1, "%s_tmp",
stream->config->file_name));
if (cm_rename_file(temp_name, stream->config->file_name) != OG_SUCCESS) {
OG_LOG_RUN_ERR("rename config failed:%s to %s errno:%d,msg=%s", temp_name, stream->config->file_name, errno,
strerror(errno));
return OG_ERROR;
}
return OG_SUCCESS;
}
status_t cm_save_config(config_t *config)
{
config_stream_t stream;
CM_POINTER(config);
if (cm_open_config_stream(config, &stream) != OG_SUCCESS) {
return OG_ERROR;
}
config_item_t *item = config->first_item;
while (item != NULL) {
if (item->flag & FLAG_INFILE) {
item = item->next;
continue;
}
if (cm_str_equal_ins(item->name, "_FACTOR_KEY") || cm_str_equal_ins(item->name, "HAVE_SSL")) {
item = item->next;
continue;
}
if (!CM_IS_EMPTY_STR(item->comment)) {
if (cm_write_config_stream(&stream, item->comment) != OG_SUCCESS) {
return OG_ERROR;
}
if (cm_write_config_stream(&stream, "\n") != OG_SUCCESS) {
return OG_ERROR;
}
}
if (item->hit_alias) {
if (cm_write_config_stream(&stream, item->alias) != OG_SUCCESS) {
return OG_ERROR;
}
} else {
if (cm_write_config_stream(&stream, item->name) != OG_SUCCESS) {
return OG_ERROR;
}
}
if (cm_write_config_stream(&stream, " = ") != OG_SUCCESS) {
return OG_ERROR;
}
if (cm_write_config_stream(&stream, item->pfile_value) != OG_SUCCESS) {
return OG_ERROR;
}
if (cm_write_config_stream(&stream, "\n") != OG_SUCCESS) {
return OG_ERROR;
}
item = item->next;
}
return cm_close_config_stream(&stream);
}
static void cm_set_config_first_last_item(config_t *config, config_item_t *item)
{
config_item_t *prev_item = NULL;
if (config->last_item == NULL) {
config->first_item = item;
config->last_item = item;
return;
}
if (config->first_item == item) {
config->first_item = item->next;
} else if (item->next != NULL) {
prev_item = config->first_item;
while ((prev_item != NULL) && (prev_item->next != item)) {
prev_item = prev_item->next;
}
if (prev_item != NULL) {
prev_item->next = item->next;
}
}
item->next = NULL;
config->last_item->next = item;
config->last_item = item;
}
static status_t cm_threads_valid(const config_t *config, const text_t *name, const config_item_t *item,
const char *value_new)
{
config_item_t *other_item = NULL;
text_t name_text;
char *other_value = NULL;
int32 ret;
int32 size;
int32 other_size;
bool8 change_max = OG_FALSE;
OG_RETVALUE_IFTRUE(config == NULL, OG_ERROR);
OG_RETVALUE_IFTRUE(item == NULL, OG_ERROR);
OG_RETVALUE_IFTRUE(value_new == NULL, OG_ERROR);
OG_RETVALUE_IFTRUE(name == NULL, OG_ERROR);
OG_RETURN_IFERR(cm_str2int(value_new, &size));
if (cm_text_str_equal_ins(name, "MAX_WORKER_THREADS")) {
cm_str2text("OPTIMIZED_WORKER_THREADS", &name_text);
change_max = OG_TRUE;
} else {
cm_str2text("MAX_WORKER_THREADS", &name_text);
}
other_item = cm_get_config_item(config, &name_text, OG_FALSE);
OG_RETVALUE_IFTRUE(other_item == NULL, OG_ERROR);
other_value = (other_item->is_default) ? other_item->default_value : other_item->value;
OG_RETVALUE_IFTRUE(other_value == NULL, OG_ERROR);
OG_RETURN_IFERR(cm_str2int(other_value, &other_size));
ret = size - other_size;
if (change_max == OG_TRUE && ret > 0) {
return OG_SUCCESS;
}
if (change_max == OG_FALSE && ret < 0) {
return OG_SUCCESS;
}
if (ret == 0) {
return OG_SUCCESS;
}
if (change_max == OG_TRUE) {
OG_THROW_ERROR(ERR_PARAMETER_TOO_SMALL, "MAX_WORKER_THREADS", (int64)other_size);
} else {
OG_THROW_ERROR(ERR_PARAMETER_TOO_LARGE, "OPTIMIZED_WORKER_THREADS", (int64)other_size);
}
return OG_ERROR;
}
static status_t cm_connsize_valid(const config_t *config, const text_t *name, const config_item_t *item, const char *value_new)
{
config_item_t *item_new = NULL;
text_t name_text;
char *value = NULL;
int32 ret;
int32 size = 0;
int32 size_old = 0;
bool8 change_max = OG_FALSE;
OG_RETVALUE_IFTRUE(config == NULL, OG_ERROR);
OG_RETVALUE_IFTRUE(item == NULL, OG_ERROR);
OG_RETVALUE_IFTRUE(value_new == NULL, OG_ERROR);
OG_RETVALUE_IFTRUE(name == NULL, OG_ERROR);
OG_RETURN_IFERR(cm_str2int(value_new, &size));
change_max = cm_text_str_equal_ins(name, "MAX_CONNECTION_POOL_SIZE");
if (change_max) {
cm_str2text("MIN_CONNECTION_POOL_SIZE", &name_text);
} else {
cm_str2text("MAX_CONNECTION_POOL_SIZE", &name_text);
}
if (size <= 0 || size > 4000) {
if (change_max) {
OG_THROW_ERROR(ERR_INVALID_PARAMETER, "MAX_CONNECTION_POOL_SIZE");
} else {
OG_THROW_ERROR(ERR_INVALID_PARAMETER, "MIN_CONNECTION_POOL_SIZE");
}
return OG_ERROR;
}
item_new = cm_get_config_item(config, &name_text, OG_FALSE);
OG_RETVALUE_IFTRUE(item_new == NULL, OG_ERROR);
value = (item_new->is_default) ? item_new->default_value : item_new->value;
OG_RETVALUE_IFTRUE(value == NULL, OG_ERROR);
OG_RETURN_IFERR(cm_str2int(value, &size_old));
ret = size - size_old;
if ((change_max == OG_TRUE && ret > 0) || (change_max == OG_FALSE && ret < 0) || ret == 0) {
return OG_SUCCESS;
}
if (change_max == OG_TRUE) {
OG_THROW_ERROR(ERR_INVALID_PARAMETER, "MAX_CONNECTION_POOL_SIZE");
} else {
OG_THROW_ERROR(ERR_INVALID_PARAMETER, "MIN_CONNECTION_POOL_SIZE");
}
return OG_ERROR;
}
static bool32 cm_check_config_same(config_item_t *item, const char *value)
{
if (item->is_diff) {
return OG_FALSE;
}
char *old_value = item->is_default ? item->default_value : item->value;
return cm_str_equal(old_value, value);
}
static status_t cm_alter_config_item(config_t *config, config_item_t *item, const char *value, config_scope_t scope)
{
size_t value_len;
errno_t errcode;
if (item->is_default) {
if (cm_alloc_config_buf(config, OG_PARAM_BUFFER_SIZE, &item->value) != OG_SUCCESS) {
return OG_ERROR;
}
if (cm_alloc_config_buf(config, OG_PARAM_BUFFER_SIZE, &item->pfile_value) != OG_SUCCESS) {
return OG_ERROR;
}
}
item->is_default = OG_FALSE;
value_len = (uint32)strlen(value);
if (scope != CONFIG_SCOPE_DISK) {
errcode = strncpy_s(item->value, OG_PARAM_BUFFER_SIZE, value, (size_t)value_len);
if (errcode != EOK) {
OG_THROW_ERROR(ERR_SYSTEM_CALL, errcode);
return OG_ERROR;
}
}
item->flag &= ~FLAG_INFILE;
if (scope != CONFIG_SCOPE_MEMORY) {
errcode = strncpy_s(item->pfile_value, OG_PARAM_BUFFER_SIZE, value, (size_t)value_len);
if (errcode != EOK) {
OG_THROW_ERROR(ERR_SYSTEM_CALL, errcode);
return OG_ERROR;
}
if (item != config->last_item) {
cm_set_config_first_last_item(config, item);
}
if (cm_save_config(config) != OG_SUCCESS) {
return OG_ERROR;
}
}
item->is_diff = (scope != CONFIG_SCOPE_BOTH) ? OG_TRUE : OG_FALSE;
return OG_SUCCESS;
}
status_t cm_alter_config(config_t *config, const char *name, const char *value, config_scope_t scope, bool32 force)
{
text_t name_text;
config_item_t *item = NULL;
status_t status;
CM_POINTER3(config, name, value);
cm_str2text((char *)name, &name_text);
item = cm_get_config_item(config, &name_text, OG_FALSE);
if (item == NULL) {
OG_THROW_ERROR(ERR_INVALID_PARAMETER_NAME, name);
return OG_ERROR;
}
if ((item->attr & ATTR_READONLY) && !force) {
OG_THROW_ERROR(ERR_ALTER_READONLY_PARAMETER, name);
return OG_ERROR;
}
OG_RETSUC_IFTRUE(cm_check_config_same(item, value));
if (cm_text_str_equal_ins(&name_text, "MAX_CONNECTION_POOL_SIZE") ||
cm_text_str_equal_ins(&name_text, "MIN_CONNECTION_POOL_SIZE")) {
OG_RETURN_IFERR(cm_connsize_valid(config, &name_text, item, value));
}
if (cm_text_str_equal_ins(&name_text, "OPTIMIZED_WORKER_THREADS") ||
cm_text_str_equal_ins(&name_text, "MAX_WORKER_THREADS")) {
OG_RETURN_IFERR(cm_threads_valid(config, &name_text, item, value));
}
cm_spin_lock(&g_config_lock, NULL);
if (cm_access_file(config->file_name, F_OK | R_OK | W_OK) != OG_SUCCESS) {
cm_spin_unlock(&g_config_lock);
OG_THROW_ERROR(ERR_OPEN_FILE, config->file_name, errno);
return OG_ERROR;
}
status = cm_alter_config_item(config, item, value, scope);
cm_spin_unlock(&g_config_lock);
return status;
}
status_t cm_read_config(const char *file_name, config_t *config)
{
CM_POINTER2(file_name, config);
size_t name_len = strlen(file_name);
errno_t errcode = strncpy_s(config->file_name, OG_FILE_NAME_BUFFER_SIZE, file_name, (size_t)name_len);
if (errcode != EOK) {
OG_THROW_ERROR(ERR_SYSTEM_CALL, errcode);
return OG_ERROR;
}
config->text_size = sizeof(config->file_buf);
if (cm_read_config_file(file_name, config->file_buf, &config->text_size, OG_FALSE, OG_TRUE) != OG_SUCCESS) {
return OG_ERROR;
}
return cm_parse_config(config, config->file_buf, config->text_size, OG_FALSE, OG_FALSE);
}
status_t cm_modify_runtimevalue(config_t *config, const char *name, const char *value)
{
size_t value_len;
text_t name_text;
config_item_t *item = NULL;
errno_t errcode;
CM_POINTER3(config, name, value);
cm_str2text((char *)name, &name_text);
item = cm_get_config_item(config, &name_text, OG_FALSE);
if (item == NULL) {
return OG_ERROR;
}
value_len = (uint32)strlen(value);
cm_spin_lock(&g_config_lock, NULL);
if (item->runtime_value == NULL || item->default_value == item->runtime_value) {
if (cm_alloc_config_buf(config, OG_PARAM_BUFFER_SIZE, &item->runtime_value) != OG_SUCCESS) {
cm_spin_unlock(&g_config_lock);
return OG_ERROR;
}
}
errcode = strncpy_s(item->runtime_value, OG_PARAM_BUFFER_SIZE, value, (size_t)value_len);
if (errcode != EOK) {
OG_THROW_ERROR(ERR_SYSTEM_CALL, errcode);
cm_spin_unlock(&g_config_lock);
return OG_ERROR;
}
cm_spin_unlock(&g_config_lock);
return OG_SUCCESS;
}
void cm_free_config_buf(config_t *config)
{
if (config->value_buf != NULL) {
free(config->value_buf);
config->value_buf = NULL;
}
}
char *cm_fgets_nonblock(char *buf, uint32 buf_len, FILE *stream)
{
char *ch = NULL;
#ifndef WIN32
struct termios oldt;
struct termios newt;
int oldf;
(void)tcgetattr(STDIN_FILENO, &oldt);
newt = oldt;
newt.c_lflag |= (ICANON | ECHO);
(void)tcsetattr(STDIN_FILENO, TCSANOW, &newt);
oldf = fcntl(STDIN_FILENO, F_GETFL, 0);
(void)fcntl(STDIN_FILENO, F_SETFL, oldf | O_NONBLOCK);
ch = fgets(buf, (int)buf_len, stream);
(void)tcsetattr(STDIN_FILENO, TCSANOW, &oldt);
(void)fcntl(STDIN_FILENO, F_SETFL, oldf);
return ch;
#else
if (_kbhit()) {
ch = fgets(buf, buf_len, stream);
}
return ch;
#endif
}
#ifdef __cplusplus
}
#endif